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.