C++ - two classes instantiate each other, can't use forward declarations - c++

I have classes A and B with both having their header files with include guards. One reads:
#ifndef A_H
#define A_H
#include "B.h"
class A
{
B b;
};
#endif
And the other one:
#ifndef B_H
#define B_H
#include "A.h"
class B
{
A a;
};
#endif
Now I test it with the following main.cpp:
#include "A.h"
int main()
{
A a;
}
The compiling error is as follows:
# make main
g++ main.cpp -o main
B.h:8: error: ‘A’ does not name a type
Is there any solution to this situation, other than using a pointer/reference and a forward declaration?

No, it's not possible: one of them needs to be a pointer or a reference: because if A contains B, which contains A, which contains B, then you have infinite recursion and are trying to specify infinite sized object.

No there is no other option than to use pointer/reference and forward declaration, unfortunately.

You can't do that, you would cause an infinite recursion (A would include B, B would include, A ...), plus the compiler won't allow it because in one of the class declarations the other class will be incomplete. (Not fully defined)
You can just do this if one of them is a pointer or a reference.

I suggest to use the pImpl idiom if possible ( Pointer-to-implementation, other names: Opaque pointer, Handle-body idiom, Cheshire Cat... see here for details. )
It basically allows you to "free" your class declaration from implementation details that are usually visible to users of your class (even though they are not usable, assuming private access).
You simply declare your class as follows:
#ifndef A_H
#define A_H
class A{
public:
//declare public methods -> "interface"
private:
struct Private;
Private * mp_d; //feel free to use smart pointer
};
#endif
The forward declared struct (or class ) is only defined in your source file and contains all implementation details like you data members and functions that are internal to your class.
#include "B.h"
struct A::Private {
B a;
};
A::A() : mp_d( new Private()) {
}
A::~A(){
delete mp_d; //not required if using smart pointer
}
NB: Now the compiler-generated copy constructor and assignement operators don't work any more (as expected). Make sure to either implement them yourself or simply prevent the compiler from generating them by declaring them private (without implementation). (This is basically C++03 style; I think in C++11 you simply add = deleteafter the declaration to prevent compiler-generation.)
EDIT: added "long" name of pImpl

Related

Resolving circular dependency when using a class enum

The title probably isn't very clear, what I'm talking about is:
Say you have a class A depending on B and a class B depending on A.
This causes a circular dependency, but can be solved pretty easily:
/// a.h
#ifndef __A_H
#define __A_H
struct B;
#include "b.h"
struct A
{
B *bptr;
A();
void doStuffWithB();
};
#endif
/// b.h
#ifndef __B_H
#define __B_H
struct A;
#include "a.h"
struct B
{
A *aptr;
B();
void doStuffWithA();
};
#endif
Boom! Circular dependency resolved.
However, what if I now wanted to use an enum declared in B as an argument in A ?
/// a.h ...
struct A
{
B *bptr;
A();
void doStuffWithB(B::Type type); // <-- Compiler smells something funny here
};
/// b.h ...
struct B
{
enum Type
{
// Whatever...
}
B();
void doStuffWithA();
};
Obviously it will not work because the enum isn't yet declared.
The solution for this would be to just put the enum in it's own header file, but it's really nice to have it attached to the class, so would there be any funny way to do something like that ? I searched around but couldn't find a satisfactory answer.
struct B;
#include "b.h"
In the original version of the two header files this #include is completely unnecessary. You'll be happy to learn that the struct B; forward declaration is completely sufficient for declaring the B * class member. The analogous thing applies for the struct A; and the #include in the other header file: the #include is unnecessary.
And once you made this fortunate discovery, the solution in this specific case becomes obvious: simply put back the #include "b.h" back wher eit was.
Only a.h needs to #include the other file, and fully declare the B object in order to make use of its inner enum. The reason for the original compilation error is the unneeded include from b.h to a.h.
When compiling the b.h, its #include of a.h happens before the class and its inner enum gets declared. Then, the #include from a.h to b.h does nothing, because it gets blocked by the include guards. And then the A class gets compiled without the B class, and its inner enum, getting declared.
So, this specific case can be solved, because the dependency on an inner class member is from one of the classes only. What is, actually, an insolvable problem is when two classes have a mutually dependency on each other's inner class member. The only solution is a refactoring, pulling out the inner class type/enums into the global scope, and perhaps using a using or a typedef to alias an inner class to it.

