I have been trying to figure out how to forward declare classes across multiple files in C++. I was able to successfully do it with two classes, but doing this across many classes puzzled me. I tried forward declaring all the classes in a header file and including that in all the classes, but I got the error of incomplete classes. I looked into it, but all the solutions seemed unreasonable or confused me. Can you please explain a good way to do it.
If it helps here is some example code of the issue that specifically occurring. Class A is included in Class C, but Class A also includes Class B which holds Class C resulting in an error because Class C has not been declared.
Class Forward Declaration
//Tried "Class Name {};" but that also failed
Class A;
Class B;
Class C;
Class A
//Class A
#include "B.h"
class A{
private:
B b;
public:
void SetBInt(int set) {b.SetInt(set);}
}
Class B
//Class B
#include "C.h"
class B{
private:
C c;
int i = 0;
public:
void SetInt(int set){i = set;}
}
Class C
//Class C
#include "A.h"
class C{
private:
int i = 0;
public:
void SetInt(int set){i = set;}
}
You have to avoid circular dependencies. One common way to avoid them is by pre-declaring the type, and not having any instances or function calls of that type in the header.
You do this by changing instances, such as B b, into references or pointers: B* b. You also have to move any code that uses b into the CPP file, so you can #include "B.h" prior to using it.
For example, instead of
// we'll remove this header's dependency on B shortly
#include "B.h"
class A
{
B b;
public:
A() { b.SetInt(0); }
};
You do something like this:
class B;
class A
{
B *b; // *pointers and &references to a predeclared class are fine.
public:
A();
~A();
};
... and then in A.cpp:
#include "A.h" // ALWAYS include your own header first
#include "B.h"
A::A()
{
// we didn't need to know how big B was until now, when we're about to make one and
// run its constructor. We'll also need to know what functions are available, and the
// types of all its parameters (or lack of parameters).
b = new B();
b->SetInt(0);
}
A::~A()
{
delete b; // for every "new" there must be a "delete"
}
Yes, this would be (much) better with std::unique_ptr<B> b instead of a raw pointer. With a smart pointer we wouldn't need an explicit destructor. I just didn't want to throw too much potentially new stuff at someone still learning.
Alternatively, you could pass a reference into the constructor, and use the member initializer list (you can only set references when they're constructed). This raises problems with "Object Lifetime". If the instance of B you pass in at construction time is destructed before A is done with it, you're program will violently crash (if you're lucky: that way you'll have a good idea of what the problem is) the next time it's used. Best to avoid it till you have considerably more experience under your belt.
Related
This is a basic question but gives me hard time. I have class A and in the header file I want to define another class constructor B from another header file. I tried this code below which I'm sure that's not the correct way.
A.h
class A{
public:
A();
B b(); //Constructor from another Class that defined in another header file
void Operation();
};
I need to call the constructor B in A.h so I can call the constructor B inside constructor A and also use function in Class B inside A::Operation().
A.cpp
#include "A.h"
#include "B.h"
A::A{
b(); //call constructor b
}
void A::Operation(){
b.someFunction(); //use function from class B, error here
}
As expected, the error I got is at b.someFunction()
expression must have class type
Anyone know how to define another class's constructor inside another class header file properly? And call the other constructor inside main class constructor and use the other class's function globally? Sorry for basic and confusing question.
This is not a constructor:
class A{
public:
A();
B b(); //This is a function named b, returning an object of type B
void Operation();
};
Same here:
A::A{
b(); //call function b from above, that returns a B object
}
And same here:
void A::Operation(){
b.someFunction(); // Without invoking method b, you apply the dot operator on the method - which is illegal.
}
You probably want an object of type B, and call someFunction method on it. Maybe you want:
class A{
public:
A();
B b; // this is object named b, of type B
void Operation();
};
And then, if the constructor of B requires parameters, you can:
A::A () : b(constructor parameters) {
}
If there is no need to pass parameters, you can just omit the construction of b, and the language will simply use the default constructor of B (without parameters).
A::A () {
}
The way to invoke or call a constructor of B is to create an instance of B.
The process of creating an instance of B involves calling/invoking a constructor of B. The implementation (aka compiler) takes care of the mechanics of calling the constructor in the process of creating an object. The job of the constructor is to ensure the object is initialised for subsequent use.
Practically speaking, it does not make sense to call a constructor in any context other than object construction. There are some advanced use cases in which a constructor is effectively called manually (e.g. using a placement new expression to initialise a block of memory so it contains an object). However that is done to create an object from the specified memory. This is completely different from what you are seeking.
To construct a B within (code in) a header file a.h, the header file a.h needs to provide visibility of a declaration of B and its constructors.
For example, assuming b.h declares the class B, the header a.h might do
#include "b.h"
class A
{
public:
A() : b() {} ;
void Operation();
private:
B b; // A contains an instance of B
};
In the above (working bottom up) the declaration B b specifies that A has a member of type B, named b.
The definition of As constructor
A() : b() {} ;
uses an initialiser list to initialise (construct) that member b. This assumes the class B has a constructor that can accept no arguments.
The declaration you had within class A (which I have removed from the sample I provided above)
B b(); //Constructor from another Class that defined in another header file
is not what you describe. It is actually a declaration of a member function of class A, which is named b() and returns a B. Calling such a function generally requires B to have a working constructor (typically a copy or move constructor). Such a declaration, however, is not a constructor of B.
just #include "B.h" in A.h and have B b; object in A.h.
#include "B.h"
class A{
A();
B b;
void operation();
}
this way the compiler will have all the information needed from class B constructors and other functions as well for this compilation unit A.cpp and linker will do its job later linking the function name to its logic in other compilation unit B.cpp .
Here is the problem. I need to write header file with two classes, say class A and class B.
in class A I have function that uses object of class B and vice versa, i.e. in class B I have function that uses objects of class A.
If A declared first then there would be error that class B has not been declared.
How to deal with it? I try declare function of a class A after declaration of class B:
void classA::myfunc (classB *b);
But I got the error that function myfunc is not declared.
Experienced people in C++, what to do?
Added:
here is a good link about header
If you need a pointer to a class on a header, not the full object, just add a forward declaration, dont include the header of the pointer's class.
I'm sure that you just use pointers to access that classes that one have a reference to another, dont you? You know, because if you use instances, you got a instance looping. Use forward declarations.
Here's a example of how you can use forward declarations:
A.h
class B;
class C;
class D;
class E;
class A {
B* pointer; //To just have a pointer to another object.
void doThings(C* object); //if you just want to tell that a pointer of a object is a param
D* getThings(); //if you wanna tell that a pointer of such class is a return.
E invalid(); //This will cause an error, because you cant use forward declarations for full objects, only pointers. For this, you have to use #include "E.h".
};
To illustrate how can have a class that mentions one that pointers its type:
B.h
class A;
class B {
A* pointer; //That can be done! But if you use a includes instead of the forward declarations, you'll have a include looping, since A includes B, and B includes A.
}
As mentioned by Tony Delroy (Many thanks to him) You should not ALWAYS use this design. It's provided by the C++ compiler, but its not a good practice. The best is to provide reference header, so your code would look like:
A.h
#include "B.fwd.h"
#include "C.fwd.h"
#include "D.fwd.h"
#include "E.fwd.h"
class A {
B* pointer; //To just have a pointer to another object.
void doThings(C* object); //if you just want to tell that a pointer of a object is a param
D* getThings(); //if you wanna tell that a pointer of such class is a return.
E invalid(); //This will cause an error, because you cant use forward declarations for full objects, only pointers. For this, you have to use #include "E.h".
};
and yours forward headers like this:
B.fwd.h:
class B;
In your fwds, you should have your class forward declaration, and any typedefs that comes with it.
I'm not mentioning the #pragma once, or the #ifndef B.H... you know they'll be there :D
Your code would be on a standard defined by <iosfwd> and better to maintain, specially, if they are templates.
Short answer:
class classA;
Then you defined your classB and then the declaration of classA.
This is called forward-declaration, and is there to solve your problem :)
You can try to add a forward declaration of a class before you use it with a ref or ptr.
classA.h:
class classB;
class classA {
void fun(classB * b);
}
classB.h:
class classA;
class classB {
void fun(classA * a);
}
classA.cpp:
#include "classA.h"
#include "classB.h"
...
classB.cpp:
#include "classA.h"
#include "classB.h"
...
This may seem weird but I have a problem in one of my programs where I have a class A which needs a variable of class B inside it, and the class B needs a pointer to class A inside it, so that I can determine which class is attached to what....
I get errors because in class A it says that the class B is not defined yet, and in class B it says class A isn't defined yet...
Both of my header files which contain the separate classes include each other and I have tried to forward declare my classes e.g. class A; class B; but I get compiler errors such as:
error C2079: 'CFrame::menu' uses undefined class 'CMenu'
I need a pointer to class A in class B because I want to pass it to another class later on.
You need to declare A before you define B:
class A; // declaration of A
class B // definition of B
{
A* foo;
// ...
};
class A // definition of A
{
B bar;
// ...
};
This kind of declaration is often referred to as a forward declaration.
First of all, consider redesigning your classes. Circular dependencies are bad practice, and chances are that you could avoid this altogether with a more elegant class design.
That said, you can get around the problem using forward references (at which point, you need to use pointers or references) -
class B;
class A
{
B *pPtr;
};
class B
{
A typeA;
};
You may be able to avoid forward declaration by simply specifying what a "B" is:
class A
{
public:
class B* pB;
};
class B
{
public:
A a;
};
If you're having problems with this, it may be because you're including implementation along with your declarations. If you separate the implementation and the header, you might have fewer problems in this scenario.
I have a bit of problem with this. I have a class A which instantiates an object of B and then B which instantiates an object of A. Is this at all possible? I tried adding this in the headers of each
#ifndef A
#define A
class a...
#endif
but if keeps me in an infinite header loop which it reaches the maximum header includes, so obviously one is calling the other and the other is calling that one. Is there any way to achieve this?
edit: Okay this seems like a good answer but now A complains that B doesn't have a Constructor despite the fact that it definitely has a constructor. I can't figure that one out.
You can forward declare the classes, for example:
A.h:
class B;
class A
{
B* a_;
};
B.h:
class A;
class B
{
A* a_;
};
In your source files where you actually use the classes (that is, create them, destroy them, use their members, etc.), you will need to include both headers so that their definitions are available:
#include "A.h"
#include "B.h"
You should break this circular dependence. For instance, you could use a pointer to B, and you could then forward declare the B class.
Have you tried using forward declaration?
class B;
class A
{
private:
B* instanceOfB_;
};
This is not a good design to start with. However to make it possible just use forward declaration.
In classA.h file remove any includes to classB.h and move them to the classA.cpp. Then before declaring classA write the line class B; to forward declare class B. This way you can have member variables of B* (but not B) inside class A. Do the same for classB next.
You can forward declare A in B's header file, and the other way around, to achieve what you want.
// In B.h
class A;
class B
{
private:
A a;
};
See Wikipedia for more information.
If you mean class A {B b;}; and class B {A a;}, no you can't. Class data members are included in the class, so you'd have a B that included an A that included a B that included an A.... Remember, in C++ a data object is not a reference to something, but is the actual thing.
You need something like class A {B * b;}; and class B {A * a;}, where you are providing pointers. Before the definitions, you need something like class A; class B; to tell the compiler that A and B are classes. These are called "forward declarations".
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 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) { }
};
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.
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.
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).
You alse include A.h from B.h and B.h from A.h. You should at least use preprocessor macros:
#ifndef __A_H__
#define __A_H__
// A.h contents
#endif
so that file won't be included more than once.
If you create an instance of A, that will create an instance of B (member var) which will create an instance of A (member var) which will create an instance of B which will create an instance of A and so on...
The compiler should not allow this since it requires infinite memory.
To solve this, either A or B must use a reference/pointer to the other class.