1

I already saw many answers how to create (e.g.) A class with an object B b and a B class with an object A a

like:

B:

class A;
class B{
  A& a;
};

A:

class A{
  B b;
};

but if I want to call a function from A in B I got: Invalid use of incomplete type 'class A' What can I do? I think I know why the compiler say that, but I don't know how to fix it.

Here my latest Code:

Main.cpp:

#include "mainclass.h"

int main()
{
    MainClass mainClass;
    mainClass.print();
    return 0;
}

MainClass.h:

#ifndef MAINCLASS_H
#define MAINCLASS_H

#include <iostream>

#include "subclass.h"

class MainClass
{
    SubClass sub;
    public:
        void print() { sub.print(); }
        void printTest() { std::cout << "test" << std::endl; }
};

#endif

SubClass.h:

#ifndef SUBCLASS_H
#define SUBCLASS_H

class MainClass;
class SubClass
{
    MainClass* main;

    public:
        void print() { main->printTest(); }
    protected:

    private:
};

#endif
DanielFvM
  • 45
  • 3
  • The both classes are unrelated, i.e. aren't bound by inheritance. The error is because you didn't include `MainClass.h` in `SubClass.h`. This will lead to the cyclic dependency, though. Therefore you need to define your functions in cpp files. – vahancho Apr 13 '18 at 13:41
  • Possible duplicate: https://stackoverflow.com/q/11344195/2640636 – SU3 Apr 13 '18 at 13:59

4 Answers4

2

The main problem with your code is that the definition of MainClass and SubClass are mutually dependent, therefore the use of the header guards will forbid the inclusion of both header files in the same translation unit (i.e. the union of a cpp file and the all the header files included.)

The forward declaration of class MainClass in subclass.h could solve this problem, since the SubClass::main is a pointer (check the PIMPL idiom), but since you have included the implementation of the class methods in the in the header files, the compiler fails when the SubClass::print() method makes a reference to MainClass::printTest() because it knows nothing about the class MainClass except the fact that it is defined somewhere else.

On the other hand, changing the forward declaration with the explicit inclusion of mainclass.h in subclass.h is not a solution, because of the header guards, as said above.

The simple solution is to split the declaration and the implementation of you classes in .h and .cpp files. If you do so, the compiler will work on multiple translation units: one for the mainclass.cpp, one for the subclass.cpp and one for the main.cpp. When processing the subclass.cpp translation unit, the compiler will be able to include the file mainclass.h and will have the complete definition of MainClass to "see" that a MainClass::printTest() method exists.

Here is the mainclass.h:

#ifndef MAINCLASS_H
#define MAINCLASS_H

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

class MainClass
{
SubClass sub;
public:
    void print();
    void printTest();
};

#endif

the mainclass.cpp file:

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

void MainClass::print()
{
    sub.print();
}

void MainClass::printTest()
{
    std::cout << "test" << std::endl;
}

The subclass.h file:

#ifndef SUBCLASS_H
#define SUBCLASS_H

class MainClass;
class SubClass
{
    MainClass* main;

public:        
    void print();
};

#endif

the subclass.cpp:

#include "mainclass.h"
//#include "subclass.h" // already included with the previous line

void SubClass::print()
{
    main->printTest();
}

and finally the main.cpp:

#include "mainclass.h"

int main()
{
    MainClass mainClass;
    mainClass.print();
    return 0;
}

This will compile and will apparently work, because it will print the string "test" even if the main pointer is not initialized, and points to an undefined memory area.

This happens because the printTest method does nothing but producing a side effect, i.e. printing on screen. Indeed it does not access to any data member of the MainClass through the this pointer, and therefore you have no memory access violation. Indeed, invoking a method on a not instantiated pointer is an undefined behavior, so it would be better to avoid it, as well as cyclic dependencies.

Gabriella Giordano
  • 1,188
  • 9
  • 10
1

Avoid creating function bodies in H files and put the function body into Cpp file.

MainClass.h:

#ifndef MAINCLASS_H
#define MAINCLASS_H

#include <iostream>

#include "subclass.h"

class MainClass {
    SubClass sub;
    public:
        void print();
        void printTest();
};
#endif

MainClass.cpp:

#include <iostream>

#include "mainclass.h"

void MainClass :: print () { sub.print(); }

void MainClass :: printTest() {std::cout << "test" << std::endl; }

SubClass.h

#ifndef SUBCLASS_H
#define SUBCLASS_H

#include "mainclass.h"

class SubClass
{
    MainClass* main;

    public:
        void print();
    protected:

    private:
};

#endif

SubClass.cpp

#include "mainclass.h"
#include "subclass.h"

void SubClass::print ()
{
    main->printTest();
}

you can actually #include "mainclass.h" in your subclass.h because it is guarded by #ifdef

pm101
  • 1,309
  • 10
  • 30
1

You can't call a function (MainClass::printTest) that does not exist yet.

You can declare the function inside the SubClass, but define it after you have the MainClass definition.

#include <iostream>

class MainClass;
class SubClass
{
    MainClass* main;

    public:
        void print();
    protected:

    private:
};

class MainClass
{
    SubClass sub;
    public:
        void print() { sub.print(); }
        void printTest() { std::cout << "test" << std::endl; }
};

void SubClass::print() { main->printTest(); }

int main()
{
    MainClass mainClass;
    mainClass.print();
    return 0;
}
SU3
  • 5,064
  • 3
  • 35
  • 66
0

You have a design problem:-

  1. How come in SubClass.h compiler will know class MainClass has a method printTest so that it can link to it as you did not included the header file for the definition of MainClass

  2. Another problem is you can not even include MainClass.h in SubClass.h because you are reference to SubClass sub; in it.

  3. MainClass* main; pointer main never initialized and hence this statement void print() { main->printTest(); } is also wrong here.

Abhijit Pritam Dutta
  • 5,521
  • 2
  • 11
  • 17