Using objects that are declared in different files across the whole project

I have a C++ project that has multiple files.
File A.h
#ifndef A_H
#define A_H
class A
{
void somefunctionA();
};
A a;
#endif
File B.h
#ifndef B_H
#define B_H
class B
{
void somefunctionB();
};
B b;
#endif
I want to use object a in class B and object b in class A
So basically I want to use variables a and b anywhere in the program.
main.cpp
#include "A.h"
#include "B.h"
...
But there is a conflict. Object "a" isn't seen in class B.
What can be done in this situation and is there a better approach?
You can declare a class anywhere, like in an unrelated header file.
For example:
#ifndef B_H
#define B_H
// Declaration of class A
class A;
extern A a;
class B
{
void somefunctionB();
};
extern B b;
#endif
Now in the implementation of e.g. B::somefunctionB you can use the variable a without seeing the definition of the variable. You do need the definition of the A class though.
A declaration is basically you telling the compiler that something exists, what type it is and what name it have. It's like function prototypes, you declare that somewhere there is a definition of a function, but after the function prototype declaration you can call the function without having seen the function definition (implementation).
A definition, on the other hand, is what tells the compiler (and later the linker) that "this is it". The definition of a variable is not only telling the compiler that the variable exists, but also instructs the compiler to reserve space for the variable in the resulting executable program. A definition of a function is the actual implementation of of the function, where you have the code inside the function.
Incidentally, if a variable or function haven't been declared then the compiler sees the definition of the variable or function, then the definition is also the declaration.
If, as you state, you have all code for the classes inline in the class definition you will have a problem using the global variables with only a class declaration, you need the complete class definition. But if you use class A in class B and the other way around, you have a circular dependency that is hard to break: Class A needs class B to work, but class B needs class A to work.
The easiest solution to break this circular dependency is to put the code from class A that uses class B in a separate source file, and the same for the code in class B that uses class A. This way the header files will not need to include each other giving you the circular dependency, and the source files can include both header files without problems.
Use the singleton pattern for implementing classes that should have only a single global instance:
class A
{
public:
static A& instance()
{
static A instance_;
return instance_;
}
virtual ~A() {}
private:
A() {} // prevent direct instantiation
A(const A&); // prevent copy construction
A& operator=(const A&); // prevent assignment
};
Then use A::instance() wherever you need to interact with the object instance.
Of course this pattern should be used sparingly. Make sure that you really need a global object before creating one and that there is no other way which will give you the same functionality.
Please note that this pattern is not suitable for global objects that depend on each other as the order of static initialization is undefined.

Cross dependencies without forward declaring all used functions?

I have class A (in A.h) which depends on class B in (B.h) and vice versa. Forward declaring the used functions works, but this means I have to update everywhere where I forward declared those functions in the future, ex, if I remove, or change argument in those functions they must all be updated to reflect change. I don't feel this is good practice. Is there a way around this?
Thanks
If you only need to work with pointers or references to a class at the declaration level, you can do it like this:
A.h
class B; // forward class declaration
class A {
A(B &);
};
B.h
class A;
class B {
B(A &);
};
B.cpp
#include "B.h"
#include "A.h" // now we get the full declaration of A
B::B(A &a) {
a.foo(5);
}
Mutual dependencies like this are tough to deal with but sometimes unavoidable.
If A and B depend on the implementations of each other, then you've got a system design problem that you need to resolve before proceeding further.
The best way is to have a forward declaration header:
a.fwd.h
#pragma once
class A;
a.h
#pragma once
#include "a.fwd.h"
#include "b.fwd.h"
class A
{
A(B*);
};
etc.
This way, each class provides its own forward declarations - localised alongside the header where it belongs - checked for consistency with the real declarations and definitions by including the forward declaration header in the header, and the header in the implementation.

Forward Declaration vs Include

