Taztingo
Taztingo

Reputation: 1945

Slaying the Circular Dependence

I'm having a problem compiling with circular dependencies. I did some research, and people recommended using a forward declaration. I'm still having a problem with that because the class that has a forward declaration is using methods from the forwarded class. This causes the compiler to give me the error "Class A has incomplete field b". How can I get around the circular dependency where A requires B, and B requires A?

A.h:

#ifndef A_H_
#define A_H_

#include <iostream>
//#include "B.h"

class A
{
    class B;
    private:
        B b;
    public:
        A();
        ~A();
        void method();
};
#endif

A.cpp:

#include <iostream>
#include "A.h"

A::A()
{
}

A::~A()
{
}

void A::method()
{
    b.method();
}

B.h:

#ifndef B_H_
#define B_H_

#include <iostream>
//#include "A.h"

class B
{
    class A;
    private:
        A a;
    public:
        B();
        ~B();
        void method();
};
#endif

B.cpp:

#include <iostream>
#include "B.h"

B::B()
{
}

B::~B()
{
}

void B::method()
{
    a.method();
}

Upvotes: 1

Views: 139

Answers (4)

Sam Cristall
Sam Cristall

Reputation: 4387

This will not work as you have constructed it as A requires full knowledge of the size of B and B requires the same of A, which is only given by seeing the full declaration.

The following is not valid:

class B;
class A {
   B b;
};

Why? How much space do we allocate for an instance of A? sizeof(A) = sizeof(B) = undefined There is a workaround, however:

class B;
class A {
    B* b_ptr;
    B& b_ref;
};

This is perfectly valid, since the pointer and reference's size are known, regardless of the type they point to.

Upvotes: 3

jdc
jdc

Reputation: 339

You could try to replace one of the member by a pointer to the other class :

class B;
class A
{
    private:
        B* b;
    public:
        A();
        ~A();
        void method();
};

Upvotes: 2

Christopher Creutzig
Christopher Creutzig

Reputation: 8774

Your classes cannot work. Every A contains a B, which contains an A, which contains a B, etc., ad infinitum.

Upvotes: 7

Chad
Chad

Reputation: 19052

In at least one case (either A or B) you have to remove the dependence on the complete type. For example, below I've removed the need for A to have the complete type of B within the A.h header file:

// A.h
class B;

// B used as a reference only, so the complete type
// is not needed at this time
class A
{
public:
   A(B& b) : b_(b) {}

   void method();

private:
   B& b_;
};

// A.cpp
// B is used, and the complete type is required
#include "B.h"

void A::f()
{
   b.method();
}

Upvotes: 3

Related Questions