I have an error that goes like this
In file included from Level.hpp:12,
from main.cpp:4:
Corridor.hpp: In method `void Game::Corridor::update()':
Corridor.hpp:41: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:42: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:43: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:44: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor and Level are …
// Corridor.hpp
#ifndef GAME_CORRIDOR_HPP
#define GAME_CORRIDOR_HPP
#include <Moot/Math.hpp>
//#include <Level.hpp>
#include <GameWindow.hpp>
namespace Game
{
class Level; // <-- LINE 13
class Corridor
{
static const unsigned int defaultLevelDepth = 800;
Moot::Math::Vector3D wp1, wp2, wp3, wp4;
Moot::Math::Vector2D sp1, sp2, sp3, sp4;
Level * p_level;
public:
Corridor(Moot::Math::Vector3D setFirstPoint, Moot::Math::Vector3D setSecondPoint)
{
wp1 = setFirstPoint;
wp2 = setSecondPoint;
wp3 = setFirstPoint;
wp3.z += defaultLevelDepth;
wp4 = setSecondPoint;
wp4.z += defaultLevelDepth;
}
void update() {
sp1 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp1); // <- LINE 41 etc.
sp2 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp2);
sp3 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp3);
sp4 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp4);
//p_level->getLevelCamera();
}
void draw()//const
{
Moot::Color tempColor;
windowInstance().graphics().drawQuad( sp1.x, sp1.y, tempColor,
sp2.x,sp2.y, tempColor,
sp3.x, sp3.y, tempColor,
sp4.x,sp4.y, tempColor, 1);
}
void setLevel(Level* setLevel) {
p_level = setLevel;
}
};
}
#endif
and
// Level.hpp
#ifndef GAME_LEVEL_HPP
#define GAME_LEVEL_HPP
#include <Moot/Forward.hpp>
#include <Moot/Window.hpp>
#include <Moot/Math.hpp>
#include <GameWindow.hpp>
#include <Camera.hpp>
#include <Corridor.hpp>
#include <Player.hpp>
#include <vector>
namespace Game
{
class Level
{
typedef Corridor* p_corridor;
typedef std::vector<p_corridor> CorridorList;
typedef CorridorList::reverse_iterator ReverseCorridorItter;
CorridorList m_map;
Camera m_camera;
Player m_player;
public:
Level()
{
m_player.setLevel(this);
// Lots of vertices being defined into m_map.
// Loop through and set camera
ReverseCorridorItter rit;
for(rit = m_map.rbegin(); rit != m_map.rend(); rit++)
(*rit)->setLevel(this);
}
~Level()
{
ReverseCorridorItter rit;
for(rit = m_map.rbegin(); rit != m_map.rend(); rit++)
delete (*rit);
m_map.clear();
}
void update()
{
// Temp delete when input and player are implimented.
if(pad[0].buttons & PAD_UP)
m_camera.updateTargetOffsets(0, -2);
if(pad[0].buttons & PAD_DOWN)
m_camera.updateTargetOffsets(0, 2);
if(pad[0].buttons & PAD_LEFT)
m_camera.updateTargetOffsets(-2, 0);
if(pad[0].buttons & PAD_RIGHT)
m_camera.updateTargetOffsets(2, 0);
m_player.update();
ReverseCorridorItter rit;
for (rit = m_map.rbegin(); rit != m_map.rend(); rit++)
(*rit)->update();
}
void draw() // const // EH!!! wtf ReverseIter isn't a member
{
m_player.draw();
ReverseCorridorItter rit;
for (rit = m_map.rbegin(); rit != m_map.rend(); rit++)
(*rit)->draw();
}
Camera& getLevelCamera() {
return m_camera;
}
};
}
#endif
The pointer is being set as far as I can tell, but when I try to access a function from Level, BOOM!
Thanks.
PS: The compiler is gcc 2.95.2 if that makes a difference.
EDIT
Updated with complete code.
I have the following errors trying to use a TFT library function inside my library. My library uses the pointer to an instance of the TFT library in the constructor, as well described there:
Basic C++ programming, how to pass constructor argument into class?
The errors are:
error: invalid use of incomplete type 'class TFT'
_TFTscreen->background(0, 0, 0);
error: forward declaration of 'class TFT'
class TFT;
MESmenu.h:
#ifndef _MESMENU_H_
#define _MESMENU_H_
#include <SPI.h>
#include <SD.h>
class TFT;
class MESmenu{
public:
MESmenu(TFT* pTFT) : _TFTscreen(pTFT) {};
void start();
void execute();
private:
TFT* _TFTscreen;
};
#endif
MESmenu.cpp:
#include "Arduino.h"
#include "MESmenu.h"
void MESmenu::start(){
_TFTscreen->background(0, 0, 0);
_TFTscreen->text("starting menu...", 0, 0);
//...
}
void MESmenu::execute(){
//some code...
}
The Arduino sketch is:
#include <SPI.h>
#include <SD.h>
#include <TFT.h> // Arduino LCD library
#include <MESmenu.h> // my library
// --------- TFT LCD ---------
// pin definition for the due
#define sd_cs 7
#define lcd_cs 10
#define dc 9
#define rst 8
TFT TFTscreen = TFT(lcd_cs, dc, rst);
// MES menu class
MESmenu *mainMenu = new MESmenu(&TFTscreen);
void setup() {
// initialize TFT
TFTscreen.begin();
TFTscreen.background(0, 0, 0);
// set the stroke color to white
TFTscreen.stroke(255,255,255);
TFTscreen.fill(255,255,255);
TFTscreen.setTextSize(2);
TFTscreen.text("TEST", 0, 0);
// Start menu
mainMenu->start();
}
void loop () {
mainMenu->execute();
}
The problem is related to the function:
_TFTscreen->background(0, 0, 0);
inside the MESmenu::start() in the .cpp file.
UPDATE:
As suggested by frarugi87 I’ve updated the question with the details of .h and .cpp files.
Those file are in the ArduinolibrariesMESmenu folder.
I try to change
class TFT;
with
#include <TFT.h>
and removed the #include from the main arduino sketch.
This leads to the following errors:
librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: first defined here
librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `PImage::read16(SDLib::File)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/PImage.h:17: first defined here
librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `PImage::read32(SDLib::File)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/PImage.h:17: first defined here
librariesMESmenuMESmenu.cpp.o: In function `Adafruit_GFX::image(PImage&, unsigned int, unsigned int)':
D:Softwarearduino-1.6.7librariesTFTsrc/utility/Adafruit_GFX.h:231: multiple definition of `PImage::loadImage(char const*)'
sketchtest_MESmenu_lib.ino.cpp.o:D:Softwarearduino-1.6.7librariesTFTsrc/utility/PImage.h:17: first defined here
Forward declarations and Invalid uses of incomplete type Init
Alright, I don’t know why I should have unresolved dependency issues here, but here goes:
And to think, I was just trying to build a simple class for initializing SDL facilities.
All the tutorials I’ve been doing (lazyfoo) seem really cluttered and have all this initialization data up-front in nested if-statements in main.cpp, and I thought it looked sloppy and that I’d do one better by encapsulating all that crap into a simple class for my own uses.
Having done thirty of them, I thought I knew enough to start screwing around on my own. Maybe not?
Init.h
|
|
(Ignore the «magic consts» in the window creation function, they’re just placeholders for variables I have yet to declare.)
Init.cpp
|
|
main.cpp
|
|
build messages (backspaced over long directory names for convenience)
|
|
Look at line 14 of Init.h. There’s something missing…
A couple of things jump off the page:
— The brackets on line 6 of Init.h shouldn’t be there,
— The declaration and definition of initAll don’t match (one has no parameters, the other has two parameters)
Thanks a ton guys. Sometimes I just need a second pair of eyes that aren’t tired.
I gotta leave for work now, but I’ll take your advice when I get back!
Thanks in advance for any additional help.
Line 6 of Init.h:
|
|
Also these are non-static members of a class, so you need to have an object to act on.
|
|
But of course… having an ‘Init’ object doesn’t really make much sense. Can you have multiple Inits? Does having the object actually do anything?
These functions are all global by nature. Rather than putting them in a class, maybe put them in a namespace:
|
|
Or… if you don’t want a namespace… then make it a static class that can’t be instantiated (though that is more work for little gain).
Remember the whole point of a class is to represent a ‘thing’. They’re nouns.
Common examples of classes and what they represent:
std::string — represents a string
std::fstream — represents a file
std::list — represents a linked list of objects
etc
What exactly does an ‘Init’ represent? It’s not a ‘thing’, so it doesn’t really need to be a class.
Ah, thank you Disch. I wasn’t sure if classes NEEDED objects or not and I had forgotten about creating namespaces. I thought it was conventional to have objects of classes, but not mandatory. I had tried converting it to a struct before posting this thread, but obviously that didn’t work.
And I had thought about making an Init object (which would require me to write a constructor) but it occurred to me, like you said in your post, that it made no sense.
I’ll eventually remember all this if I fail enough times.
EDIT:
Disch! I noticed in your namespace example that you put the namespace Init member functions in main, is that truly necessary? The whole reason I decided to do this whole wrapper class thing was to keep excess stuff out of main. Should I define the functions inside the namespace, instead? Will that create problems because it’s inside a header?
Edit 2: Never mind the previous edit. Everything is in order now.
Last edited on
Topic archived. No new replies allowed.
In this guide, we will walk you through the process of troubleshooting and fixing C++ Invalid Use of Incomplete Type Errors. These errors usually occur when you try to use a class or structure that has been declared, but not yet defined or fully specified. Let’s dive into the details and learn how to fix these errors in your C++ code.
Table of Contents
- Understanding Invalid Use of Incomplete Type Errors
- Identifying the Causes of Invalid Use of Incomplete Type Errors
- Step-by-Step Guide to Fixing Invalid Use of Incomplete Type Errors
- FAQ
- Related Links
Understanding Invalid Use of Incomplete Type Errors
In C++, an incomplete type is a type that has been declared but not defined. This means that the compiler doesn’t have enough information about the type to determine its size or layout in memory. When you try to use an incomplete type in a way that requires the compiler to know its size or layout, you will encounter an «Invalid Use of Incomplete Type» error.
Here’s an example of an incomplete type error:
class MyClass; // Forward declaration
void myFunction(MyClass obj) {
// Invalid use of incomplete type 'class MyClass'
int x = obj.someFunction();
}
In this example, MyClass
has been declared but not defined, so the compiler doesn’t know the size or layout of the class. When you try to use an object of type MyClass
inside the myFunction
function, the compiler generates an error.
Identifying the Causes of Invalid Use of Incomplete Type Errors
There are several common causes for Invalid Use of Incomplete Type Errors:
- Missing includes: If you forget to include the header file that contains the definition of a type, the compiler will only have access to its declaration and will treat it as an incomplete type.
- Forward declarations: When you use a forward declaration instead of including the header file, the type remains incomplete until it’s defined later in the code.
- Circular dependencies: If two types depend on each other, the compiler may not be able to determine their size and layout, which can result in an incomplete type error.
Step-by-Step Guide to Fixing Invalid Use of Incomplete Type Errors
- Check your includes: Make sure you’ve included the appropriate header files that contain the definitions of the types you’re using. If you’re unsure which header files to include, consult the documentation or source code of the library or module you’re using.
- Replace forward declarations with includes: If you’re using a forward declaration, consider replacing it with an include statement for the header file that contains the type’s definition. This will provide the compiler with the necessary information about the type.
- Resolve circular dependencies: If two types depend on each other, you may need to refactor your code to break the circular dependency. This can be done by using pointers or references instead of direct object instances, or by moving the common functionality to a base class or separate utility class.
FAQ
Why does forward declaration cause an incomplete type error?
Forward declaration is a technique used to inform the compiler about the existence of a class or structure without providing its full definition. This can be helpful in certain situations to avoid circular dependencies or reduce compile times. However, when you use a forward-declared type in a way that requires the compiler to know its size or layout, you will encounter an incomplete type error.
Can I use pointers or references to avoid incomplete type errors?
Yes, using pointers or references can help you avoid incomplete type errors because they don’t require the compiler to know the size or layout of the underlying type. Instead, the compiler only needs to know the size of the pointer or reference itself. This can be a useful technique when working with forward-declared types or circular dependencies.
How can I fix circular dependencies that cause incomplete type errors?
To fix circular dependencies, you can use one or more of the following techniques:
- Use pointers or references instead of direct object instances, as they don’t require the compiler to know the size or layout of the underlying type.
- Move common functionality to a base class or separate utility class, which can then be included by both dependent classes without creating a circular dependency.
Is it possible to use forward declarations and avoid incomplete type errors?
Yes, it is possible to use forward declarations without encountering incomplete type errors, as long as you only use the forward-declared type in ways that don’t require the compiler to know its size or layout. This typically means using pointers or references to the forward-declared type or only using the type in function declarations, not definitions.
What is the difference between a declaration and a definition in C++?
In C++, a declaration introduces a name and a type to the compiler, while a definition provides the complete information required to create an instance of the type. For example, a class declaration specifies the class name and any base classes or interfaces it inherits from, while the class definition includes the full list of member variables and member functions.
- C++ Forward Declarations
- C++ Incomplete Types
- C++ Class Definitions
- C++ Circular Dependency Solutions
- C++ Headers and Includes
Solution 1
In order to define a class or struct, the compiler has to know how big each member variable of the class is. A forward declaration does not do this. I’ve only ever seen it used for pointers and (less often) references.
Beyond that, what you’re trying to do here cannot be done. You cannot have a class A that contains an object of another class B that contains an object of class A. You can, however, have class A contain a pointer to class B that contains an object of class A.
B.cpp
#include "B.h"
void B::SomeFunction()
{
}
B.h
#ifndef __B_h__ // idempotence - keep header from being included multiple times
#define __B_h__
#include "A.h"
class B
{
public:
A a;
void SomeFunction();
};
#endif // __B_h__
A.h
#ifndef __A_h__ // idempotence - keep header from being included multiple times
#define __A_h__
#include "B.h"
class B; // forward declaration
struct A
{
B *b; // use a pointer here, not an object
};
#endif // __A_h__
Two points. First, be sure to use some form of idempotence to keep the headers from being included multiple times per compilation unit. Second, understand that in C++, the only difference between classes and structs is the default visibility level — classes use private visibility by default while structs use public visibility by default. The following definitions are functionally equivalent in C++.
class MyClass
{
public: // classes use private visibility by default
int i;
MyClass() : i(13) { }
};
struct MyStruct
{
int i;
MyStruct() : i(13) { }
};
Solution 2
Forward declarations, like
struct A;
or
class A;
Introduce A as an incomplete type and it remains incomplete until end of type’s definition is reached. There are things you can do with incomplete types and things you can’t. You can
- Declare variables (or members) of type «pointer to A» and «reference to A»
- Declare functions which take arguments of type A or return type A
You can’t
- Declare variables (nor members) of type A
- Dereference pointers to A or access any members of references to A
- Define subclasses of A.
In your code you try to declare struct member of incomplete type. It’s illegal. Only pointers and references are allowed.
Solution 3
public:
A a;
You are trying to create the object of A with only forward declaration. Compiler at this moment ( with only forward decl) cannot decide the size of the object A and hence, it cannot allocate memory required for A. So you cannot create objects with only forward decl.
Instead replace with:
A* a;
Pointer or reference to A without A’s class definition will work fine.
Solution 4
Two issues jump out at me here.
1: You’ve written Struct A
instead of struct A
; note the lower-case «s». Your compiler might consider the equivalent, but I don’t think it’s standard C++.
You have defined a circular reference between A
and B
. Each A object must contain a B
object, but each B
object must contain an A
object! This is a contradiction, and will never work the way you want it to. The usual C++ way to solve that problem is to use pointers or references for A::b
or B::a
(or both).
Related videos on Youtube
17 : 09
05 : 05
Forward Declaration of Class C++
15 : 10
10 : 14
Learning C++ STL — Forward List
09 : 22
C++/Game Tutorial 10: Parameters and Forward Declarations!
15 : 41
C++ Class declaration | Part-1/2 | OOPs in C++ | Lec-13 | Bhanu Priya
27 : 48
Modern C++ CLASSES — Easy and In-depth explanation | All the basics you need with examples!
39 : 47
C++ for C# and Java Developers
17 : 24
08 : 47
UE4 C++ Tutorial — #Include and Forward Declarations — UE4 / Unreal Engine 4 Intro to C++
02 : 19
C++ Forward Declaration Objects/Enums
04 : 09
Forward Declarations | Introduction to Programming with C++ | Part 43
02 : 13
Forward Declaration — Beginner C++ Tutorials
Comments
-
The follwing code is compiled in VC++6. I don’t understand why I am getting the compilation error
C2079: 'b' uses undefined class 'B'
for the following code.Class B Source
#include "B.h" void B::SomeFunction() { }
Class B Header
#include "A.h" struct A; class B { public: A a; void SomeFunction(); };
struct A Header
#include "B.h" class B; struct A { B b; };
If I changed class B header to the following, then there will be no error. But the header declaration won’t be at the top!
Class B Header with weird header declaration
struct A; class B { public: A a; void SomeFunction(); }; #include "A.h"
-
In the actual code, preprocessor macros are defined but it is not shown here to make the code simpler.
-
Double-underscores are reserved for the compiler. Use a different naming convention.
-
Double-underscores are reserved for the compiler. Use a different naming convention.
-
@GMan: I’ve always used this convention for my idempotence markings when the compiler doesn’t generate them automatically. Is this specific to a compiler or is it in the C++ spec?
-
@Matt, it is part of the C++ spec that such identifiers are reserved. I personally use «HEADER_PATH_TO_HEADER_H_INCLUDED» or «HEADER_PATH_TO_HEADER_INCLUDED» (if no «.h»).