Resolving circular dependencies from inheritance - c++

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.

Related

Cyclic dependency and inheritance compilation error on c++

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()
{
}

C++ Method declaration using another class

I'm starting to learn C++ (coming from Java), so bear with me.
I can't seem to get my method declaration to accept a class I've made.
'Context' has not been declared
I think I'm not understanding a fundamental concept, but I don't know what.
Expression.h
#include "Context.h"
class Expression {
public:
void interpret(Context *); // This line has the error
Expression();
virtual ~Expression();
};
Context.h
#include <stack>
#include <vector>
#include "Expression.h"
class Context {
private:
std::stack<Expression*,std::vector<Expression*> > theStack;
public:
Context();
virtual ~Context();
};
You have to forward declare Expression in Context or vice versa (or both), otherwise you have a cyclic dependency. For example,
Expression.h:
class Context; // no include, we only have Context*.
class Expression {
public:
void interpret(Context *); // This line has the error
Expression();
virtual ~Expression();
};
Context.h:
#include <stack>
#include <vector>
class Expression; // No include, we only have Expression*
class Context {
private:
std::stack<Expression*,std::vector<Expression*> > theStack;
public:
Context();
virtual ~Context();
};
You can perform the forward declarations because the full definition of the classes isn't needed, since you are only referring to pointers to the other class in each case. It is likely that you will need the includes in the implementation files (that is, #include "Context.h" in Expression.cpp and #include Expression.h in Context.cpp).
Finally, remember to put include guards in your header files.
In C++, class definitions always have to end with a semi-colon ;
so example:
class foo {};
Java and C# doesn't require that, so I can see your confusion.
Also it looks like both your header files include each other. Thus it's kind of like a snake eating it's tail: Where does it start? Thus in your Expression.h you can replace the 'include' with a forward declaration instead:
class Context;
class Expression {
public:
void interpret(Context *); // This line has the error
Expression();
virtual ~Expression();
}
And last but not least, you should put a compiler guard to prevent the header from getting included more than once into a .cpp file. You can put a #pragma once in the top of the header file. That is useful if you are using visual studio and the microsoft compiler. I don't know if GCC supports it or not. Or you can wrap your header file like this:
#ifndef EXPRESSION_H_
#define EXPRESSION_H_
class Context;
class Expression {
public:
void interpret(Context *); // This line has the error
Expression();
virtual ~Expression();
}
#endif
you might need to forward declare the classes Context and Expression in the header files before the #include
e.g.
#include <stack>
#include <vector>
// forward declaration
class Context;
class Expression;
#include "Expression.h"
class Context {
private:
std::stack<Expression*,std::vector<Expression*> > theStack;
public:
Context();
virtual ~Context();
}

How to avoid #include dependency to external library

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.

Classes using each other?

I have 2 header files that contain 2 classes. Each class is dependent on other, like so:
// class1.h
#include "class2.h"
class ClassOne {
ClassTwo* c2;
};
// class2.h
#include "class1.h"
class ClassTwo {
ClassOne* c1;
};
I expected the code not to compile, so I added a forward declaration to one of the headers:
// class1.h
#include "class2.h"
class ClassTwo;
class ClassOne {
ClassTwo* c2;
};
But sadly that isn't working, either. I keep getting compiler errors for "use of undefined type 'ClassTwo'".
I know I can just combine them into one header file and they will work, but in reality they are both really big classes and I really would prefer they have their own header file for organization purposes.
Is there a way to get around this?
Thanks,
Alex
You added the forward declaration but didn't remove the include. Do that and you're golden.
Actually, remove both includes, and replace them with forward declarations.
// class1.h
class ClassTwo;
class ClassOne {
ClassTwo* c2;
};
// class2.h
class ClassOne;
class ClassTwo {
ClassOne* c1;
};
Note that cases where circular dependencies are actually required are few and far apart, so at least review the design.

Circular Dependencies / Incomplete Types

In C++, I have a problem with circular dependencies / incomplete types. The situation is as follows:
Stuffcollection.h
#include "Spritesheet.h";
class Stuffcollection {
public:
void myfunc (Spritesheet *spritesheet);
void myfuncTwo ();
};
Stuffcollection.cpp
void Stuffcollection::myfunc(Spritesheet *spritesheet) {
unsigned int myvar = 5 * spritesheet->spritevar;
}
void myfunc2() {
//
}
Spritesheet.h
#include "Stuffcollection.h"
class Spritesheet {
public:
void init();
};
Spritesheet.cpp
void Spritesheet::init() {
Stuffcollection stuffme;
myvar = stuffme.myfuncTwo();
}
If I keep the includes as shown above, I get the compiler error
spritesheet has not been declared in Stuffcollection.h (line 4 in
the above). I understand this to be due to a circular dependency.
Now if I change #include "Spritesheet.h" to the Forward
Declaration class Spritesheet; in Stuffcollection.h, I get the
compiler error invalid use of incomplete type 'struct Spritesheet'
in Stuffcollection.cpp (line 2 in the above).
Similarly, if I change #include "Stuffcollection.h" to class
Stuffcollection; in Spritesheet.h, I get the compiler error aggregate
'Stuffcollection stuffme' has incomplete type and cannot be defined
in Spritesheet.cpp (line 2 in the above).
What can I do to solve this problem?
You should include Spritesheet.h in Stuffcollection.cpp
Just use forward declaration in the header file not the cpp file, that solves the circular dependency of the header file. The source file has no circular dependency actually.
Stuffcollection.cpp needs to know the complete layout of class Spritesheet(because you dereference it), So you need to include the header which defines the class Spritesheet in that file.
From your previous Q here, I believe that class Stuffcollection is used in the class declaration of Spritesheet header file and hence the above proposed solution.
Use this form for your nested includes:
Stuffcollection.h
#ifndef STUFFCOLLECTION_H_GUARD
#define STUFFCOLLECTION_H_GUARD
class Spritesheet;
class Stuffcollection {
public:
void myfunc (Spritesheet *spritesheet);
void myfuncTwo ();
};
#endif
Stuffcollection.cpp
#include "Stuffcollection.h"
#include "Spritesheet.h"
void Stuffcollection::myfunc(Spritesheet *spritesheet) {
unsigned int myvar = 5 * spritesheet->spritevar;
}
void Stuffcollection::myfuncTwo() {
//
}
Spritesheet.h
#ifndef SPRITESHEET_H_GUARD
#define SPRITESHEET_H_GUARD
class Spritesheet {
public:
void init();
};
#endif
Spritesheet.cpp
#include "Stuffcollection.h"
#include "Spritesheet.h"
void Spritesheet::init() {
Stuffcollection stuffme;
myvar = stuffme.myfuncTwo();
}
General rules I follow:
Don't include an include from an include, dude. Prefer forward declarations if possible.
Exception: include system includes anywhere you want
Have CPP include everything it needs, not relying upon H recursively including it files.
Always use include guards.
Never use pragma
Spritesheet.h doesn't need to include Stuffcollection.h, since no Stuffcollection is used in the class declaration of Spritesheet. Move that include line to Spritesheet.cpp instead and you should be fine.