Does forward declaration fully remove the need for any #including for pointer types?

485 Views Asked by At

Let's assume that we have a source file A.cpp where we forward declare a type ClassB, and then we keep using pointers to ClassB without ever #including file B.cpp (where ClassB is defined); And in B.cpp we forward declare ClassA and use a pointer to it without ever #including A.cpp (where ClassA is defined), then is the compiler fully happy with that? and will symbols resolution work just fine? In other words, do these two object files need not know about one another at all before link-time?

(I am assuming compiling C++ code on visual studio without any changes to the default compiler)

PS:

File A.cpp

class ClassB;

class ClassA
{
bool JustTakeAClassBPointAndDoNothingWithIt(ClassB* class_b_pointer)
{
if(class_b_pointer)
return true;
else
return false;
return false;
}
}

File B.cpp

class ClassA;

class ClassB
{
bool JustTakeAClassAPointAndDoNothingWithIt(ClassA* class_a_pointer)
{
if(class_a_pointer)
return true;
else
return false;
return false;
}
}
2

There are 2 best solutions below

0
On BEST ANSWER

This questions is really too general to answer properly, but here's my 2 cents. In general, as long as you only refer to a class as a pointer to it, compilation will work. eg this example compiles fine:

class B;

int main() {
    B * tst;
    return 0;
}

However, as soon as you try to actually instantiate a the pointer, or access any of its methods, you need a full definition. Those examples will NOT work:

class B;

int main() {
    B * tst = new B(); // error: allocation of incomplete type 'B'
    return 0;
}

Or:

class B;

int main() {
    B * tst;
    tst->print(); // error: member access into incomplete type 'B'
    return 0;
}

tl;dr; As long as you don't actually interact with it, you can use an incomplete type. If you use any method or function, you need to declare them in advance (including constructors)

0
On

It depends on what exactly you want to do with the pointer - you will only be able to do very limited things with pointers to forward-declared types. For example, an assigment, like this, is fine:

class A;

void myFunc(A* a1)
{
    A* a2 = nullptr; 
    A* a3 = a1;
}

But you will not even be able to increment/decrement them (because for that, the compiler has to know the size of the objects to "walk over). Neither will you be able to construct an object of this type, or access any of its methods (because for that, of course the compiler needs to know what the type looks like, or what methods it has). See the examples given in the answer by XapaJIaMnu.

One additional point about your question - you mention including "B.cpp". This suggests that either

  • you only have one file which includes both your declaration and your definition, which is bad practice (split them up into .h and .cpp files! and only include the .h file!)
  • or that you are actually including the file with definitions instead of the header file - which is never required, unless you're doing something wrong; e.g. templates can be tricky in this regard - they basically should be defined in the headers as well.

In order to give more details, you'll have to provide more information on what exactly you want to do with such forward-declared pointers.

See also