Alles, was Sie tun mussten, war, RB
ohne das zu deklarieren : public RA
(oh, und auch ;
am Ende Ihrer Klassendefinitionen hinzuzufügen ):
class RA;
class A {
public:
virtual RA* Foo();
};
class RB;
class B {
public:
virtual RB* Foo();
};
class RA {};
class RB : public RA {};
int main ()
{
return 0;
}
Dies löst jedoch nicht das spezifische Problem, das in der Antwort von user1332054 gut beschrieben ist.
Einige der anderen Antworten scheinen einige Missverständnisse aufzuzeigen, die ich zerstreuen möchte:
Die Vorwärtsdeklaration ist auch dann nützlich , wenn wir wissen, dass die Definition wahrscheinlich nicht enthalten ist. Dies ermöglicht es uns, in unseren Bibliotheken viele Typabzüge vorzunehmen, die sie mit vielen anderen etablierten Bibliotheken kompatibel machen, ohne sie einzuschließen. Das Einschließen von Bibliotheken führt unnötigerweise zu zu vielen verschachtelten Includes, die die Kompilierungszeit sprengen können. Es wird empfohlen, Ihren Code gegebenenfalls kompatibel zu machen und so wenig wie möglich einzuschließen.
Typischerweise Sie können eine Klasse mit Zeigern auf Klassen definieren , die nur erklärt wurden und nicht definiert. Beispiel:
struct B;
struct A
{
B * b_;
B * foo ()
{
return b_;
}
B & foo (B * b)
{
return *b;
}
};
int main ()
{
return 0;
}
Das obige Kompilieren funktioniert einwandfrei, da der Compiler nichts über B wissen muss.
Ein Beispiel, bei dem es möglicherweise etwas schwieriger ist zu erkennen, dass der Compiler weitere Informationen benötigt:
struct B;
struct A
{
B * foo ()
{
return new B;
}
};
Das obige Problem ist, weil new B
der B::B()
Konstruktor aufgerufen wird, der noch nicht definiert wurde. Ebenfalls:
struct B;
struct A
{
void foo (B b) {}
};
Hier foo
muss der Kopierkonstruktor für aufgerufen werden b
, der ebenfalls noch nicht definiert wurde. Zuletzt:
struct B;
struct A
{
B b;
};
Hier haben wir implizit A
mit dem Standardkonstruktor definiert , der den Standardkonstruktor des Aufrufs seiner Mitglieder aufruft b
, der noch nicht definiert wurde. Ich denke, du verstehst, worum es geht.
In Bezug auf das allgemeinere Problem, das von user1332054 beschrieben wird, verstehe ich ehrlich gesagt nicht, warum es nicht möglich ist, Zeiger auf undefinierte Klassen in einer geerbten virtuellen Funktion zu verwenden.
Im weiteren Sinne denke ich jedoch, dass Sie es sich selbst schwerer machen, indem Sie Ihre Klassen definieren , anstatt sie nur zu deklarieren . Hier ist ein Beispiel, in dem Sie DoCleverStuff
mit Ihren Klassen in Ihrer Bibliothek beginnen, bevor Sie überhaupt eine Ihrer Klassen definiert haben:
class RA;
class RB;
class A;
class B;
template <class T>
struct is_type_A
{
static constexpr bool value = false;
};
template <>
struct is_type_A <A>
{
static constexpr bool value = true;
};
template <class T>
struct is_type_B
{
static constexpr bool value = false;
};
template <>
struct is_type_B <B>
{
static constexpr bool value = true;
};
#include <type_traits>
template<class T>
typename std::enable_if<is_type_A<T>::value, RA *>::type
DoCleverStuff (T & t)
{
return t.fooRet();
}
template<class T>
typename std::enable_if<is_type_B<T>::value, RB *>::type
DoCleverStuff (T & t)
{
return t.fooRet();
}
class RA
{
int x;
};
class RB : public RA
{
int y;
};
class A
{
public:
virtual RA * fooRet()
{
return new RA;
}
};
class B : public A
{
public:
virtual RB * fooRet()
{
return new RB;
}
};
int main ()
{
A a;
RA * ra = DoCleverStuff(a);
B b;
RB * rb = DoCleverStuff(b);
delete ra;
delete rb;
return 0;
}