I solved a circular dependency. Are there problems with the solution? - c++

I solved a circular dependency. It has been compiled by g++. Already existing solutions on the site don't include include in headers and just add class ...;. So, I want to know, are there any problems with the solution?
classA.h
#ifndef CLASS_A_H
#define CLASS_A_H
class ClassB;
class ClassA {
public:
ClassB* b;
int get5();
};
#include "classB.h"
#endif
classB.h
#ifndef CLASS_B_H
#define CLASS_B_H
class ClassA;
class ClassB {
public:
ClassA* a;
int get7();
};
#include "classA.h"
#endif
classA.cpp
#include "classA.h"
int ClassA::get5() {
return 5;
}
classB.cpp
#include "classB.h"
int ClassB::get7() {
return 7;
}
main.cpp
#include <iostream>
#include "classA.h"
int main() {
ClassA a;
std::cout << a.get5() << std::endl;
ClassB b;
std::cout << b.get7() << std::endl;
return 0;
}

are there any problems with the solution?
Defining B in the header classA.h is unnecessary, and vice versa.
This won't break anything, but can cause the translation units that include one of those headers to be recompiled when either of the definitions is changed even when those translation units did not depend on the transitively included definition.
Best practice is to only include headers that are necessary to be included.
Another issue is that in main.cpp, you depend on definition of B without including its definition directly. If you at some point change the definition of A to no longer depend on B in any way, and consequently remove the apparently unnecessary include, then main.cpp will fail to compile because it assumes that B is defined by including classA.h.
It is usually best practice to directly include headers that define dependencies and to not rely on transitive inclusions.

That's an usual solution, except that you have unnecessary includes at the end of each of headers. Remove them, and in main.cpp include both classA.h and classB.h.

Related

Dividing project to .h and .cpp

I wanted to divide my project into smaller parts cause it started to be unreadable(1000+ lines) and i have some problem with specified .h and .cpp that need to use definitons defined in other files.
Project contains following files:
main.cpp
RPG.h and .cpp
Hero.h and .cpp
Globaldefs.h and .cpp
#ifndef Hero_h
#define Hero_h
#include "Globaldefs.h"
#include "RPG.h"
#include <vector>
using namespace std;
extern class NPC;
extern class Inventory;
class Hero
{
protected:
(...)
Inventory inventory;
(...)
public:
vector<Mob*>::iterator TryAttack(vector <Mob*>& monsters, int & number);
vector<NPC*>::iterator TryTalk(vector <NPC*>& _NPCs, int & number);
};
(...)
#endif
declaration above is from Hero.h file and compilator finds error in line Inventory inventory; (that class is outside, declared in RPG.h and defined in RPG.cpp): 'Hero::inventory' uses undefined class 'Inventory' RPG d:\programming\rpg\rpg\rpg\hero.h 23 I completely don't understand why Mob(other class from RPG.h and .cpp) work properly and NPC defined as extern(too in RPG.h) as well.
#ifndef RPG_h
#define RPG_h
#include "Globaldefs.h"
#include "Hero.h"
#include <vector>
using namespace std;
class Mob;
class NPC;
class Fight;
class Item;
extern class Hero;
(...)
class Meat : public Item
{
(...)
public:
virtual void ActivateEffect(Hero* _hero) { _hero->AddHp(15); };
};
#endif
this is RPG.h file, and there, compilator says that something went wrong in line
virtual void ActivateEffect(Hero* _hero) { _hero->AddHp(15); };
there is: use of undefined type 'Hero' RPG d:\programming\rpg\rpg\rpg\rpg.h 97 and left of '->AddHp' must point to class/struct/union/generic type RPG d:\programming\rpg\rpg\rpg\rpg.h 97
i reserched many sites, but everywhere people has problems with simple adding files to main.cpp, not making internal connections beetween files.
Inclusion guards prevent you to include RPG.h in Hero.h and vice-versa.
What you did is to forward declare Hero in RPG.h, which is good.
But then you did:
virtual void ActivateEffect(Hero* _hero) { _hero->AddHp(15); };
and the compiler needs to know the structure of Hero class to link it to AddHp method. You just cannot do that.
Do that instead (just declare the method):
virtual void ActivateEffect(Hero* _hero);
And remove the #include "Hero.h" line.
Then in the RPG.cpp file do:
#include "Hero.h"
void RPG::ActivateEffect(Hero* _hero) { _hero->AddHp(15); }
We don't see the code for the Inventory problem, but I suppose that's the same problem.
To summarize:
you can include file A.h in file B.h but in that case you cannot include file B.h in A.h
but you can forward declare class B in A.h and reference the pointer/reference on that class, as long as you don't try to use B methods in the header file.
to use B methods in A object, just include B.h in A.cpp and have access to all B method in A.cpp. Some inline methods cannot be implemented in the .h file when they use methods/members of B
You have a circular dependency between RPG.h and Hero.h, and RPG.h line 97, only the forward declaration (extern class Hero;) is visible so you can only reference pointers and references to whole Hero objects and cannot reference members of Hero.
The circular dependency may itself indicate poor design in any case.

