2012-04-04 7 views
0

Diese Frage betrifft das Überschreiben einer virtuellen Methode in einer abgeleiteten Klasse mit einem anderen Rückgabetyp. Für den folgenden Code:Fehler beim Zurückgeben eines abgeleiteten Klassenzeigers beim Überschreiben einer virtuellen Methode

class father { 
public: 
    virtual father* ref() { return this; } 
}; 

class child : public father { 
    virtual child* ref() { return this; } 
}; 

Wenn ich versuche, direkt einen Zeiger zu erhalten, g ++ (F15, g ++ 4.5) berichtet, "ungültige Umwandlung von Vater zu Kind"

child m_child; 
father* pf = &m_child; 
child* pc = pf->ref(); 

verstehe ich die ref() -Methode in der Kindklasse wird verwendet und dies ist wahrscheinlich nur ein Fehler bei der Kompilierungszeit.

Gibt es jedoch eine Möglichkeit, dies ohne explizite Verwendung eines Typcast zu tun?

Zusätzliche Beschreibung: Ich verstehe den Grund, warum Compiler diesen Fehler melden. Was ich brauche, ist etwas aus der Box, das auf die Daten in abgeleiteten Objekten zugreifen kann, ohne explizit einen Zeiger zu konvertieren.

Die Vaterklasse wird verwendet, um verschiedene abgeleitete untergeordnete Objekte in Listen oder Vektoren einzufügen. Wenn also ein Element aus der Liste oder dem Vektor abgerufen wird, kann nicht angegeben werden, welcher Kindklasse es angehört.

Ich habe interne Methode zum Aufzeichnen und Überprüfen der Kindklasse Typ. Aber ich möchte den Zeiger nicht explizit konvertieren.

Zum Beispiel würde Ich mag so etwas tun:

// assuming pf is pointer pointed to an item fetch from a vector 
switch(fp->get_type()) { 
case child_type1: fp->ref()->list1.push(data); break; 
case child_type2: fp->ref()->list2.push(data); break; 
case child_type3: fp->ref()->list3.push(data); break; 
} 

Gerade jetzt, ich brauche eine neue Variable explizit erklären oder explizit fp auf die richtige Art jeweils konvertieren und jedes Mal, wenn ich brauche Zugriff auf Daten in abgeleiteten Klassen, die mühsam und verwirrend sind.

Was ich erwarte sind: kann einige Boost-Bibliotheken können ähnliche Dinge auf eine andere Weise tun, die ich noch nicht weiß, oder kann die C++ 11 Standard erlaubt es aber eine spezielle Compiling-Parameter gesetzt werden muss?

+0

Ich glaube ich verstehe es sehr gut, warum der Compiler einen Typenkonflikt meldet. Was ich brauche, ist keine Erklärung darüber, was hier passiert. Ich brauche etwas aus der Box. Um es weiter zu erklären, sehen Sie bitte die zusätzliche Beschreibung hinzugefügt. –

Antwort

2

Einfache Antwort ist "Nein".

Sie haben die zusätzliche Informationen verloren (child* statt father*) über ref, wenn Sie werfen m_child s Typinformationen entfernt, indem er mich als Zeiger auf Basis (pf) zu speichern.

Ein Grund, warum es wird nie ohne Guss möglich sein, ist dieses Beispiel:

class father { 
public: 
    virtual father* ref() { return this; } 
}; 

class childA : public father { 
    virtual childA* ref() { return this; } 
}; 

class childB : public father { 
    virtual childB* ref() { return this; } 
}; 

void should_never_compile(int i) 
{ 
    childA a; 
    childB b; 
    father pf; 
    if(i) { pf=&a; } 
    else { pf=&b; } 

    // This is evil and will not compile 
    childA * pa = pf->ref(); 

    //But this is OK: 
    childA * pa = dynamic_cast<childA*>(pf->ref()); 
} 

Wenn Sie wirklich diese machbar, ohne die dynamische Umwandlung machen möchten, können Sie einfach die dynamische Umwandlung verstecken (aber es macht mir Angst ein wenig)

class father { 
public: 
    virtual father* ref() { return this; } 
    template<typename T> T* as() { return dynamic_cast<T*>(ref()); } 
}; 

child m_child; 
father* pf = &m_child; 
child* pc = pf->as<child>(); 
+0

Danke, du stellst mir etwas etwas besser! –

1

Ihre Funktion erfüllt, was Sie erwarten und was Sie sagen. Die Linie

child* pc = pf->ref(); 

ist das Problem. Sie rufen die Funktion "ref()" für einen Zeiger auf Vater auf, der (nach Typ) einen Vater * zurückgibt. Sie weisen dies - ohne Conversions - einem Kind zu *. Die Implementierung dieser Funktion gibt ein Kind *, aber von wo Sie es nennen, dass Informationen nicht bekannt sind wie Sie nur wissen, dass es ein Vater * ist. Der Rückgabetyp ist daher ein Vater * (wie in der Klasse Vater angegeben), und Sie weisen das ohne Konvertierung einem Kind * zu. Sie können tun:

child *pc = m_child.ref(); 
father *pf = m_child.ref(); 
father *pf2 = pf->ref(); 
+0

Gut erklärt @dascandy – Ricketyship

1

Das Problem ist, dass in dem Aufruf pf->ref(), die Art der ref ist: father* (father::*)().

Das heißt, ref ist aufgelöst statisch zu einem virtual Methode mit einer bestimmten Signatur. Und diese Signatur zeigt an, dass sie father* zurückgibt.

So:

int main() { 
    father f; 
    father* pf = &f; 

    child c; 
    child* pc = &c; 

    child* xf = pf->ref(); // compile-time failure 
    child* xc = pc->ref(); // okay 
} 

Das Problem ist, dass in der Regel von einem father* beginnen Sie können nicht wissen, ob Sie eine child* erhalten wird, ist es auf dem dynamischen Typ der Instanz abhängt. Der Compiler nimmt also den schlimmsten Fall an: er muss mindestens father sein.

Verwandte Themen