acn3 acn3 - 10 days ago 5
C++ Question

Errors using forward declaration in c++

I am trying to write a simple program in c++ where I have 2 classes, and both can access functions from each other. This is a simplification of what I am actually trying to do in the end, which is to create a game with board and piece classes. I was able to do this in java, but I am now running into problems trying to do the same in c++. My code is as follows:

#include <iostream>
class B;
class A {
public:
void sync(B obj){
b = obj;
}
void print(){
std::cout << "Hello from class A" << std::endl;
}
void printBoth(){
std::cout << "Hello from class A" << std::endl;
b.print();
}
private:
B b;
};

class B {
public:
B(A obj){
a = obj;
}
void print(){
std::cout << "Hello from class B" << std::endl;
}
void printBoth(){
std::cout << "Hello from class B" << std::endl;
a.print();
}
private:
A a;
};

int main(){
A a;
B b(a);
a.sync(b);
a.printBoth();
std::cout << std::endl;
b.printBoth();
return 0;
}


When I try to compile this with
g++ example.cpp
, I receive 5 errors:

example.cpp:20:5: error: field ‘b’ has incomplete type
B b;
^
example.cpp: In member function ‘void A::sync(B)’:
example.cpp:7:8: error: ‘obj’ has incomplete type
void sync(B obj){
^
example.cpp:3:7: error: forward declaration of ‘class B’
class B;
^
example.cpp:8:4: error: ‘b’ was not declared in this scope
b = obj;
^
example.cpp: In member function ‘void A::printBoth()’:
example.cpp:17:4: error: ‘b’ was not declared in this scope
b.print();
^


I have never used forward declaration with classes, so I apologize if I am missing something glaringly obvious. Any help is appreciated, and I thank you in advance.

Answer

There are two problems with your code.

Let's take the first problem.

Here's an example of two classes with methods that call each other. Pretty meaningless, and results in an infinite loop, but this demonstrates the general principles of forward declarations, and you can use this as a template to fix the code you've shown.

class A {

public:
     void foo();
};

class B {

public:
      void foo();
};

void A::foo()
{
   B b;

   b.foo();
}

void B::foo()
{
   A a;

   a.foo();
};

Now, the second problem with your code:

As written, your class A contains an instance of class B, which contains an instance of class A, which contains an instance of class A, which contains an instance of class B, all the way until the universe implodes in one massive black hole. Suffice to say, this is not going to compile.

C++ objects are fundamentally different from Java objects. They work in completely different ways. You can do this in Java because the dirty little secret is that all objects in Java are really a mirage, they are really reference-counted pointers to the actual objects. In C++, the closest equivalent of this would be to declare a std::shared_ptr to the object:

#include <memory>

class A;
class B;

class A {

  // ...

  private:
            std::shared_ptr<B> b;
};

class B {

  // ...

  private:
            std:shared_ptr<A> a;
};

And this would be the second problem with your shown code. In general, you need to pretty much forget everything you know about Java objects, when learning C++ objects. They are fundamentally different, and trying to consistently draw analogies between what you already know about Java objects, and C++ objects, will only lead to confusion.