Template circular dependency - seperate classes in different files - c++

first of all, I want to say that I am aware that this kind of question has been asked before (e.g. here Resolving a Circular Dependency between Template Classes).
However, this solution (Separating the declaration from the implementation) only works when putting both classes into one file. In my case, I have a StateManager and a State class both of which are fairly large and guaranteed to grow. Thus having them in one big file seems unsatisfactory to mine.
Here some important code snippets:
// Forward declare the StateManager --> does not work (incomplete type)
class State
{
public:
template <class TData>
void RequestStackPush(ID stateId, std::shared_ptr<TData> data);
private:
StateManager & stataManager;
}
Here the implementation of the RequestStackPush() method
template<class TData>
inline void State::RequestStackPush(ID stateId, std::shared_ptr<TData> data)
{
// Uses the state manager's PushState() method - here the issue with the incomplete type arises
stateManager.PushState<TData>(stateId, data);
}
Obviously, the StateManager uses the State class all the time. It creates it calls methods etc. so forward declaration is no solution here. Just to give You an example:
template<class TData>
inline void StateManager::PushState(State::ID stateId, std::shared_ptr<TData> data)
{
std::unique_ptr<BasePendingChange> pendingChange = std::make_unique<PendingPushDataChange<TData>>(Push, stateId, data);
pendingChangeQueue.push(std::move(pendingChange));
}
Currently, both classes are in one big file. First, the declaration of the State class with the StateManager being forward declared followed by the declaration of the StateManager class followed by the implementation of the above described State::RequestStackPush() method and finally the implementation of all the StateManager template methods.
How can I separate this into two different files?

However, this solution (Separating the declaration from the implementation) only works when putting both classes into one file.
No, it doesn't only work in one file. You can always construct an identical file by including sub-headers. It just requires you to do something that would be unusual with non-templates (although same technique works with all inline function definitions): You need to include a file after defining the class. Headers are not limited to being at the top of the file despite the name given to them.
So, in one file:
Declare StateManager
Define State
Include definition of StateManager
Define member functions that depend on definition of StateManager
Nothing unusual in the other file:
Include definition of State
Define StateManager and its member functions.
The end result is that including either header produces the same definitions and declarations in the required order. So, this splitting of files does in no way help with limiting the amount of re-compilation caused by modifying one of the headers.
It may be a matter of taste, but I always include definitions required by inline functions (including members of templates and template functions) after the definition of the class. That way I don't need to worry whether doing so is necessary.

Related

C++ Two Classes Template Methods Reference (Not Compose) Each Other

