If you’re defining a class, but only declaring its member functions, then you can easily add a pointer to a different class. You don’t need to know the structure of a class to be able to hold a pointer to it - it’s only when you try to dereference it, or use it to call a member function of that class, that you find a problem.
So, the solution is always to separate the implementation of your functions (specifically any that make use of the pointer) from the class definition.
you obviously know your stuff and so i apologise if the rest of this sounds really elementary and childish! but examples are fun!
For example, in my class I know that i need to make use of a gwargle… i even know that a particular function will take/return a gwargle… but right now i don’t know what a gwargle is, and that’s okay because i don’t yet know what those functions will try to do with it. As long as i know that a gwargle exists (forward declaration) and i don’t try to do anything with it, i’m okay. The same goes for the gwargle… he is expecting to have to do something with me at some point… he knows he’s got to bear me in mind, but until he goes off to compile his plans, he doesn’t need to know what i actually am. And by the time he’s got back, he’ll have been given a blueprint showing exactly what he needs to know about me. Heck, i’ve just started learning my ‘gwargle’ functions and i’ve got here a gwargle schematic so i know which bits do what.
So a ‘simple’ solution is to make sure that both classes have their classes defined each in a separate header, each keeping their member function definitions in an external implementation file. The class definitions in the headers are each preceded with a forward declaration of the other, and both implementation files include both headers.
Here’s another simplistic example. [Don’t worry about reading all the code, the important bits are commented and obvious…]
Most basic example, with obvious errors:
class A
{
public:
int a;
B* b_ptr; // <--- first error
void f()
{
b_ptr->b = a;
}
};
class B
{
public:
int b;
A* a_ptr;
void f()
{
a_ptr->a = b;
}
};
Here, class A gives an error, trying to make a pointer to a ‘B’ (which the compiler does not yet know about)… a forward declaration of class B enables the compiler to know enough to allow a pointer to exist…
class B; // forward declaration...
class A
{
public:
int a;
B* b_ptr; // <--- this is okay now...
void f()
{
b_ptr->b = a; // <--- but THIS is not okay
}
};
class B
{
public:
int b;
A* a_ptr;
void f()
{
a_ptr->a = b;
}
};
… but now the key problem is that the compiler still doesn’t know how to use the pointer- it certainly doesn’t know that there is a ‘b’ int member in this ‘B’ class type.
So we take the function definition outside, away from the class definition, leaving just a declaration…
class B; // forward declaration...
class A
{
public:
int a;
B* b_ptr;
void f(); // <-- the definition would be in A.cpp
};
class B
{
public:
int b;
A* a_ptr;
void f()
{
a_ptr->a = b;
}
};
Everything else in this example is now fine. Of course, we can take it further by putting B into its own file.
// A.h
//----------------------
class B; // forward declaration...
class A
{
public:
int a;
B* b_ptr;
void f(); // <-- the definition would be in A.cpp
};
// B.h
//----------------------
class A; // forward declaration...
class B
{
public:
int b;
A* a_ptr;
void f(); // <-- the definition would be in B.cpp
};
// A.cpp
//----------------------
void A::f()
{
b_ptr->b = a;
}
// B.cpp
//----------------------
void B::f()
{
a_ptr->a = b;
}