I have a problem in C++ that involves circular dependencies and inheritance.
I have implemented the design in parts and I will use pesudocode to ilustrate where the problem happens.
The first part is:
//app.h
include rel.h
class Rel; // forward declaration
class App {
shared_ptr<Rel> //member variable
}
//rel.h
include app.h
class App; //forward declaration
class Rel {
shared_ptr<App> //member variable
}
Until here, the program compiles without warnings
Then, I want to add inheritance as follows:
//app.h
include rel.h
include drel.h
class Rel; // forward declaration
class DRel // forward declaration
class App {
shared_ptr<Rel> //member variable
shared_ptr<DRel> //member variable
}
//rel.h (the same as before)
include app.h
class App; //forward declaration
class Rel {
shared_ptr<App> //member variable
}
//drel.h
include app.h
include rel.h
class App; //forward declaration
class DRel: Rel { // compile error here: expected class name before { token
shared_ptr<App> //member variable
}
As you see, the compiler throws "expected class name before { token" which means that Rel is not resolved, but why the first code without inheritance works and the second one doesn't? How can I fix that? Is that a "wrong" pattern?
I am using c++14
I know there are a lot of questions regarding the issues I am having, but I can't find the answer to my specific problem. Maybe I don't see it...
Since all the variables you declare do not need to know the space occupied by App, Rel and DRel, you don't even need to #include the headers in question, you just have to forward declare the name as you do.
So you have you .h with
class A;
class B;
class C {
std::shared_ptr<A> ptra;
std::shared_ptr<B> ptrb;
};
And then your .cpp with
#include "A"
#include "B"
C::C() { ... }
The original headers files needed to be guarded by #ifdefs like this:
#ifndef CYCLIC_DEPENDECY_1
#define CYCLIC_DEPENDECY_1
#include "cyclic_dependency2.h"
class Rel; // forward declaration
class App {
std::shared_ptr<Rel> test; //member variable
};
#endif
#ifndef CYCLIC_DEPENDECY_2
#define CYCLIC_DEPENDECY_2
#include "cyclic_dependency1.h"
class App; //forward declaration
class Rel {
std::shared_ptr<App> test;//member variable
};
#endif
#include <iostream>
#include <memory>
#include "cyclic_dependency2.h"
class Rel; // forward declaration
class DRel; // forward declaration
class DRel: Rel {
std::shared_ptr<App> test ;//member variable
};
main()
{
}
Related
Is it not possible to include the baseclass header and have it include all of its subclasses through it?
I seem to have come to an circular dependency with my base class and its subclasses.
From the program entry, I need to initialize one of the subclasses based on user input. I thought I could include the header of the base class which includes the headers of the subclasses:
main.cpp
#include "baseclass.h"
int main()
{
...
}
baseclass.h
#include "sub1.h"
class Base
{
public:
int name;
};
sub1.h
#include "baseclass.h"
class Base; // forward declaration
class Sub : public Base
{
public:
int age;
};
So the dependency is:
main -> baseclass -> sub1 -> baseclass -> sub1 -> etc...
If I keep the forward declaration in, g++ -std=c++11 -o prog *.cpp throws:
error: invalid use of incomplete type 'class Base'
Removing:
error: expected class-name before '{' token {
Not sure how to resolve this without putting a middle "factory" that includes all the subclass headers which each include the baseclass header.
Remove the #include "sub1.h" from baseclass.h, and create a separate header file, which includes all the derived classes you need, and include this header file into main.cpp.
Note: this line class Base; // forward declaration is not needed.
Remove #include "sub1.h" from base.h (also the class Base forward declaration). Where you wan't to use sub include sub1.h, in this case in the main. If you are actually building a bunch of sub type child classes then in all likelihood you will implement something to create them correctly anyway. That something would probably be a factory. It will look something like this:
// ClassFactory.h
#include "sub1.h"
#include "sub2.h"
...
#include "subN.h"
std::unique_ptr<Base> createClass(std::string name) {
if (name == "sub1")
return std::unique_ptr<Base>(new sub1());
if (name == "sub2")
return std::unique_ptr<Base>(new sub1());
...
return nullptr;
}
And your main will include and use this file:
#include "ClassFactory.h"
int main(int argc, char** argv)
{
...
std::unique_ptr<Base> myClass = createClass(argv[1])
Big note: All pseudo code.
Then you will have solved the problem of creating a complex set of child classes at runtime and your problem of how to include all of them.
If you want base.h to include sub1.h, that is possible only after the definition of class Base :
#ifndef BASE_H_
#define BASE_H_
class Base
{
public:
int name;
};
#include "sub1.h"
#endif
It's obvious that this removes the need for a forward declaration of Base; at the point of inclusion it's fully defined.
I've a question about something what really confuses me!
Let's watch this code righ here:
#ifndef HEADER_H
#define HEADER_H
#include <iostream>
class example;
class anything_else;
class A {
public:
A();
};
...
What does class example; and class anything_else; mean,
while class A {}; gets declared? Inside the CPP File i saw definitions like void example::release() { ... } and so on...
I'm really confused, does anyone have a example with class example; ... ?
What does class example; and class anything_else; mean
They are declarations of the classes example and anything_else. They tell the compiler that those are valid class names. This kind of declaration is informally referred to as "forward declaration".
while class A {}; gets declared?
class A gets defined.
Inside the CPP File i saw definitions like void example::release() { ... } and so on...
That's the definition of the function example::release.
Somewhere in the definition of example, there's the declaration of the function:
class example
{
// ...
void release(); // declaration
};
If example is only declared and not defined, then the definition of example::release results in a compilation error.
if you want to have member variables of a type that have not yet been included you do a forward declaration of the type.
class X;
forward declares the class X so you can have a. e.g. a pointer to that class in our class declaration.
class Y
{
...
X* p;
};
later you must supply the definition of the class somewhere in your .cpp file.
If I'm creating a static library with a header file such as this:
// Myfile.h
#include "SomeHeaderFile.h" // External library
Class MyClass
{
// My code
};
Within my own project I can tell the compiler (in my case, Visual Studio) where to look for SomeHeaderFile.h. However, I don't want my users to be concerned with this - they should be able to include my header without having to inform their compiler about the location of SomeHeaderFile.h.
How is this type of situation normally handled?
This is a classic "compilation firewall" scenario. There are two simple solutions to do:
Forward-declare any classes or functions that you need from the external library. And then include the external library's header file only within your cpp file (when you actually need to use the classes or functions that you forward-declared in your header).
Use the PImpl idiom (or Cheshire Cat) where you forward-declare an "implementation" class that you declare and define only privately (in the cpp file). You use that private class to put all the external-library-dependent code to avoid having any traces of it in your public class (the one declared in your header file).
Here is an example using the first option:
#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H
class some_external_class; // forward-declare external dependency.
class my_class {
public:
// ...
void someFunction(some_external_class& aRef); // declare members using the forward-declared incomplete type.
};
#endif
// in the cpp file:
#include "my_header.h"
#include "some_external_header.h"
void my_class::someFunction(some_external_class& aRef) {
// here, you can use all that you want from some_external_class.
};
Here is an example of option 2:
#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H
class my_class_impl; // forward-declare private "implementation" class.
class my_class {
private:
std::unique_ptr<my_class_impl> pimpl; // a vanishing facade...
public:
// ...
};
#endif
// in the cpp file:
#include "my_header.h"
#include "some_external_header.h"
class my_class_impl {
private:
some_external_class obj;
// ...
public:
// some functions ...
};
my_class::my_class() : pimpl(new my_class_impl()) { };
Say the external header file contains the following:
external.h
class foo
{
public:
foo();
};
And in your library you use foo:
myheader.h:
#include "external.h"
class bar
{
...
private:
foo* _x;
};
To get your code to compile, all you have to do is to forward declare the foo class (after that you can remove the include):
class foo;
class bar
{
...
private:
foo* _x;
};
You would then have to include external.h in your source file.
Here is basically what my class layout is:
GameDriver.h:
#ifndef GAMEDRIVER_H
#define GAMEDRIVER_H
#include "CameraSystem.h"
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
#endif
CameraSystem.h:
#ifndef CAMERASYSTEM_H
#define CAMERASYSTEM_H
#include "Tickable.h"
class GameDriver;
class CameraSystem: public Tickable { //Complains here
//Stuff
};
#endif
Tickable.h:
#ifndef TICKABLE_H
#define TICKABLE_H
#include "GameDriver.h"
class GameDriver;
class Tickable {
//Stuff
};
#endif
Here is the error I get:
CameraSystem.h:9 error: expected class-name before '{' token
Forward declaring Tickable does not work either. Any help? Thanks in advance.
If you forward delcare a class you shouldn't include the class' header.
#include "CameraSystem.h" // DO NOT INCLUDE THIS
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
Ok, I see two problems here.
First: Your forward declarations are useless. You are writing (using GameDriver.h: as an example):
#include "CameraSystem.h"
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
Here CameraSystem will already be known by including CameraSystem.h, so the forward declaration is nonsense. What you meant to write was:
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
Second: Where you really would need a forward declaration you cannot use it, as you cannot derive from a forward declared class:
#include "Tickable.h"
class CameraSystem: public Tickable { //Complains here
//Stuff
};
Note that a forward declaration works only if you are not using the forward declared class directly as a class member. You are then restricted to pointers or references to the forward declared class. The reason for this is, that the compiler does not know the memory layout of the class unless its completely known (i.e. by including the header file). For example:
class CameraSystem;
class GameDriver {
CameraSystem m_cameraSystem;
};
will NOT work. However,
class CameraSystem;
class GameDriver {
CameraSystem *m_cameraSystem;
CameraSystem& m_otherCameraSystem;
};
will. Of course you will still have to include the correct header files in your *.cpp file.
You can't resolve such circular dependencies. However, you've got the solution (partially):
I.e. instead of including a header, just use a forward declaration. If you do this right, there shouldn't be any issues. However, try to group your program into logical elements/groups and only add cross-references if they're requied (e.g. the game has to know about and access the camera, but the camera shouldn't have to access the game system as a whole).
You can't inherit from a class that has not been declared.
Pre-processing Tickable.h gives you:
class GameDriver;
class CameraSystem: public Tickable { //Complains here
//Stuff
};
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
class GameDriver;
class Tickable {
//Stuff
};
See how Tickable hasn't even been forward declared when you inherit from it?
Try adding #pragma once at the very beginning of each header file.
You should somehow tell the compiler to only put those once. That's one way. Another is using #ifndef X and #define X.
If this doesn't solve it, try to just eliminate the circular dependency - it doesn't seem like it has to happen...
I have the following code:
Master.h
#ifndef MASTER_H
#define MASTER_H
class Master
{
friend class Friend;
public:
Master(void);
~Master(void);
void CallFriendFunction(int largeData);
private:
int largeData;
//Want this class to share largeData;
Friend testFriend;
};
#endif // MASTER_H
Master.cpp
#include "Master.h"
Master::Master(void)
{
//Inentionally left blank
}
Master::~Master(void)
{
//Intentionally left blank
}
void Master::CallFriendFunction(int largeData)
{
this->largeData = largeData;
this->testFriend.Test(this);
}
Friend.h
#ifndef FRIEND_H
#define FRIEND_H
#include "Master.h"
class Friend
{
public:
Friend(void);
~Friend(void);
void Test(Master* masterPtr);
};
#endif // FRIEND_H
Friend.cpp
#include "Friend.h"
#include <iostream>
Friend::Friend(void)
{
//Intentionally left blank
}
Friend::~Friend(void)
{
//Intentionally left blank
}
void Friend::Test(Master* masterPtr)
{
std::cout << masterPtr->largeData << std::endl;
}
I want class Friend to be able to share Master's private members. However, I can't get this code to compile. I've tried Forward Declaration, and #includes, but I start getting into circular dependencies. When Friend class is not a member of Master class, the code compiles?
Is it possible for Friend class be a member of Master and be friends?
How else can Friend class have access to Masters private members?
You need the following includes and forward declarations:
In Master.h:
#include "Friend.h"
In Friend.h:
class Master;
In Friend.cpp:
#include "Master.h"
Putting the forward declaration in Friend.h prevents circular dependency. A forward declaration is enough there because you only declare a Master* parameter, without using its members yet.
You do need to include Friend.h from Master.h because you are declaring a Friend member, and this requires a complete type.
It looks like you're struggling with circular dependencies. Note that, to make something a friend you do not need to include it. That said, in your Master class, you instantiate friend which requires its inclusion as a header (otherwise the compiler will be all WTF?).
However, in friend.h you can simply forward-declare the master class and not directly include it:
class Master;
This is because you are not attempting to instantiate the Master class, but use a pointer to it.