I've gotten into a bit of a design block in a C++ program of mine as two different header files are required to reference each other. Typically a forward declaration would be used here, but since both classes use template functions/constructors a forward declaration cannot be used as methods/variables from both classes need to be used.
For example consider the following scenario (this is pseudo code as an example, it may/may not compile. The objects are representative of my actual application so if a redesign is necessary then I'd love to understand the design philosophies of what I did wrong)
// Application.hpp
#include <Assets.hpp>
#include <Logger.hpp>
class Application {
public:
// Some brilliant code here ...
Logger myLogger;
template <int someArrayLen> Application(std::array<int, someArrayLen> myArr, SomeOtherTypes someOtherStuff) : myLogger(stuffHere) {
mainAssets = new Assets(myArr);
}
~Application(); // Assume this is implemented in Application.cpp and has delete mainAssets;
};
extern Application* mainApp; // Assume Application* mainApp = nullptr; in Application.cpp
// Assets.hpp
// #include <Application.hpp> ???? The issue lies here
class Assets {
private:
// Random data structures/stuff for holding shaders/textures/etc
protected:
template <int someArrayLen> Assets(std::array<int, someArrayLen> myArr) {
if (!shadersSupported()) {
// Main app is an unknown symbol
mainApp->myLogger->error("Your GPU is too old/whatever!");
}
// Random code for loading assets based on my template stuff
}
friend class Application;
public:
// Get assets/whatever here
};
extern Assets* mainAssets; // Assume Assets* mainAssets = nullptr; in Assets.cpp
How can I fix the compile error regarding mainApp being an unknown symbol? Any feedback/help is appreciated, thanks!
I've already looked through all the following questions but none address this unique scenario:
two classes referencing each other
This question had no use of templates so forward declarations could be used as the method bodies weren't defined in the headers
Two classes referencing each other with hash template specialization
The solution from this question cannot be used as here the compiler was unable to figure out how much memory to allocate, whereas in my question the issue isn't regarding the compiler being confused with how much to allocate but rather what to reference
Two template classes being composed of a member of each other
This question addressed a design flaw of circular dependencies which my application does not have, both classes are stored globally, they are just instantiated in separate constructors which reference each other.
Two classes that refer to each other
This question provides forward declarations as a solution which cannot be used here due to the requirement for using the class methods/constructors in template function definitions.
I've also already considered the following:
Trying to change from std::array to pointers, this wouldn't work as my Assets constructor does rely on the lengths of the array.
Trying to change from std::array to std::vector, I want to stick to aggregate initialization so it can be done at compile time, I believe vectors/lists would be too heavy for this.
Forward declarations will indeed work for your problem. The key is that function templates can be defined out of line (i.e., not in your class ... { }; declaration) legally. The same can be achieved for arbitrary functions using the inline keyword.
To now solve your specific problem, just split Application.hpp into Applicaton_fwd.hpp and Application.hpp - similar to iosfwd. Application_fwd.hpp contains almost all the code and Application.hpp includes Application_fwd.hpp and Assets.hpp before defining the Application::Application function template (just like you would define a function in a *.cpp file).
In Assets.hpp, you can simply use Application_fwd.hpp as long as you do not use the constructor. If you also use the Application constructor in Assets.hpp, things become a bit more complicated in that you need to very carefully consider all possible inclusion scenarios (i.e., what happens exactly every time one of your headers is included by themselves or a user) to make sure that it resolves in the order that you need it to without the guards causing trouble.
You can see it in action here

What are the risks to massively forward declaration classes in header files?

For every pointer p1 of class class1, are there any risks we should consider by using a forward declaration of class1 instead of including class1 header file?
I can see only the advantage: The header file will have less size.
Forward declarations outside the control of the provider of the class are problematic! I’m working on a code base where a lot of forward declarations are used. While things are initially great the existence of forward declarations become a legacy:
Classes can’t be moved from one namespace to a different one. Without the forward declarations the name in the original namespace could be made an alias (typedef or using alias).
Classes can’t be turned into specialisations of class templates as is, e.g., useful when generalising a successful class.
Class templates cannot be forward declared by users as only the first declaration of a class template can provide default arguments.
Assuming the forward declarations are provided via a header under the control of the class provider/implementer (e.g., the implemented providing something akin to <iosfwd>) these problems are not relevant as there is a central place where the declarations can be changed. However, having users decide to declare entities becomes a legacy causing significant cost.
The approach to provision of declarations outlined above seems to have caused some confusion. I'll try to clarify. In my mind the unit of implementation is a component (which is based on John Lakos's notation of a component). A component defines one or more closely related classes and/or functions. The implementation of a component consists of multiple files:
A header file declaring all relevant entities which also defines entities which must be defined when using the component, i.e., user-accessible classes, enumerations, etc. are defined.
A header file only declaring relevant entities provided by the component (multiple related components may share one such header file; <iosfwd> is an example of such a header shared across multiple components).
An implementation file defining all entities [which are meant to be ODR-used] which are only declared in by the headers above.
At least one file with a test driver testing all entities defined by the component.
Users of a component which in some contexts only need to know about names in the component would include the declaration-only header. In no case would a user provide a declaration of a name in a component: all declaration of a name in a component are the responsibility of the provider/implementer of the component.
I can see only the advantage: The header file will have less size.
That's not exactly the point.
Let's assume you have a class declaration in a header file like
namespace MyNamespace {
class Baz;
}
class Foo {
public:
void bar(const MyNamespace::Baz & x);
};
and the definition in a separate translation unit as
#include "Baz.hpp"
void Foo::bar(const MyNamespace::Baz & x) {
// actually do something with Baz
}
and in contrast having everything included in the header file (and necessarily all dependent sources will be recompiled when Baz.hpp will be changed)
#include "Baz.hpp"
class Foo {
public:
void bar(const MyNamespace::Baz & x);
};
with the declaration, the 1st version might help to compile the code a little bit faster.
Especially if you have your own headers and class declarations, and if any of these are likely to be changed, you only want to recompile your translation units in the codebase, and not every source file that includes your type dependent header.
Note that forward declarations can be only used with references and pointers. Also header inlined code which dereferences to the forwarded type members cannot be used.

