I am not sure if I asked the most clear question so forgive me if it comes off as opinion based.
In programming, I have generally followed the philosophy that if a library belongs in the .cpp
file, then it should belong in the .hpp
file. However, this does not necessarily apply when it comes to OOP. I came up with a very small example:
Class1 Source:
#include "class1.hpp"
int Class1::getOther(Class2 *obj)
{
return obj->get();
}
void Class1::setOther(Class2 *obj, int val)
{
obj->set(val);
}
Class1 Header:
#ifndef CLASS_1_HPP
#define CLASS_1_HPP
#include "class2.hpp"
class Class1
{
public:
int getOther(Class2 *obj);
void setOther(Class2 *obj, int val);
int get() const { return value; }
void set(int val) { value = val; }
private:
int value;
};
#endif
Class2 Source:
#include "class1.hpp" // Placed here instead of class2.hpp
#include "class2.hpp"
int Class2::getOther(Class1 *obj)
{
return obj->get();
}
void Class2::setOther(Class1 *obj, int val)
{
obj->set(val);
}
Class2 Header:
#ifndef CLASS_2_HPP
#define CLASS_2_HPP
class Class1; // Forward Declaration
class Class2
{
public:
int getOther(Class1 *obj);
void setOther(Class1 *obj, int val);
int get() const { return value; }
void set(int val) { value = val; }
private:
int value;
};
#endif
Main:
#include <iostream>
#include "class1.hpp"
int main()
{
Class1 *A = new Class1;
Class2 *B = new Class2;
A->setOther(B,15);
A->set(A->getOther(B));
std::cout << "A: " << B->getOther(A) << " B: " << A->getOther(B) << std::endl;
delete A;
delete B;
}
This is a simple example and not necessarily meant to depend on each other. However, in order to get this code to compile, we have to move class1.hpp
from class2.hpp
, to class2.cpp
. And then to get around it, we create a forward declaration of Class1
in Class2
. This get's rid of the cyclic dependency as the two headers do not clash, and Class1
and Class2
will now know about each other safely.
When I program, I consider both the header and source file as one entire object. Or rather that source file is just an extension of the header file and expands all of the definitions of the header file. What I would do in this case, is create a driver class that know's about both Class1
and Class2
and controls them.
How is this implementation avoiding the cyclic dependencies? And how does the compiler compile this and not catch any possible cyclic dependencies? And lastly, when is it necessary to use forward declarations in this manner?