5

I meet a problem like this: UPDATE

class A
{
public:
    A(){}
    int i;
    B b;
};

class B
{
public:
    B(){}
    int j;
    A a;
};

When I define it in one .h file, it would give an error. I think the problem is the recursive definition. But could someone help me how to solve such issue?

  1. error C2146: syntax error : missing ';' before identifier 'b' c:\users\xingyo\documents\visual studio 2010\projects\cppalgo\recudef\test1.h 9 1 RecuDef

  2. error C4430: missing type specifier - int assumed. Note: C++ does not support default-int c:\users\xingyo\documents\visual studio 2010\projects\cppalgo\recudef\test1.h 9 1 RecuDef

  3. error C4430: missing type specifier - int assumed. Note: C++ does not support default-int c:\users\xingyo\documents\visual studio 2010\projects\cppalgo\recudef\test1.h 9 1 RecuDef

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Yongwei Xing
  • 12,983
  • 24
  • 70
  • 90
  • 6
    What exactly do you want to do? The example you give contains errors and leaves us guessing. Did you really mean to declare a nested class `class B` inside class `A`, etc.? That wouldn't be recursive. Also, if you get an error **tell us what that error is**. The first step to solving an error is to know the error. – sth Nov 29 '10 at 02:37
  • I am sorry, I have updated the question – Yongwei Xing Nov 29 '10 at 03:08

5 Answers5

17

This is not possible verbatim in C++. The explanation is that the compiler needs full, not just forward, declaration of a class to be able to use it as a member of another class. It simply needs the size of a class object.

The workaround in C++ (and in C) is to use a pointer or a reference as a member of one of the classes. That way you can use forward declaration as follows:

class A; // forward declaration

class B {
    // ...
    A* pa;
};

class A { // full declaration
    // ...
    B b;
};

It's your (not the compiler or runtime) responsibility to keep the instance of A that instance of B points to (or references) valid.

Nikolai Fetissov
  • 82,306
  • 11
  • 110
  • 171
6

You can't solve it. It's meaningless. You've defined A to contain B which contains another A which contains another B which ... You can't possibly have intended that. Maybe you need to use a pointer or a reference?

user207421
  • 305,947
  • 44
  • 307
  • 483
1

Split you codes into 4 files, say A.h, A.cpp, B.h, and B.cpp.

// A.h

class B;
class A {
public:
    A();
    B* b;
};

// A.cpp

#include "A.h"
#include "B.h"

A::A() : b(new B) {
}

// B.h

class A;
class B {
public:
    B(A* a_);
    A* a;
};

// B.cpp

#include "B.h"
#include "A.h"

B::B(A* a_) : a(a_) {
}

And use them this way:

#include "A.h"
#include "B.h"

int main() {
    A a;
    B b(&a);

    // do logics

    return 0;
}
upriser
  • 192
  • 1
  • 7
0

If it is a recursive problem. Declare the classes without the definitions:

class A;
class B;

class A
{
   ...
};

class B
{
   ...
};

See: http://www.gotw.ca/gotw/034.htm

Julio Guerra
  • 5,523
  • 9
  • 51
  • 75
  • 1
    Forward declarations only work for pointers and references. – Dima Nov 29 '10 at 03:19
  • @Dima that's not correct. They also work for classes, structs, and namespaces, and probably unions as well. – user207421 Nov 29 '10 at 04:22
  • 1
    @Dima: He will have to use a pointer or reference anyway, it is simply physically impossible to have two classes or structs contain each other, as the result would have infinite size. – Mephane Nov 29 '10 at 09:42
  • @EJP, you can certainly forward declare classes, structs, and namespaces. But you cannot declare an object of a class or struct that has only been forward declared, because its size is not yet known to the compiler. You can only declare a pointer or a reference to a forward declared class or struct. – Dima Nov 29 '10 at 15:49
  • I agree. That's a bit different to 'forward declarations only work for pointers and references', isn't it? – user207421 Nov 30 '10 at 01:08
0

You cannot have a recursive definition like that in C++. Before you can declare an object of class A, A must be fully defined, so that the sizeof(A) is known to the compiler. Same with B. However, you can get around it by using pointers. You can declare a pointer to an object of class A by simply "promising" to define class A at some later point. This is called forward declaration.

class B;  // forward declaration

class A
{
  B *b;
};

class B
{
  A *a;
};

Forward declarations also work for references.

Dima
  • 38,860
  • 14
  • 75
  • 115