ich habe eine Art Huhn und Ei Problem, daher möchte eine Klasse voraus deklarieren.
Ich wollte wissen wie ich die class MyClass voraus deklarieren kann
so dass die class IUseMyClassAsBase mit der Vererbung dieser keine Probleme hat. Soll ich die Basisklassen bei der voraus Deklarierung immer mit angeben ?
Bsp.
internal stellt ein namespace dar mit den Base Klassen,
meine class MyClass befindet sich aber ausserhalb dieses internal namespaces. class MyClass is eine 'nested class' und befindet sich in der class MainClass
1
namespace internal
2
{
3
...
4
class BaseClass<>...
5
...
6
class BaseClassRef<> ...
7
...
8
} // namespace internal
9
10
class MainClass
11
{
12
13
//forward declaration -> *MACHT DAS SINN* ?
14
template<typename T>
15
class MyClass : public internal::BaseClass<internal::BaseClassRef<T>>;
16
17
class IUseMyClassAsBase : public MyClass<>
18
{
19
...
20
{
21
...
22
template<typename T>
23
class MyClass : public internal::BaseClass<internal::BaseClassRef<T>>
24
{
25
...
26
// here I access IUseMyClassAsBase related functionality
Das dürfte nicht funktionieren. Wenn man von einer Klasse was ableiten will, dann muss die gesamte Klassendefinition dafür verfügbar sein und nicht nur deklariert sein.
Vielleicht erklärst Du uns einfach, welches Problem Du mit dem Konstrukt lösen möchtest. Grundsätzlich braucht der Compiler den complete type der Basis Klassen. Für das Verständnis Deines Problems, kannst Du die namespaces sicher erst mal weg lassen. MainClass::MyClass ist ein Template, dass keine default Parameter hat, damit fehlt bei MyClass<> ein Parameter.
// here I access IUseMyClassAsBase related functionality
10
}
11
12
classIUseMyClassAsBase:publicMyClass<>
13
{
14
...
15
}
16
}
Die Implementationen der Funktionen von MyClass müssen dann ggf. ganz am Ende kommen, nachdem IUseMyClassAsBase vollständig definiert wurde, falls du dort Instanzen von IUseMyClassAsBase anlegen oder Funktionen davon aufrufen möchtest.
PS: Verschachtelte templates würde ich sparsam einsetzen, die helfen der Lesbarkeit nicht besonders. Man kann aber Aliase gewinnbringend einsetzen:
Dein Problem ist leider ziemlich abstrakt formuliert und daher schwer verständlich. Es hilft dieser Art von Frage ungemein, einen Schritt zurückzutreten und das Ziel zu formulieren, was erreicht werden soll, anstatt 95% der Lösung mit einem Detail-Roadblock zu posten. Der ist nämlich oft nicht lösbar und es muss stattdessen ein komplett anderer Ansatz gewählt werden, wobei man dir aber kaum helfen kann, weil man erst reverse-engineeren muss was du eigentlich tust.
Die "Maskierung" von Klassennamen zu "MyClass" und "Foo" und "X" ist auch extrem hinderlich bei einer Diskussion weil sie es unmöglich macht beim Formulieren einer Lösung die tatsächlichen Requirements deiner Anwendung von over-engineertem Nonsens zu trennen.
Davon abgesehen suchst du evtl. folgendes Pattern?
1
template<typename T>
2
class IUseMyClassAsBase : public T { ... };
und dann MyClass für T einsetzen. Damit kannst du den Code hinschreiben, aber er wird erst später vom Compiler gelesen, wenn T eingesetzt wird.
Forward Declarations helfen dir hier keinesfalls, damit kannst du eigentlich nur Pointer und Referenzen auf den unbekannten Typ machen und das war's.
Forward Declarations helfen dir hier keinesfalls, damit kannst du
eigentlich nur Pointer und Referenzen auf den unbekannten Typ machen und
das war's.
Doch, in der korrekten Reihenfolge schon. Alles andere außer Pointer & Referenzen macht sowieso keinen Sinn - also z.B. zirkulär ableiten oder Instanzen anlegen - weil das eine unendlich große Datenstruktur bedeuten würde...
Alles andere außer Pointer &
Referenzen macht sowieso keinen Sinn - also z.B. zirkulär ableiten oder
Instanzen anlegen - weil das eine unendlich große Datenstruktur bedeuten
würde...
Einfaches Gegenbeispiel: eine Baumstruktur mit 2 Typen von Knoten, die immer nur den jeweils anderen Typ als Kind haben können:
1
class Node1 {
2
std::optional<Node2> child;
3
}
4
5
class Node2 {
6
std::optional<Node1> child;
7
}
Geht in C++ in dieser Form nicht, macht aber absolut Sinn. Im Allgemeinen erlaubt die Sprache mit den Forward Declarations eben nur eine sehr kleine Klasse solcher Rekursionen, mit sehr trivialem statisch analysierbarem Verhalten. Es gibt aber noch viel mehr solche Strukturen, die nicht möglich sind, und zwar auch solche, bei denen schon statisch prüfbar wäre dass das immer geht, der Compiler das aber nicht kann.
Ok, stimmt, dieses Beispiel ist tatsächlich Quatsch. Dann nimm zwei Typen mit Member-Funktionen, die Instanzen des jeweils anderen Typs by value als Argument nehmen.
Hallo, ok, wie ich verstanden habe muss ich einen anderen Weg suchen. Zumindest die Definition wenigstens einer Klasse muss gegeben/bekannt sein.
Ich ginge von aus, dass einfaches Mitteilen dem Compiler, dass die Definition später folgt, für beide Klassen ausreichen wäre.
Danke für die Hinweise.
Hallo, ok, wie ich verstanden habe muss ich einen anderen Weg suchen.
Zumindest die Definition wenigstens einer Klasse muss gegeben/bekannt
sein.
Wobei dein Nutzungsfall auch so leicht fraglich ist, was du damit bezwecken willst. Grundsätzlich macht es nur Sinn aus C++-Sicht, zu fordern, dass die Basisklasse klar bekannt sein muss. Denn Vererbung garantiert ja, dass die abgeleitete Klasse eine Spezialisierung der Basisklasse ist (is-a-relationship). Wenn du die Basisklasse p-impeln könntest (vorwärtsdeklarieren), macht das ja so keinen Spaß.
Die Lösung für das Problem was du suchst, ist P-IMPL-Pattern in Verbindung mit dem Favor-Composition-Over-Inheritance-Prinzip.