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).
Related
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.
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
I'm not exactly certain what happens but take the following:
class A{
}
-
class B{
#include "A.h"
}
-
class C{
#include "B.h"
}
Now if I were to code in class C does it mean class A is also automatically included as well? From what I understand is that #include basically copies the entire file right on the spot.
Can anyone elaborate on this?
I'm trying to use class forwarding as much as I can. But sometimes I simply can not.
Edit:
The classes above are not in the same file. Imagine them separated.
Edit II:
Let me put it into more context.
Lets say I'm creating a new class that includes class B, but then I declare a variable of type A. This seems to compile even though I never included A to the class. Is this just how it goes in C++?
That would basically declare a nested class called A inside class B.
Cases where include directives should be anywhere else other than the top of the file are very rare, and usually have completely different purpose than what you have.
If I understood your file hierarchy correctly, it's equivalent to:
//A.h
class A{
};
//B.h
class B{
class A{
};
};
//C.h
class C{
class B{
class A{
};
};
};
You are right, the preprocessor just copies the headers in. Think of it like a long macro if you will.
A #include directive simply tells the compiler to pretend that the text in the named file had been written where the #include directive occurs. It has nothing to do with scopes, syntax, or anything else. It's simply text.
Without seeing the contents of A.h and B.h it's impossible to say anything more about what the effects of those #include directives are.
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.
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.