0

My code has 2 related classes:
Class1 has pointer field to instance of Class2;
Class2 has pointer field to instance of Class1:

class1.hpp

#ifndef __CLASS_1_HPP
#define __CLASS_1_HPP

#include "all.hpp"

class Class1
{
public:
    Class1();
private:
    Class2 *c2;
};

Class1::Class1() 
{
    c2 = new Class2();
}

#endif // __CLASS_1_HPP

class2.hpp

#ifndef __CLASS_2_HPP
#define __CLASS_2_HPP

#include "all.hpp"

class Class2
{
public:
    Class2();
private:
    Class1 *c1;
};

Class2::Class2() 
{
    c1 = new Class1();
}

#endif // __CLASS_2_HPP

all.hpp

#ifndef __ALL_HPP
#define __ALL_HPP

class Class1;
class Class2;
#include "class1.hpp"
#include "class2.hpp"

#endif // __ALL_HPP

main.cpp

#include "all.hpp"
int main() {}

When I'm trying to compile this I get Invalid use of incomplete type Class2 on line c2 = new Class2();. Division .hpp files on .hpp and .cpp does not help!

julia
  • 3
  • 2
  • Note that names like `__CLASS_1_HPP` are not allowed to be created in user code - simply use `CLASS_1_HPP` –  Feb 23 '18 at 17:56
  • @NeilButterworth I'll keep this in mind, thank you. – julia Feb 23 '18 at 18:01

3 Answers3

0

all.hpp is included. So, Class1 and Class2 are forwarded until a full definition.

Then class1.hppis included. The constructor for Class1 is both declared and defined.

The definition of this ctor calls new Class2(), but at this point the constructor of Class2 is not defined yet. The compiler only knows that Class1 stores a pointer to an object of type Class2, not how to build that object.

Perhaps you want to separate declarations (in headers) from definitions (in .cpp code)

Ripi2
  • 7,031
  • 1
  • 17
  • 33
0

Let see all these through the compiler glasses. After the pre-processor did it work you end up with a so called translation unit looking like this:

main.cpp:

class Class1;
class Class2;

class Class1
{
public:
    Class1();
private:
    Class2 *c2;
};

Class1::Class1() 
{
    c2 = new Class2();    // error: invalid use of incomplete type 'class Class2'
    /// So all what the compiler knows at this point
    /// about Class2 is that's a class, but not how to create it.
    /// It was just declared but not defined yet.
}

class Class2
{
public:
    Class2();
private:
    Class1 *c1;
};

Class2::Class2() 
{
    c1 = new Class1();
}

int main() {}

At the line c2 = new Class2(); all what the compiler knows about Class2 is that is's a class, but not how to create it. It was just declared but not defined yet.

So usually this problem is solved by putting the class member function definitions in separate source (e.g. cpp) files that include the header files with the definition of both classes.

Class1.cpp:

#include "class1.hpp"
#include "class2.hpp"
Class1::Class1() 
{
    c2 = new Class2();
}

Class2.cpp:

#include "class2.hpp"
#include "class1.hpp"
Class2::Class2() 
{
    c1 = new Class1();
}

And leave only the class defintions in the header files:

#ifndef __CLASS_1_HPP
#define __CLASS_1_HPP

class Class2;

class Class1
{
public:
    Class1();
private:
    Class2 *c2;
};
#endif // __CLASS_1_HPP
Mihayl
  • 3,821
  • 2
  • 13
  • 32
0

My guess is you cramped:

class Class1
{
public:
    Class1();
private:
    Class2 * c2;
};
Class1::Class1()
{
    c2 = new Class2();
}

into the Class1.hpp What you need to do is:

Class1.hpp

#include all.hpp
class Class1
{
public:
    Class1();
private:
    Class2 * c2;
};

and

Class1.cpp

#include "Class1.hpp"     
Class1::Class1()
{
    c2 = new Class2();
}

Same with the Class2.cpp/Class2.hpp In your code you are not calling the constructors of c1 and c2 ( Class1::Class1() ), since you didn't create the objects there but in the hpp which doesn't work. If you want to create the objects in the header you can try initializers.

Community
  • 1
  • 1
innuendomaximus
  • 353
  • 2
  • 3
  • 17