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

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

Related

Template circular dependency - seperate classes in different files

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.

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...

Is it possible to define a class in 2 or more file in C++?

I know it's possible to do class implementation in more than one file(yes, I know that this is bad idea), but I want to know if it's possible to write class definition in separate files without getting a redefinition error (maybe some tricks, or else...)
No, not the same class, but why would you?
You could define two classes with the same name in the same namespace (the same signature! That will actually be the same class at all, just defined in two ways) in two different header files and compile your program, if your source files don't include both headers. Your application could even be linked, but then at runtime things won't work as you expect (it'll be undefined behavior!), unless the classes are identical.
See Charles Bailey's answer for a more formal explanation.
EDIT:
If what you want is to have a single class defined by more than one file, in order to (for example) add some automatically generated functions to your class, you could #include a secondary file in the middle of your class.
/* automatically generated file - autofile.gen.h */
void f1( ) { /* ... */ }
void f2( ) { /* ... */ }
void f3( ) { /* ... */ }
/* ... */
/* your header file with your class to be expanded */
class C
{
/* ... */
#include "autofile.gen.h"
/* ... */
};
Not as nice and clean as the partial keyword in C#, but yes, you can split your class into multiple header files:
class MyClass
{
#include "my_class_aspect1.h"
#include "my_class_aspect2.h"
#include "my_class_aspect3.h"
};
#include "my_class_aspect1.inl"
#include "my_class_aspect2.inl"
#include "my_class_aspect3.inl"
Well sort of ...
If you have 1 header file as follows
ClassDef1.h:
class ClassDef
{
protected:
// blah, etc.
public:
// more blah
and another as follows
ClassDef2.h:
public:
// Yet more blah.
};
The class will effectively have been defined across 2 files.
Beyond that sort of trickery .. AFAIK, no you can't.
Yes, you can. Each definition must occur in a separate translation unit but there are heavy restrictions on multiple definitions.
Each definition must consist of the same sequence of tokens and in each definition corresponding names must refer to the same entity (or an entity within the definition of the class itself).
See 3.2 [basic.def.odr] / 5 of ISO 14882:2003 for full details.
Yes. Usually, people put the declaration part in .h file and then put the function body implementations in .cpp file
Put the declarations in a .h file, then implement in as many files as you want, but include the .h in each.
But, you cannot implement the same thing in more than one file
I know this is a late post, but a friend just asked me a similar question, so I thought I would post our discussion:
From what I understand you want to do ThinkingStiff, it's not possible in C++. I take it you want something like "partial class" in C#.
Keep in mind, "partial class" in .NET is necessary so you don't have to put your entire implementation in one big source file. Unlike C++, .NET does not allow your implementation to be separate from the declaration, therefore the need for "partial class". So, Rafid it's not a nice feature, it's a necessary one, and a reinvention of the wheel IMHO.
If your class definition is so large you need to split it across more than one source file, then it can probably be split into smaller, decoupled classes and the primary class can use the mediator design pattern that ties them all together.
If your desire is to hide private members, such as when developing a commercial library and you don't wish to give away intelectual property (or hints to that affect), then you can use pure abstract classes. This way, all that is in the header is simple class with all the public definitions (API) and a factory function for creating an instance of it. All the implementation details are in your source file(s).
Another alternative is similar to the above, but uses a normal class (not a pure virtual one), but still exposes only the public interface. In your source file(s), you do all the work inside a nameless namespace, which can include friend functions from your class definition when necessary, etc. A bit more work, but a reasonable technique.
I bolded those things you might want to lookup and consider when solving your problem.
This is one of the nice features of C#, but unfortunately it is not supported in C++.
Perhaps something like policy based design would do the trick? Multiple Inheritience gives you the possiblity to compose classes in ways you can't in other languages. of course there are gotchas associated with MI so make sure you know what you are doing.
The short answer is yes, it is possible. The correct answer is no, you should never even think about doing it (and you will be flogged by other programmers should you disregard that directive).
You can split the definitions of the member functions into other translation units, but not of the class itself. To do that, you'd need to do preprocessor trickery.
// header file with function declarations
class C {
public:
void f(int foo, int bar);
int g();
};
// this goes into a seperate file
void C::f(int foo, int bar) {
// code ...
}
// this in yet another
void C::g() {
// code ...
}
There must be a reason why you want to split between two headers, so my guess is that you really want 2 classes that are joined together to form components of a single (3rd) class.

Forward declaration in multiple source directory; template instantation

I am looking for a nice book, reference material which deals with forward declaration of classes esp. when sources are in multiple directories, eg. class A in dirA is forward declared in class B in dirB ? How is this done ?
Also, any material for template issues, advanced uses and instantation problems, highly appreicated ?
Thanks.
Forward declarations have nothing to do with the directory structure of your project. You can forward declare something even not existing in your project. They are mostly used to resolve cyclic references between classes and to speed up compilation when the complete class declaration is not necessary, and the corresponding #include can be replaced with a forward declaration.
To determine when a forward declaration is sufficient, the sizeof() query can usually answer the question. For example,
class Wheel;
class Car
{
Wheel wheels[4];
};
In this declaration, a forward declaration cannot be used since the compiler cannot determine the size of a Car: it doesn't know how much data the wheels contain. In other words, sizeof(Car) is unknown.
Also regarding templates, forward declared classes cannot be used as template parameters if the template class contains data members of the template parameter (but their pointers can be). For instance,
template<class T> class pointer
{
T *ptr;
};
class Test;
pointer<Test> testpointer;
is legal but
std::vector<Test> testvector will not compile.
Because of the aforementioned limitations, forward declared classes are generally used as pointers or references.
I don't know if there's a book on the subject but you can see this section on c++ faq lite.
Generally speaking you can forward declare in headers as a means of avoiding full includes or as a way to enable circular referencing (bad).
You can use a forward declared type by pointer or reference or return type only.
Large-Scale C++ Software Design by John Lakos (book review here) addresses physical design (files) and logical design and how they relate to software components (which aren't always 1:1 with classes).
if they are in parallel directories you can include it like
#include "../dirB/B.h"
but in header you just call this line for forward decleration
class B;
instead of this, you can seperate your include directories and source directories.
so then you can show include directory as this directory and you can add header by calling
#include "dirB/B.h"
since you will make a forward decleration on header, it wont be problem.

Forward declare pointers-to-structs in C++

I am using a 3rd party library that has a declaration like this:
typedef struct {} __INTERNAL_DATA, *HandleType;
And I'd like to create a class that takes a HandleType in the constructor:
class Foo
{
Foo(HandleType h);
}
without including the header that defines HandleType. Normally, I'd just forward-declare such a type, but I can't figure out the syntax for this. I really want to say something like:
struct *HandleType;
But that says "Expected identifier before *" in GCC. The only solution I can see is to write my class like this:
struct __INTERNAL_DATA;
class Foo
{
Foo(__INTERNAL_DATA *h);
}
But this relies on internal details of the library. That is to say, it uses the name __INTERNAL_DATA, which is an implementation detail.
It seems like it should be possible to forward-declare HandleType (part of the public API) without using __INTERNAL_DATA (part of the implementation of the library.) Anyone know how?
EDIT: Added more detail about what I'm looking for.
Update:
I am using it in the implementation .cpp of Foo, but I want to avoid including it in my header .h for Foo. Maybe I'm just being too pedantic? :)
Yes you are :) Go ahead with forward declaration.
If HandleType is part of the interface there must be a header declaring that. Use that header.
Your problem is still a vague one. You are trying to protect against something you cannot.
You can add the following line to your client library:
typedef struct INTERNAL_DATA *HandleType;
but, if the name/structure changes you may be in for some casting nastiness.
Try templates:
template <class T>
class Foo
{
Foo(T h);
};
Forward declaration is fine. If you are going to use pointers or references you only need a class (__INTERNAL_DATA) declaration in scope. However, if you are going to use a member function or an object you will need to include the header.
If the type is in a 3rd party library then the big benefit of forward declaration (isolating rebuilds due to changes in headers) is effectively lost.
If you're worried about compilation times (it's a sizeable header) then perhaps you can place it in a precompiled header or just include the relevant header from a library.
E.g. many library headers look like
// library.h
#include "Library/Something.h"
#include "Library/SomethingElse.h"
typedef struct {} __INTERNAL_DATA, *HandleType;
If it is defined like that (all on one line), then __INTERNAL DATA is as much a part of the public interface as HandleType.
However, I don't think __INTERNAL_DATA actually exists. More than likely, HandleType is really (internally) an int. This odd definition is just a way of defining it so that it's the same size as an int, but distinct, so that the compiler give you an error if you try passing an int where you're supposed to pass an HandleType. The library vendor could just as easily have defined it as "int" or "void*", but this way we get some type checking.
Hence __INTERNAL_DATA is just a convention and is not going to change.
UPDATE: The above was a bit of a mental burp... OK, __INTERNAL_DATA definitely does not exist. We know this for a fact, because we can see it's definition as an empty struct. I'm going to guess that the 3rd-party library uses "C" external linkage (no name managling), in which case, just copy the typedef -- it will be fine.
Inside the library itself, HandleType will have a completely different definition; maybe int, maybe "struct MyStruct {.......} *".
If you really, really, really don't want to expose _INTERNAL_DATA to the caller then your only real choice is to use typedef void* HandleType; Then inside your library you can do anything you want including changing the entire implementation of *HandleType.
Just create a helper function to access you real data.
inline _INTERNAL_DATA* Impl(HandleType h) {
return static_cast<_INTERNAL_DATA*>(h);
}
I'm not quite sure what you're going for, but the following will work without including the actual header file:
// foo.h
class Foo
{
public:
template<typename T>Foo(T* h) { /* body of constructor */ }
};
Mind you, you will still have to have access the public members of __INTERNAL_DATA within the body of the constructor.
edit: as pointed out by James Curran, the __INTERNAL_DATA structure has no members, so it can be used, as above, with no problems.