2009-02-26 30 views
5

Ich habe eine Basisklasse und eine abgeleitete Klasse. Jede Klasse hat eine .h-Datei und eine .cpp-Datei.dynamic_cast schlägt fehl

I dynamic_cast der Basisklasse Objekt der abgeleiteten Klasse in dem folgenden Code tue:

h Dateien:

class Base 
{ 
    public: 
    Base(); 
    virtual ~Base(); 
}; 

class Derived : public Base 
{ 
    public: 
    Derived(){}; 
    void foo(); 
}; 

class Another 
{ 
    public: 
    Another(){}; 
    void bar(Base* pointerToBaseObject); 
}; 

cpp Dateien:

Base::Base() 
{ 
    //do something.... 
} 
Base::~Base() 
{ 
    //do something.... 
} 
void Derived::foo() 
{ 
    Another a; 
    a.bar(this); 
} 
void Another::bar(Base* pointerToBaseObject) 
{ 
    dynamic_cast<Derived*>(pointerToBaseObject) 
} 

Aus irgendeinem seltsamen Grund , das Casting schlägt fehl (gibt NULL zurück). Das Casting ist jedoch erfolgreich, wenn ich die Implementierung des Konstruktors der Derived-Klasse von .h in die .cpp-Datei verschiebe.

Was kann das verursachen?

Der Compiler ist gcc 3.1, auf Linux-SUSE. Übrigens, ich sehe dieses Verhalten nur auf dieser Plattform, und derselbe Code funktioniert in Visual Studio einwandfrei.

+0

vielleicht ist es ein Fehler mit gcc 3.1? Versuchen Sie "-fdump-class-hierarchy" -Option und schauen, ob es eine vtable für Ihre zwei Klassen erstellt –

Antwort

5

Der Code, wie gepostet, sollte nicht fehlschlagen, vorausgesetzt, Sie haben eine virtuelle Funktion in der Basisklasse (wie litb wies darauf hin).

Aber ich glaube, jeder aktuelle Compiler erzeugt eine "Basisklasse ist nicht polymorph" Art von Fehler, wenn Sie nicht, so dass wahrscheinlich nicht das Problem sein wird.

Das einzige, was mir einfällt ist, dass aufgrund eines seltsamen Fehlers alles inline wird und keine Vtable generiert wird. Wenn Sie jedoch den Konstruktor in die C++ - Datei einfügen, entscheidet der Compiler, dass er nicht alles inline einfügt, wodurch die Erstellung einer vtable ausgelöst wird, wodurch Ihre Umwandlung funktioniert.

Aber das ist sehr wild Mutmaßungen, und ich glaube nicht, dass Compiler einen solchen Fehler in ihm haben würde (?)

Wenn Sie eine definitive Antwort wünschen, mehr Code schreiben. Und der verwendete Compiler/Plattform.

EDIT: Sehen Sie die aktualisierte Code

Ich glaube, Sie zumindest von Base abgeleitet abzuleiten sollten;) (Ich nehme an, dass ein Tippfehler)

Aber nach dem Code zu sehen, das einzige, was ich denken kann, ist, dass gcc (falsch) alles einlindet und keine vtable für Derived generiert. Für was es wert ist, läuft das gut kompiliert mit gcc 4.0

3.1 ist jetzt über 7 Jahre alt ... wenn es irgendeine Möglichkeit gibt, upgrade ich würde dafür gehen.

7

Haben Sie eine virtuelle Funktion in Base? Es wird sonst nicht funktionieren. Wenn nichts anderes, mach seinen dtor virtuell.

Ich weiß nicht, ob es schon von dem anderen Typ gefragt wurde, der seine Antwort gelöscht hat, aber ich glaube, es war etwas anderes: Machst du den dynamic_cast vom Konstruktor der Basen? Wenn das so ist, wird das nicht funktionieren. Der Compiler wird denken, dass die Base der am weitesten abgeleitete Typ ist, ähnlich wie wenn Sie eine virtuelle Funktion aufrufen und die Version der Base aufgerufen wird.

+0

Ich habe virtuelle Funktionen in Base. –

3

Machen Sie den Destruktor virtuell und platzieren Sie ihn (oder mindestens eine virtuelle Methode) in der CPP-Datei.

Einige Compiler (lies: gcc) suchen nach dem zuerst gefundenen Nicht-Inline-Körper der virtuellen Methode und verwenden ihn, um zu entscheiden, wo die Tabelle der virtuellen Methoden abgelegt werden soll.Wenn Sie keine virtuellen Methoden mit Körpern in einer CPP-Datei haben, wird die virtuelle Methodentabelle nicht erstellt.

Sie müssen mindestens eine virtuelle Methode haben, damit dynamic_cast funktioniert. Dynamic Cast verwendet die Tabelle, um Typinformationen herauszufinden, und es wird keine Tabelle erstellt, wenn keine virtuellen Methoden vorhanden sind.

Wenn Sie eine Klasse haben, von der Sie erwarten, dass sie unterklassifiziert wird und einen Destruktor aufweist oder wenn die Klasse über Instanzvariablen verfügt, die Klassen mit Destruktoren sind, dann sollten Sie Ihren Destruktor wirklich virtuell machen (auch wenn dies der Fall ist) ein leerer Körper). Andernfalls wird die Bereinigung, die Sie erwarten, nicht für Subklasseninstanzen passieren.

0

Machst du das in Visual C++? Ich glaube, Sie müssen RTTI (Runtime Type Information) in der Compiler-Einstellung aktivieren, damit dies funktioniert.

Bitte flame mich nicht, wenn ich das falsch verstanden habe. Es ist schon eine Weile her, seit ich C++ benutzt habe !!!

0

Beim Betrachten Ihres Codes sehe ich keine Vererbung. Hast du das vergessen? Abgeleitet ist nicht von etwas abgeleitet.

0

In dem Code, den Sie gepostet haben Abgeleitet wird nicht von Base abgeleitet.

Edit: FYI, modifizierte Code funktioniert gut mit g ++ 3.4.5