Why do we use #includes if forward declarations seem to be superior?

I've recently run into the idea of forward declarations within C++. I have read that by using forward declarations, compile times can be quickened by avoiding unnecessary declarations and recursive #includes. However, this has got me wondering, why exactly does anyone use #includes then?
Are there situations where plain forward declarations just aren't reasonable? Such as if you have a library header file, it would just make more sense to have a single #include then naming each class/function prototype?
I've read many posts on stack overflow explaining the differences between each path, but why exactly use #includes?
The main reason for including headers, rather than using forward declarations throughout your code, is enforcing consistency with minimal duplication.
Consider a header used in several cpp files. When a class or a variable changes in the header, you would need to find and change all references in all files. Otherwise, the code would continue compiling, but it would fail to link.
In addition, forward declarations have their limits: they let you declare pointer to classes or call functions, but they do not allow creating instances or accessing their members.
It is simply that forward declarations you have in mind cannot replace declarations in headers.
One obvious example is the declaration of class:
Assuming I have a Foo class and is going to contains Bar:
This will work
// FOO.H
class Bar;
class Foo {
private:
Bar* bar;
};
But this won't:
// FOO.H
class Bar;
class Foo {
private:
Bar bar;
};
There is a lot of cases that compiler needs to know the "full" declaration (which we usually put in headers) in order to do its work, instead of just a forward declaration containing the name of class etc (which allow you to mostly create pointer/reference to such class).

multiple definitions error in c++ and solution to solve this issue

I am new to C++. I have some doubts regarding multiple definitions error in C++.
Let's say I have 3 files in a program. One header file and 2 .cpp files. I have included the header file in both the .cpp files.
I have declared a class in the header file and I have defined the class in each of the .cpp files in exactly the same way. So will this type of implementation cause multiple definitions error? If so, is it because it has two copies of class definitions and the compiler doesn't know which one to take during linkage of two .o files?
Can we solve this problem by using extern in header file and defining the class in only one of the files?If we can solve the issue by using this method,do we have to include the .cpp(with class definition) into other .cpp file(with no class definition)?
I have declared and defined a class in header file. Is this case the same as above (mentioned in 1)?
I have declared a class in the header file and I have defined the class in each of the .cpp files but the definitions (function bodies)differs. So will this type of implementation causes multiple definitions error? If so, how can we solve this problem where the functions bodies differs in the .cpp files?
1) You solve this by 'defining the class' in only one cpp file. Why would you want to define it in two files?
2) Don't define things in header files, only declare them. There are exceptions to this rule, for instance inline functions. Also classes themselves can defined more than once (by this I mean declaring the methods and data members of the class, (i.e. writing class XYZ { ... };) but each definition must be identical. The simplest way to achieve this is to define a class once in a header file. Then each definition resulting from including that header file in multiple places will necessarily be identical.
3) This one is even sillier, it's one thing to define somethiing twice, but define it twice and differently each time makes even less sense.
I guess the issue is why you think it might sometimes be necessary to define things more than once. Don't do that.
You should also make it clear what you mean by 'define the class'. I've taken that to mean define the methods and static members of the class. But if you have something else in mind that might be a source of confusion. As usual the best way to avoid this kind of terminology confusion is to post some code.
To answer all of these questions, you only need to look at the purpose of declarations and definitions.
Declarations of a class simply state that the class exists and in which context. For a class, a simple forward declaration (e.g. class Banana;) allows you to use pointers or references to that class, but that's it.
Definitions state exactly what the class is. That is, which members it has and from what base classes it is derived. You need this available whenever you access members of the class, or need to know the size of its instances. This means the class definition needs to be put in a header file, so that it can be included wherever in all files which use the class. This is OK, because the standard says that a class can be defined in multiple translation units, as long as all definitions are identical.
A class definition typically looks something like this:
class Banana
{
public:
Banana(){}
void eat();
private:
//....
};
However, please note that this class definition only means the definition of the class itself, not the non-inline member functions. Such as void eat() in the above example. These need to be defined in the .cpp file, because they may not be defined in multiple translation units.
So in short:
This is not right, only define it in the header file and define non-inline member functions in the matching .cpp file. You should never define the same function or type in more than one file.
This is OK, as long as you define the member functions separately in the .cpp file.
No, see 1.
1) You can't have two definitions of the same class in your project. And I have no idea how you plan to use it. If you want to make instances of one class with different behavior, use virtual function like:
class A {
public:
virtual int foo() = 0;
}
class B : public A {
public:
virtual int foo() { return 1; }
}
class C : public A {
public:
virtual int foo() { return 2; }
}
2) You may define class in header file (java-style), but it's not the best idea because compiler will consume more resources to build other files, include this header. Let compiler work fast - define classes in .cpp files.
3) See p.1
There's no problem with defining a class in several places. That's exactly what happens when you put the definition in a header and #include that header in more than one source file. However, note that defining a class means writing out what the class contains, not defining its members. This is a class definition:
class C {
void f(); // member function declaration
void g() { } // member function declaration with inline definition
int i; // member declaration
static int j; // member declaration
};
like most things, you can't define it more than once in a single source file. However, it can appear in as many source files as you like, provided only that it's the same everywhere.
This class definition declares two members that must be defined somewhere, typically like this:
void C::f() {
std::cout << "In C::f\n";
}
int C::j = 3;
These definitions can appear only once in the entire program; usually each is defined once in a source file.