How do circular dependencies occur in C++?

I've been reading Design Patterns(GOF) and in it it's mentioned that Facade pattern eliminates circular dependencies.
I want to know how do they come in picture in C++?
PS: I am not asking how can I resolve them.
ClassA.h
#ifndef CLASS_A_H
#define CLASS_A_H
#include "ClassB.h" // Contributes To Circular Include
class ClassA {
private:
ClassB* m_pB;
public:
explicit ClassA( ClassB* pB );
}; // ClassA
#endif // CLASS_A_H
ClassA.cpp
#include "ClassA.h"
ClassB.h
#ifndef CLASS_B_H
#define CLASS_B_H
#include "ClassA.h" // Contributes To Circular Include
class ClassB {
public:
ClassB();
void updateA( ClassA* pA );
}; // ClassB
#endif // CLASS_B_H
ClassB.cpp
#include "ClassB.h"
What causes the circular dependencies is when one class includes the header file of another class within its own header file where the other class is also including the previous header file. This can also happen if multiple classes are involved where it may not be apparent but is done through a chain of includes for example:
A.h includes B.h : B.h includes C.h : C.h includes D.h : D.h includes A.h This still creates the circular dependency.
This is why it is advisable to have class prototypes or forward declarations in the header file of the class that depends on them; then to include those dependencies headers within the class's cpp file that requires those dependencies. There may be several cases where you can't not avoid this and that the included header has to be within the class's header, so this is why care needs to be taken towards a good program design.

C++ proper way for solve this inheritence include issue "already has a body"?

Heyo, I have a question about this issue I am having in C++. I am new to C++ and learning. I have experience in object oriented programming so I am looking for the correct way and solve this issue and why it should be done that way.
Classes
I have separated each class into an interface header file and implementation cpp file.
The first class "Alpha" is my base class:
// a.h
#pragma once
class Alpha
{
public:
virtual void myFunction();
};
Alpha Implementation:
// a.cpp
#include <iostream>
#include "a.h"
void Alpha::myFunction()
{
std::cout << "Class Alpha myFunction" << std::endl;
}
I then have a sub class "Beta":
// b.h
#pragma once
#include "a.h"
#include "a.cpp"
class Beta : public Alpha
{
public:
virtual void myFunction();
};
Beta Implementation:
// b.cpp
#include <iostream>
#include "b.h"
void Beta::myFunction()
{
std::cout << "Class Beta myFunction" << std::endl;
}
I then have what will be like a manager class called "Gamma".
// g.h
#pragma once
#include <vector>
#include "a.h"
#include "a.cpp"
class Gamma
{
public:
void run();
std::vector<std::shared_ptr<Alpha>> alphaCollection;
};
Gamma implementation:
// g.cpp
#include "g.h"
#include "b.h"
#include "b.cpp"
void Gamma::run()
{
Beta localBeta;
alphaCollection.push_back(std::make_shared<Beta>(localBeta));
// example usage
alphaCollection.at(0)->myFunction();
}
Then finally my main:
#include "g.h";
#include "g.cpp";
int main()
{
Gamma objectG;
objectG.run();
}
Why I am doing this
The purpose for all of this being that I want a vector of the base class Alpha in my manager where I can then insert elements of a varying number of base class objects.
I used Beta as an example of a derived class but in the real implementation would have more derived classes such as Charlie, Delta etc.
The goal being that my Manager class Gamma will be able to operate on the vector elements as Alpha objects and each of the sub classes perform their own behavior.
The Problem
I cannot compile the above example because of how Gamma's implementation file includes "g.h" and "b.h" each of which include "a.h" and "a.cpp" thus double including "a.cpp" since it has no header guard.
error C2084: function 'void Alpha::myFunction(void)' already has a body a.cpp
error C2264: 'Alpha::myFunction' : error in function definition or declaration; function not called g.cpp
I have read varying opinions on how to use includes and overall I just feel like a noob in understanding the proper way to organize code to prevent his.
Am I very disorganized?
Should implementation files use header guards too?
Should I be using forward declarations? If so how?
Am I crazy to want the implementation to include the sub class includes while the header includes the base class include only?
Seriously any guidance is appreciated!
Do not #include the cpp files. It's not required and that's what is causing the issue.
#pragma once is the same as an include guard - but remember it's not portable - it's specific to your current compiler.
You should not have include guards in your cpp files because you shouldn't #include them.
You only need to include header files, not .cpp files.
You do not want to use header guards in .cpp files.
You don't need forward declaration here (although you could use it instead)
Your implementations are not including "sub class includes", they are including the header files that define their interface. Your include of a.h is correct in g.h.
Stop #including .cpp files. The .h is the most you'll ever need, and sometimes just a forward declaration is enough. Here, here, and here are decent descriptions of what purposes they serve.

