2

I have a simple code below:

class B;
class A{
    B b;
};

class B{
public:
    B(){

    }
};

In class A's definition, I have a B-typed property. Using MS Visual Studio to compile, I've got the following error:

error C2079: 'A::b' uses undefined class 'B'

Due to some reasons, I can't put class B's definition before class A's one. Any idea?

razlebe
  • 6,916
  • 6
  • 38
  • 53
anhldbk
  • 4,507
  • 5
  • 25
  • 34
  • 3
    What do you mean saying "some reasons" ? What are those reasons? – Patryk Czachurski Mar 18 '11 at 10:22
  • if class B does not need definition of class A - define class B first, then class A. Otherwise you will be forced to use pointers. – rmflow Mar 18 '11 at 10:27
  • The reason here can be explained by the term "Circular dependency". See more at http://en.wikipedia.org/wiki/Circular_dependency. All what I want is to place declarations of 2 classes in one file. :( – anhldbk Mar 19 '11 at 03:50

4 Answers4

12

The compiler is already telling you what's wrong : A has a member data b which is of an undefined type. Your forward declaration:

class B;

is just that : a declaration, not a definition. Since class A contains an instance of B directly (not just a pointer to B), the compiler needs to know the exact size of B : it needs its definition, not just a declaration, i.e. a promise that B will exist at some point.

The simplest thing to do here would be to reorder things this way:

class B{
public:
    B(){

    }
};

class A{
    B b;
};

Edit : see also this question for the difference between declaration and definition.

Further edit : an alternative would be to change your member data to a pointer or a reference. Do note that this isn't a trivial syntax change: it has implications on the life-cycle of your objects since the object pointed by A::b may then survive the destruction of A.

If what you want is composition (B is a part of A and dies with A), using a pointer will make your life harder with little benefits.

More edits(!) : just realized I misread the end of your question; what are the reasons preventing you from declaring B before A ?

If they cannot be worked around, you may have to go the pointer route. These reasons might be a sign that your objects are too tightly coupled though ! (perhaps B needs to be an inner class of A ? Or simply be merged into a single object ?)

Community
  • 1
  • 1
Nicolas Lefebvre
  • 4,027
  • 22
  • 28
1
class A;

class B {
  A * getA();
};

class A {
  B b;
};

This is the typical way to solve this. You must have B's definition in order to have a B b; member.

You need a forward declaration in order to declare a reference/pointer to B, you need the full definition in order to do anything else with B (such as defining a variable, calling a member function and so on)

Erik
  • 80,488
  • 12
  • 185
  • 183
1

You can do what you wish if you change the reference to b into a pointer to B.

class A{
    B* bPtr;
};

class B{
public:
    B(){

    }
};

In principle, you don't need an explicit declaration - that is, a forward declaration is all that is needed - when you don't need the actual size of the class, or access to the types and member functions inside the class.

In your original example, you are making a direct reference to B. As a result, the compiler needs to know everything about B, thus requiring an explicit declaration instead of a forward one.

By having your A class declaration using a pointer to B, then you can get away with a forward declaration.

edit

Some links might explain the concept for you:

http://www.goingware.com/tips/parameters/notrequired.html

http://www-subatech.in2p3.fr/~photons/subatech/soft/carnac/CPP-INC-1.shtml

http://www.codeguru.com/forum/showthread.php?t=358333 (see post #2)

http://en.wikipedia.org/wiki/Forward_declaration

luis.espinal
  • 9,728
  • 5
  • 35
  • 54
1

C++ has the concept of an "incomplete" class and it is something you need to know.

Using an incomplete class allows you, in many situations, to use a class just knowing it is one, without knowing what is in it.

This enables the class detail to change later without requiring a recompile, thus it is a far weaker dependency in the coupling model.

You need a complete class to:

  • Have an instance of one.
  • Derive from it
  • Call any method on it.
  • delete a pointer to it.

You only need an incomplete class to:

  • Hold a pointer or reference to it.
  • Pass a pointer or reference to a function that takes a pointer or reference. (This can be a function that deletes the pointer, as long as it is fully defined at that point).

I think you only need an incomplete class to declare a function that returns one, and possibly to declare a function that takes one as a parameter, but at the time you define or call the function it needs to be complete, even if you don't use the return value.

CashCow
  • 29,087
  • 4
  • 53
  • 86