2010-09-28 7 views
5

Zum Beispiel habe ich Code wie dieIst es möglich, von einer Basisklasse zur anderen zu dynamic_cast?

class Base1 
{ 
    virtual void wonderFULL() = 0; 
}; 

class Base2 
{ 
    // all this weird members 
}; 

class Derived : public Base1, public Base2 
{ 
    // not so weird members 
}; 

int main() 
{ 
    Derived Wonder; 
    magicFunction(&Wonder); 
    return 0; 
} 

void magicFunction(Base2 *ptr) 
{ 
    if (Base1 *b1 = dynamic_cast<Base1 *>(ptr)) 
    b1->wonderFULL(); 
} 

Allerdings ist wunderbar nie wegen Unmöglichkeit ausgeführt ptr auf b1 zu werfen. Ist es überhaupt möglich, eine solche Umwandlung durchzuführen?

+1

'-1' für das Posten von Code, der ein Problem hat, das die Kompilierung des Codes in einem Bereich verhindert, der sehr eng mit dem Problem verbunden ist. – sbi

+1

Ich stimme mit sbi überein. Dieses Beispiel sollte wie folgt aussehen: http://www.ideone.com/dg0gc. 'magicFunction' sollte vor' main' gehen, 'wonderFULL' sollte definiert und öffentlich sein. – Bill

Antwort

0

Ausgehend von dem, was ich verstehe, wie einige C++ - Compiler die Klassenhierarchie im Speicher anordnen, sollte es möglich sein, von einer Basisklasse in eine andere zu konvertieren, aber Sie müssen zuerst in die abgeleitete Klasse umwandeln.

Daher müssten Sie so etwas wie zu tun:

Base1* b1 = dynamic_cast<Derived*>(ptr); 

Dies wirft den gegebenen Zeiger ptr auf der abgeleiteten Klasse, und dann wird es implizit auf seine anderen Basisklasse Zeiger gegossen. Eine andere einfachere Möglichkeit dies zu tun wäre, eine Methode in der Base2-Klasse zu haben, die einen Base1-Zeiger zurückgibt, und die abgeleitete Klasse kann dies selbst ohne irgendeinen kniffligen Code implementieren.

(Die gleiche Funktion in Base2 kann nur NULL zurückgeben, wenn Sie keine reine virtuelle Klasse wollen).

7

Diese

#include <iostream> 

class Base1 { 
public: 
    virtual void wonderFULL() = 0; 
}; 

class Base2 { 
public: 
    virtual ~Base2() {}          // added so the code compiles 
}; 

class Derived : public Base1, public Base2 { 
    virtual void wonderFULL() {std::cout << "wonderful\n";} // added so the code compiles 
}; 

void magicFunction(Base2 *ptr) { 
    if (Base1 *b1 = dynamic_cast<Base1 *>(ptr)) 
     b1->wonderFULL(); 
} 

int main() { 
    Derived Wonder; 
    magicFunction(&Wonder); 
    return 0; 
} 

druckt wonderful für mich. Meine Schlussfolgerung ist, dass Sie nicht den Code zeigen, der für die Reproduktion Ihres Problems notwendig ist.

Nehmen Sie (eine Kopie von) Ihren tatsächlichen Code und entfernen Sie unwichtigen Code Schritt für Schritt destillieren Sie es, bis Sie in einem eigenständigen (benötigt keine anderen Header außer von der Standardbibliothek), kompilierbar Beispiel, das das Problem reproduziert. Sehr wahrscheinlich werden Sie das Problem dabei finden. Wenn Sie das nicht tun, haben Sie den perfekten Repro-Fall, um hierher zu kommen und danach zu fragen.

+0

Dieser Code ist nicht das, was das OP gepostet hat. (Beachten Sie, dass Sie in Base2 eine virtuelle Funktion haben, die dynamic_cast erlaubt.) – Bill

+0

@Bill: Ja, natürlich. Andernfalls kompiliert der Compiler den Code nicht einmal.Siehe meine Notiz am Ende meiner Antwort. – sbi

+0

+1, kann nicht auf einen Zeiger auf Klasse A umgewandelt werden, wenn Klasse A keine virtuellen Elementfunktionen hat. – sharptooth

2

Sie können die Hierarchie aufschütten dann wieder nach unten:

void magicFunction(Base2& ptr) 
{ 
    try 
    { 
     Derived& d = dynamic_cast<Derived&>(ptr); 
     Base1& b = dynamic_cast<Base1&>(d); 
     b.wonderFULL(); 
    } 
    catch(const std::bad_cast&) 
    { /* Cast failed */ } 
} 
+0

Das sollte bei 'dynamic_cast' nicht notwendig sein. Siehe meine Antwort. – sbi

+1

Es dokumentiert Absicht. Wenn der Compiler es gut optimiert. Aber die extra menschenlesbare Dokumentation von entente ist gut für mich. –

+0

(Sie sollten richtig @address ...) Ob die Absicht zu dokumentieren ist notwendig, ist offen für Diskussionen. Die ursprüngliche Frage ("Ist es möglich, von einer Basisklasse zur anderen zu wechseln?") Sollte eine klare und einfache Antwort haben. – sbi

2

Sie haben einige Syntaxfehler, aber Ihre eigentliche Problem ist dynamic_cast funktioniert nicht richtig, wenn Ihre Basisklassen nicht mindestens eine virtuelle haben Funktion.

Wenn Sie machen es wie folgt aussehen:

class Base2 
{ 
public: 
    virtual ~Base2() {} 
    // all this weird members 
}; 

Und dann fixieren Sie Ihre Fehler: wonderFULL ist privat, und nie definiert. magicFunction wird nach der Verwendung deklariert.

Dann alles works.

0

Ich habe das Problem gefunden. Es ging nicht um dynamic_casts. Ich habe ein falsches Objekt überprüft, das nicht von der abstrakten Basis geerbt wurde. Vielen Dank.