views:

161

answers:

5

Hi guys. What is the issue with this code? Here we have two files: classA.h and classB.h

classA.h:

#ifndef _class_a_h_
#define _class_a_h_

#include "classB.h"

class B; //????

class A
{
public:
    A() {
        ptr_b = new B(); //????
    }

    virtual ~A() {
        if(ptr_b) delete ptr_b; //????
                    num_a = 0;
    }

    int num_a;
    B* ptr_b; //????
};

#endif //_class_a_h_

classB.h:

#ifndef _class_b_h_
#define _class_b_h_

#include "classA.h"

class A; //????

class B
{
public:     
    B() { 
        ptr_a = new A(); //????
                    num_b = 0;
    }

    virtual ~B() { 
        if(ptr_a) delete ptr_a; //????
    }

    int num_b;
    A* ptr_a; //????
};

#endif //_class_b_h_

when I try to compile it, the compiler (g++) says:

classB.h: In constructor ‘B::B()’:

classB.h:12: error: invalid use of incomplete type ‘struct A’

classB.h:6: error: forward declaration of ‘struct A’

classB.h: In destructor ‘virtual B::~B()’:

classB.h:16: warning: possible problem detected in invocation of delete operator:

classB.h:16: warning: invalid use of incomplete type ‘struct A’

classB.h:6: warning: forward declaration of ‘struct A’

classB.h:16: note: neither the destructor nor the class-specific operator delete will be

called, even if they are declared when the class is defined.

+2  A: 

EDIT: Read James McNellis's answer first -- this is a code example of what you'd have to do. But the recursion is the bigger point and he deserves any upvotes for that particular point -- not me :)

You can't use inline functions here as the full definition for classes A and B is not available when you're declaring them inline. Declare them as normal functions and you'll be fine with the forward declarations you have.

classA.h

#ifndef _class_a_h_
#define _class_a_h_

#include "classB.h"

class B; //????

class A
{
public:
    A();
    virtual ~A();
    int num_a;
    B* ptr_b;
};

#endif //_class_a_h_

classB.h

#ifndef _class_b_h_
#define _class_b_h_

#include "classA.h"

class B
{
public:     
    B();
    virtual ~B();
    int num_b;
    A* ptr_a;
};

#endif //_class_b_h_

classes.cpp

#include "classA.h"
#include "classB.h"

A::A() {
    ptr_b = new B(); //????
}

A::~A() {
    if(ptr_b) delete ptr_b; //????
}

B::B() { 
    ptr_a = new A; //????
}

B::~B() { 
    if(ptr_a) delete ptr_a; //????
}
Billy ONeal
But...look out for infinite recursion!
Drew Hall
@Drew Hall: Good point -- didn't think of that. But not going to steal James McNellis's points here -- he deserves them.
Billy ONeal
i think it doesn't work at all. have you tried to compile it yourself?
SepiDev
@Billy: You give me too much credit. I've made a minor correction to your answer (the `virtual` specifier only goes in the function declaration, not in the definition); I hope you don't mind. @SepiDev: the code as it stands now will compile. You'll still have to fix the other issues that have been mentioned on this page.
James McNellis
@James McNellis: Doh! Thanks! @SepiDev: Try removing the virtual specifier like James McNellis has done.
Billy ONeal
+9  A: 

You cannot create instances of an incomplete type (the compiler doesn't know anything about the class!)

You need to move the definitions of your functions (the constructor of A and B) into a C++ file that can include both headers (or into several C++ files, if you follow the convention that you have one class per file).

That having been said, your code as written has a serious problem: every A creates an instance of B and every B creates and instance of A. You will end up with an infinite recursion and you will eventually run out of memory.

Two minor nitpicks: you do not need to test whether a pointer is null before calling delete on it (it is safe to delete a null pointer), and you need to change your include guards (names beginning with an underscore in the global namespace are reserved to the implementation).

James McNellis
+1 for the recursion
Rado
+1  A: 

classB.h: In constructor ‘B::B()’:

classB.h:12: error: invalid use of incomplete type ‘struct A’

A is not fully defined. You've only given it a prototype (class A;).

classB.h:6: error: forward declaration of ‘struct A’

classB.h: In destructor ‘virtual B::~B()’:

I think this is the same problem. It needs to know how A is defined so it knows how much memory to free up.

Refactor your code to remove the circular dependency. (A creates B, and B creates A... creates B, creates A, creates B...)

Mark
A: 

The simple solution is to pull your member function definitions out-of-line and into the files classA.cpp and classB.cpp. Remove the mutual includes from the header files and instead insert those into the .cpp files.

Anywhere class A or B is used more than just in name (that is, other than just naming its pointer or reference types), a complete class declaration must already be present. With your current include/inline design, one or the other will necessarily not be complete. By splitting the class implementations out into .cpp files, you allow the declarations to complete gracefully before instantiating objects of type A or B.

Drew Hall
A: 

wow..., thanx alot

I put all the codes in header files just for ease of reading.

I'll try what you suggested now... ////////////////////////////////////////

it seems that the issue still exist. when i just use the pointers in classes everything works fine, but when i try to use new() on pointers in constructor or anywhere else i get the same problem. Can you try to compile the code on you computers to find out the real problem

SepiDev
You should give James McNellis the checkmark if it works for you.
Billy ONeal
i think i doesn't work at all
SepiDev