views:

136

answers:

7

I have a bit of problem with this. I have a class A which instantiates an object of B and then B which instantiates an object of A. Is this at all possible? I tried adding this in the headers of each

#ifndef A
#define A
  class a...
#endif

but if keeps me in an infinite header loop which it reaches the maximum header includes, so obviously one is calling the other and the other is calling that one. Is there any way to achieve this?

edit: Okay this seems like a good answer but now A complains that B doesn't have a Constructor despite the fact that it definitely has a constructor. I can't figure that one out.

+7  A: 

You can forward declare the classes, for example:

A.h:

class B;

class A
{
    B* a_;
};

B.h:

class A;

class B
{
    A* a_;
};

In your source files where you actually use the classes (that is, create them, destroy them, use their members, etc.), you will need to include both headers so that their definitions are available:

#include "A.h"
#include "B.h"
James McNellis
Using a smart pointer is recommended to simplify your destructor a little. :-) If one class is using `shared_ptr`, the other should be a `weak_ptr`, to avoid circular references.
Chris Jester-Young
Would this mean I don't have to use the #include A or B anymore in those classes or headers?
John Baker
@John Baker : Yes, you don't need to include A.h or B.h. Actually, you really shouldn't !
Benoît
Yeah for some reason this won't work for me. Now it just says undeclared identifier A
John Baker
With the given example, if you have separate headers for the two classes (which is a good idea), you would need to include `B.h` in `A.h` (but not `A.h` in `B.h`). You can avoid doing this by forward declaring `B` in `A.h` as well. You will have to include both `A.h` and `B.h` in source files (`.cpp`s) that make use of classes `A` and `B`.
James McNellis
Oh man that is confusing. Could I beg for an ammended sample?
John Baker
Let me know if the amended sample makes it clearer.
James McNellis
Yes your sample is absolutely perfect! Now I get it. Thanks A TON! Definitely got the accepted answer, solved my problem perfectly. Thanks again
John Baker
You are most welcome.
James McNellis
+1  A: 

Have you tried using forward declaration?

class B;

class A
{
  private:
     B* instanceOfB_;

};
Extrakun
+3  A: 

You should break this circular dependence. For instance, you could use a pointer to B, and you could then forward declare the B class.

Francesco
+1  A: 

This is not a good design to start with. However to make it possible just use forward declaration.

In classA.h file remove any includes to classB.h and move them to the classA.cpp. Then before declaring classA write the line class B; to forward declare class B. This way you can have member variables of B* (but not B) inside class A. Do the same for classB next.

ruibm
+1  A: 

You can forward declare A in B's header file, and the other way around, to achieve what you want.

// In B.h
class A;

class B
{
  private:
    A a;
};

See Wikipedia for more information.

Håvard S
This should be "A *a"
dseifert
That all depends on whether you want a pointer to an a or a value member. Value members are just as valid as pointer members.
Håvard S
Håvard: you can't forward-declare a value member of a class, because its size is unknown.
Peter
Peter: Ah, right you are, thanks for spotting.
Håvard S
A: 

If you mean class A {B b;}; and class B {A a;}, no you can't. Class data members are included in the class, so you'd have a B that included an A that included a B that included an A.... Remember, in C++ a data object is not a reference to something, but is the actual thing.

You need something like class A {B * b;}; and class B {A * a;}, where you are providing pointers. Before the definitions, you need something like class A; class B; to tell the compiler that A and B are classes. These are called "forward declarations".

David Thornley
A: 

If you can, break the cyclic dependency. One idea is to use a mediator or a 3rd class.

class Mediator
{
// contains common functionality to A & B
// contains dependent functionality
};

class A : public Mediator;
class B : public Mediator;

As some experts say, 'All problems can be resolved with an additional layer of redirection."

Thomas Matthews