Consider the following two scenarios (Edited just to complete the whole question and make it clearer)
Case 1: (doesnt compile as rightly mentioned below)
//B.h
#ifndef B_H
#define B_H
#include "B.h"
class A;
class B {
A obj;
public:
void printA_thruB();
};
#endif
//B.cpp
#include "B.h"
#include <iostream>
void B::printA_thruB(){
obj.printA();
}
//A.h;
#ifndef A_H
#define A_H
#include "A.h"
class A {
int a;
public:
A();
void printA();
};
#endif
//A.cpp
#include "A.h"
#include <iostream>
A::A(){
a=10;
}
void A::printA()
{
std::cout<<"A:"<<a<<std::endl;
}
//main.cpp
#include "B.h"
#include<iostream>
using namespace std;
int main()
{
B obj;
obj.printA_thruB();
}
Case 2: (the only modifications...works without compiliation error)
//B.h
#include "A.h" //Add this line
//class A; //comment out this line
Let us assume both the A.cpp and B.cpp are complied together. Do the above two scenarios make any differences? Is there a reason to prefer one method over the other?
Edit:
So how do I make scenario 1 work.
Forward declaration is not a substitute for Header file inclusion.
As the name itself implies, forward declaration is just a Declaration and not a definition.
So, you will declare saying the compiler that it is a class and I just declaring it here and will provide you the definition when am gonna use it. So, normally you forward declare in the Header file and #include in the .cpp file where you will use the members of the forward declared class.
By doing so, what you make is, wherever you are including the header file there will just be a declaration for the class instead of the entire contents #included...
But having said that, when the compiler requires the definition of the class, it should be #included..
So, in your case A obj; requires the definition of class A and hence you should #include..
I myself asked a similar question here and another similar question which has also a nice answer...
Hope it helps..
Case 1 will produce an "incomplete type" error when you compile B.cpp. Because class B contains a class A object, the definition (and in particular the size) of class A is required to be complete before the definition of class B.
Alternatively, you could choose to make some_variable a pointer or reference to class A, and in that case your forward declaration would be sufficient in B.h. You'd still need a full definition of A in B.cpp (assuming you made actual use of the A member functions/data).
You need to use forward declarations in cases where you have classes that refer to each other.
//A.h
class B;
class A {
B* someVar;
}
//B.h
#include <A.h>
class B {
A* someVar;
}
But there's no benefit for doing it in the case you laid out.
Think like a compiler. In order to create an A inside of B, the compiler has to know how to build an A, and the only way to do that is to have the complete definition. The forward declaration tells the compiler that class A exists without describing what it looks like; this is adequate for defining a pointer or a reference. When it comes time to use that pointer or reference, the complete class definition will be required.
If you meant to portray some_variable as a pointer then the frequently recommended practice is to use forward declarations whenever possible to avoid the overhead of includes and longer compile times.
I'm all for best practices but I really like using IDEs that have nice code navigation features and forwards cause a problem there, at least with Netbeans. Whenever I try to navigate to a type declaration, I always end up at the forward and not the .h file containing the actual declaration. I'm willing to accept some extra compile time for the ease of navigation. Maybe this is just a problem with Netbeans :)
.. oh yeah.. If you look at the related questions to the right of your question, you will find lots of additional information of forward declarations.
For case 1, compiler will complain with "incomplete type" for class B because class B contains a class A object, and you did not tell B any detail of class A, so compiler cann't decide the size of object B.
For your case, you can use A& obj or A* obj instead of A obj, since the size of a reference/pointer is const(4/8 for 32bit/64bit CPU).

Class name does not name a type in C++

