2012-03-31 17 views
0

Ich habe ein Problem. Es gibt zwei Klassen:Typecasting und Vererbung in C++

struct Base { 
    Base* retain() { 
    //retain here 
     return this; 
    } 
}; 

struct Derived : Base { 
}; 


Derived *d1 = new Derived(); 
Derived *d2 = d1->retain(); //error here: need to typecast to Derived* 
Derived *d3 = (Derived*)d1->retain(); //OK 

Gibt es eine Möglichkeit() Funktion in einer Weise neu zu schreiben behalten, dass ich nicht brauchen, um manuell Typumwandlung Ergebnis? Mit anderen Worten: retain() sollte ein Objekt des abgeleiteten Typs zurückgeben.

Antwort

4
template<typename T> 
struct Base 
{ 
    T* retain() 
    { 
     return (T*)this; 
    } 
}; 

struct Derived : Base<Derived> 
{ 
}; 


Derived *d1 = new Derived(); 
Derived *d2 = d1->retain(); 

Alternativ:

struct Base 
{ 
    template<typename T> 
    void retain(T** ptr) 
    { 
     *ptr = (T*)this; 
    } 
}; 

struct Derived : Base 
{ 
}; 

Derived *d1 = new Derived; 
Derived *d2; 
d1->retain(&d2); 
+0

Das ist besser als meine Antwort. Bevorzugen Sie diese. – thb

+0

BTW, der erste Ansatz heißt ["Curiously wiederkehrende Vorlage Muster" (CRTP)] (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) –

0

Normalerweise, wenn Sie die Art der Sache tun, die Sie tun, wird die Base-Klasse einen virtuellen Destruktor haben. Dies ermöglicht die Identifikation des Laufzeittyps.

Sie möchten wahrscheinlich auch struct Derived : public Base schreiben, einschließlich des Schlüsselworts public.

Erklärung für den virtuellen Destruktor folgt.

Ein Objekt einer einfachen Klasse, die Klasse ohne virtuelle Methoden, ist nichts als eine Sammlung von Daten im Speicher. Code, der die Adresse eines solchen Objekts hat, kann nicht einfach durch Betrachten des Objekts feststellen, ob das Objekt von der Basis oder vom abgeleiteten Typ ist.

Wenn jedoch der Basistyp über mindestens eine virtuelle Methode verfügt, fügt der Compiler jedem Objekt des Typs einen einzelnen versteckten Zeiger hinzu. Dieser Zeiger zeigt auf eine Tabelle, die unter anderem den Typ des Objekts genau identifiziert, so dass dynamic_cast<>() und andere polymorphe Operationen auf dem Zeiger möglich sind.

Wenn all dies für Sie neu ist, dann ist hier, was ich empfehle nächste zu versuchen: fügen Sie einen null virtuellen Destruktor virtual ~Base() {} der Base-Klasse und lesen Sie dann über dynamic_cast<>(). Als nächstes möchten Sie vielleicht auch die Basis retain() virtuell machen und dann Derived eine eigene, überschreibende retain() geben.

Wie auch immer, es sei denn, Sie können gezieltere Ratschläge erhalten, das vorhergehende sollte Ihnen etwas geben, mit dem Sie anfangen können. Viel Glück.

+1

der Standardvererbungs Zugriffsbezeichner für Strukturen Öffentlichkeit ist – givi

+0

@givi: Das habe ich nicht wissen. Vielen Dank. – thb

+0

Ich weiß, was virtuelle Funktion ist und was virtueller Destruktor ist. Dynamisches Casting passiert in Runtime und ich habe einen Kompilierzeitfehler. – givi