62

I'm looking to create two classes, each of which contains an object of the other class type. How can I do this? If I can't do this, is there a work-around, like having each class contain a pointer to the other class type? Thanks!

Here's what I have:

File: bar.h

#ifndef BAR_H
#define BAR_H
#include "foo.h"
class bar {
public:
  foo getFoo();
protected:
  foo f;
};
#endif

File: foo.h

#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo {
public:
  bar getBar();
protected:
  bar b;
};
#endif

File: main.cpp

#include "foo.h"
#include "bar.h"

int
main (int argc, char **argv)
{
  foo myFoo;
  bar myBar;
}

$ g++ main.cpp

In file included from foo.h:3,
                 from main.cpp:1:
bar.h:6: error: ‘foo’ does not name a type
bar.h:8: error: ‘foo’ does not name a type
Steve Johnson
  • 949
  • 3
  • 12
  • 13

2 Answers2

123

You cannot have two classes directly contain objects of the other type, since otherwise you'd need infinite space for the object (since foo has a bar that has a foo that has a bar that etc.)

You can indeed do this by having the two classes store pointers to one another, though. To do this, you'll need to use forward declarations so that the two classes know of each other's existence:

#ifndef BAR_H
#define BAR_H

class foo; // Say foo exists without defining it.

class bar {
public:
  foo* getFoo();
protected:
  foo* f;
};
#endif 

and

#ifndef FOO_H
#define FOO_H

class bar; // Say bar exists without defining it.

class foo {
public:
  bar* getBar();
protected:
  bar* f;
};
#endif 

Notice that the two headers don't include each other. Instead, they just know of the existence of the other class via the forward declarations. Then, in the .cpp files for these two classes, you can #include the other header to get the full information about the class. These forward declarations allow you to break the reference cycle of "foo needs bar needs foo needs bar."

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 18
    "foo needs bar needs foo needs bar." lawl. =P – prolink007 Feb 11 '11 at 00:55
  • Actually, if they only contained each other, no space would also suffice. But that degenerate case isn't useful. and so there are no special provisions made for it. – Deduplicator Aug 31 '18 at 19:09
  • but how can i invoke a method with help of these pointer inside the class without giving rise to the error – nabhiraj jain Nov 05 '18 at 17:36
  • Once you’ve written both header files, in your .cpp file you can include both headers to pull in both class definitions. From there you can use any member functions you’d like. If you’re having trouble getting this working, feel free to post a separate question outlining your situation! – templatetypedef Nov 05 '18 at 17:39
  • wow.... this is the best answer by far. it also allows you to use instances of each class in both. is what l was looking for, – vincent thorpe Jul 02 '19 at 11:08
  • what if I want, for example, from a method of foo to use a method or a variable of bar, will I have to change anything? – platinoob_ Aug 24 '20 at 06:39
  • @platinoob_ In that case, use forward declarations as in the above in the header files, then in the .cpp files #include the other header and you can reference the other member functions without issue. – templatetypedef Aug 24 '20 at 16:16
5

That doesn't make sense. If A contains B, and B contains A, it would be infinite size. Imagine putting having two boxes and trying to put both into each other. Doesn't work, right?

Pointers work though:

#ifndef FOO_H
#define FOO_H

// Forward declaration so the compiler knows what bar is
class bar;

class foo {
public:
  bar *getBar();
protected:
  bar *b;
};
#endif
EboMike
  • 76,846
  • 14
  • 164
  • 167