Member function definition

What is the right approach to take:
Define the member (class) function inside the class?
Define the member (class) function outside the class?
Thanks.
Assuming you're talking about these three possibilities:
Method defined in class definition in header file.
Method define outside class definition in header file.
Method define outside class definition in implementation file.
Then project and company guidelines may force you to use (1) or (3) always.
When you have a choice, it's IMHO best to adapt to circumstances at hand, considering things such as
Do you want a header-only module? Then (1) as default, (2) possible.
Is the method a large beast? Then (2) or (3).
Template method specialization? Then (2) or (3).
There is a build-time problem (slow builds)? Indicates (3).
Template class? (1) or possibly (2)
But except where the choice is effectively forced on you, above all consider the clarity of your code.
Cheers & hth.,
A common advice is to keep headers as simple and clean as possible. Headers will be included by external code, and they will have to process everything that you have written there. If you write a method in the header, all translation units will compile that function, only so that the linker can discard all but one of them later on.
If your code has an internal dependency on a type or library that is not part of your interface, then by inlining the code of the member function in the class declaration the definition of that class or the headers of that library will have to be included in your header, and that means that you are leaking your implementation details to your users.
Unless the member function definition is trivial (in an informal sense) and doesn't introduce any additional dependencies I would normally define a member function outside of the class body in a separate source file.
It's often a matter of style but there are some cases in which it is necessary and many other cases in which it is desirable to define function outside of the class body.
For example, in the cases where you have interdependent classes and only a forward declaration of another class can be made available before the class definition, a member function which uses the definition of that other class can only be defined outside of the class body after a full definition of the other class has been provided.
Do you mean "in the class declaration / .h file" vs "in a .cpp file using ::" ?
If so I always go for the latter. When it comes to debugging, it's a lot easier to step through and see what's going on. It also helps declutter the class declaration, which doesn't need to know any implementation details"
If you want to define a function within a class the most basic syntax looks generally like:
class Object
{
int property;
void doSomething()
{
property=100;
}
};
If you want to define a function outside it is similar to declaring functions before main and in library files. In your class you have:
class Object
{
int property;
void doSomething();
};
Then somewhere after your class, after the main() function or in an included file you can have the definition:
void Object::doSomething()
{
property=100;
}
Some place classes in a header file and the definitions in a cpp file used by that header. Various techniques possible.
Both of these approaches are valid. Often I will include very small and/or core class functionality directly within the class and other functions which do heavier bulk work I tend to separate. Try to think the difference in coming upon your code and wanting to alter it.
if we see according to performance issue than it is more effective way to declare the function in the class . becouse at the compile time it conects all the funcation calls and other components so it will easy and must be faster to get all in one source...