Using forward reference

I have a circular header problem that is different from most of the ones already asked on here. I have two classes that depend on each other but not as members so don't run into the problem of the compiler not being able to calculate the class's sizes. So I'm able to use a forward-declaration to break the cycle.
However, I don't want the client to have to include both these headers to use my classes. The headers should be self-contained so the user doesn't need to be aware of this dependency. Is there some way to do this?
Edit: the tricky part is that A and B must be defined header-only.
In header A.hpp
#ifndef A_HPP
#define A_HPP
#include "B.hpp"
struct A
{
B foo() { ... }
};
#endif
In header B.hpp
#ifndef B_HPP
#define B_HPP
struct A;
struct B
{
void bar()
{
A a = A();
...
}
};
#endif
In main.cpp
#include "B.hpp"
B().bar(); // error: 'a' uses undefined class 'A'
Header B.hpp
#ifndef B_HPP
#define B_HPP
struct A;
struct B
{
void bar();
};
#endif
Source B.cpp
#include "A.hpp"
void B::bar()
{
A a;
}
EDIT. So, if you want header-only implementation, then use AndreyT solution.
If both headers contain code that requires the other type to be complete, then in general case it cannot possibly be implemented by self-contained headers.
In your specific example (which is too simple to be representative), you can simply move the definition if B::bar to A.hpp:
inline void B::bar()
{
A a = A();
...
}
But, of course, having methods of B defined in A.hpp doesn't look very elegant.
If the "inlinedness" of B::bar is important to you, the "industrial" solution would involve placing the definition of B::bar into an additional header file B_aux.hpp. When you include the headers, you should include the "aux" ones after all "normal" ones are included, i.e. in main.cpp you'd have
#include "A.hpp"
#include "B.hpp"
#include "C.hpp"
...
#include "B_aux.hpp"
...
But this is, obviously, not a "self-contained" approach.
Just add a #include "A.hpp" to the bottom of B.hpp. You'll still have a circular include, but now it won't hurt anything.
Usually circular includes are a sign that the two types are closely related, and that could mean that they are a single component. If that is the case, then just merge the two headers into a single header for the component, with the type declarations first and the member function definitions at the end, when both types have been fully defined.

Circular dependencies in c++

Say I have these two classes:
// a.h
#include "b.h"
and:
// b.h
include "a.h"
I understand there is a problem over here, but how can I fix it and use a objects and their methods in b class and vice versa?
You can use forward declarations, like this:
class B;
class A
{
B* ThisIsValid;
}
class B
{
A SoIsThis;
}
For more information, see this SO question.
As for the preprocessor #includes, there's likely a better way to organize your code. Without the full story, though, it's hard to say.
To extend on #Borealid 's answer:
To avoid problems with circular includes, using an "include guard"
eg.
#ifndef MYFILE_H /* If this is not defined yet, it must be the first time
we include this file */
#define MYFILE_H // Mark this file as already included
// This only works if the symbol we are defining is unique.
// code goes here
#endif
You can use what is called a "forward declaration".
For a function, this would be something like void myFunction(int);. For a variable, it might look like extern int myVariable;. For a class, class MyClass;. These bodiless statements can be included before the actual code-bearing declarations, and provide the compiler with enough information to produce code making use of the declared types.
To avoid problems with circular includes, using an "include guard" - an #ifdef at the top of each header file which prevents it being included twice.
The "other" class can only have a reference or pointer to the "first" class.
in file a.h:
#include "b.h"
struct a {
b m_b;
};
in file b.h:
struct a;
struct b {
a* m_a;
};
void using_the_a_instance(b& theb);
in file b.cpp:
#include "b.h"
#include "a.h"
void using_the_a_instance(b& theb)
{
theb.m_a = new a();
}