I just started programming in C++, and I've tried to create 2 classes where one will contain the other.
File A.h:
#ifndef _A_h
#define _A_h
class A{
public:
A(int id);
private:
int _id;
B _b; // HERE I GET A COMPILATION ERROR: B does not name a type
};
#endif
File A.cpp:
#include "A.h"
#include "B.h"
#include <cstdio>
A::A(int id): _id(id), _b(){
printf("hello\n the id is: %d\n", _id);
}
File B.h:
#ifndef _B_h
#define _B_h
class B{
public:
B();
};
#endif
File B.cpp:
#include "B.h"
#include <cstdio>
B::B(){
printf("this is hello from B\n");
}
I first compile the B class and then the A class, but then I get the error message:
A.h:9: error: ‘B’ does not name a type
How do I fix this problem?
The preprocessor inserts the contents of the files A.h and B.h exactly where the include statement occurs (this is really just copy/paste). When the compiler then parses A.cpp, it finds the declaration of class A before it knows about class B. This causes the error you see. There are two ways to solve this:
Include B.h in A.h. It is generally a good idea to include header files in the files where they are needed. If you rely on indirect inclusion though another header, or a special order of includes in the compilation unit (cpp-file), this will only confuse you and others as the project gets bigger.
If you use member variable of type B in class A, the compiler needs to know the exact and complete declaration of B, because it needs to create the memory-layout for A. If, on the other hand, you were using a pointer or reference to B, then a forward declaration would suffice, because the memory the compiler needs to reserve for a pointer or reference is independent of the class definition. This would look like this:
class B; // forward declaration
class A {
public:
A(int id);
private:
int _id;
B & _b;
};
This is very useful to avoid circular dependencies among headers.
I hope this helps.
error 'Class' does not name a type
Just in case someone does the same idiotic thing I did ...
I was creating a small test program from scratch and I typed Class instead of class (with a small C). I didn't take any notice of the quotes in the error message and spent a little too long not understanding my problem.
My search for a solution brought me here so I guess the same could happen to someone else.
NOTE: Because people searching with the same keyword will land on this page, I am adding this answer which is not the cause for this compiler error in the above mentioned case.
I was facing this error when I had an enum declared in some file which had one of the elements having the same symbol as my class name.
e.g. if I declare an enum = {A, B, C} in some file which is included in another file where I declare an object of class A.
This was throwing the same compiler error message mentioning that Class A does not name a type. There was no circular dependency in my case.
So, be careful while naming classes and declaring enums (which might be visible, imported and used externally in other files) in C++.
You must first include B.h from A.h. B b; makes no sense until you have included B.h.
The problem is that you need to include B.h in your A.h file. The problem is that in the definition of A, the compiler still doesn't know what B is. You should include all the definitions of all the types you are using.
Include "B.h" in "A.h". That brings in the declaration of 'B' for the compiler while compiling 'A'.
The first bullet holds in the case of OP.
$3.4.1/7 -
"A name used in the definition of a
class X outside of a member function
body or nested class definition27)
shall be declared in one of the
following ways:
— before its use in
class X or be a member of a base class
of X (10.2), or
— if X is a nested
class of class Y (9.7), before the
definition of X in Y, or shall be a
member of a base class of Y (this
lookup applies in turn to Y’s
enclosing classes, starting with the
innermost enclosing class),28) or
— if
X is a local class (9.8) or is a
nested class of a local class, before
the definition of class X in a block
enclosing the definition of class X,
or
— if X is a member of namespace N,
or is a nested class of a class that
is a member of N, or is a local class
or a nested class within a local class
of a function that is a member of N,
before the definition of class X in
namespace N or in one of N’s enclosing
namespaces."
when you define the class A, in A.h, you explicitely say that the class has a member B.
You MUST include "B.h" in "A.h"
Aren't you missing the #include "B.h" in A.h?
The solution to my problem today was slightly different that the other answers here.
In my case, the problem was caused by a missing close bracket (}) at the end of one of the header files in the include chain.
Essentially, what was happening was that A was including B. Because B was missing a } somewhere in the file, the definitions in B were not correctly found in A.
At first I thought I have circular dependency and added the forward declaration B. But then it started complaining about the fact that something in B was an incomplete type. That's how I thought of double checking the files for syntax errors.
Try to move all includes outside namespace.
//Error
namespace U2 {
#include <Head.h>
#include <LifeDiode.h>
}
//Solution
#include <Head.h>
#include <LifeDiode.h>
namespace U2 {
}
Not the answer, but for me the thing was that I forgot to add the std:: before the potential type to properly use it.
It actually happend to me because I mistakenly named the source file "something.c"
instead of "something.cpp".
I hope this helps someone who has the same error.