2016-06-01 10 views
0

Ich habe folgendes MWE Code:Virtuelle Zuweisungsoperator nicht static_cast ermöglicht

#include <algorithm> 

class Base{ 
public: 
    int baseMember; 
    friend void swap(Base& in, Base& out) 
    { 
     using std::swap; 
     swap(in.baseMember, out.baseMember); 
    } 
    virtual Base& operator=(Base obj) 
    { 
     swap(*this, obj); 
     return *this; 
    } 
    Base() : baseMember(1) 
    {  
    } 
}; 
class Derived : public Base 
{ 
public: 
    int derivedMember; 
    friend void swap(Derived& in, Derived& out) 
    { 
     using std::swap; 
     swap(in.derivedMember, out.derivedMember); 
     swap(static_cast<Base&>(in), static_cast<Base&>(out)); 
    } 
    virtual Base& operator=(Base obj) 
    { 
     swap(*this, static_cast<Derived&>(obj)); 
     return *this; 
    } 
    Derived() : Base(), derivedMember(2) 
    { 
    } 
}; 

int main() 
{ 
    Base *b1 = new Derived(); 
    Base *b2 = new Derived(); 
    *b1 = *b2; 
    delete b1; 
    delete b2; 
} 

Ich habe zwei Base Zeiger zeigt auf Derived Daten. Ich mache dann eine Zuordnung der Inhalte der Zeiger. Da der Zuweisungsoperator der Klasse Basevirtual ist, tritt Polymorphismus ein und der Zuweisungsoperator der Klasse Derived (mit der gleichen Signatur) wird stattdessen aufgerufen.

Die static_cast Umwandlung der Quelle in ein Derived Objekt schlägt jedoch fehl. Oder, naja, es wandelt es erfolgreich in ein Derived Objekt um, aber sein derivedMember ist Müll (nachdem es anfänglich im Konstruktor gesetzt wurde).

Wie kann dies vermieden werden? Wie kann eine Zuordnung zwischen dem Derived Inhalt von zwei Base Zeigern erfolgen?

+0

Verwenden Sie 'dynamic_cast' stattdessen, es ist sicherer, weil es überprüft, ob die Referenz * wirklich * auf' Derived' Objekt bezieht. – PcAF

Antwort

3

Ihr Code weist einen Tippfehler und ein inhärent unsicheres Verhalten auf. Der Tippfehler hier:

virtual Base& operator=(Base obj) // <-- should be base& 
{ 
    swap(*this, static_cast<Derived&>(obj)); 
    return *this; 
} 

Wenn Sie dieses Problem zu beheben, der Code in dem einfachen Beispiel vorgesehen funktionieren soll. Aber es würde immer noch insgesamt scheitern, denn wie würden Sie garantieren, dass das an operator= übergebene Argument in der Tat von Derived sein wird?

1

Das Übergeben eines Arguments nach Wert schneidet dieses Argument ab. Wenn Sie also Ihre operator= Funktion aufgerufen haben, haben Sie eine tatsächliche Base, keine Derived.

Ich fürchte, Sie müssen Ihre Zuweisung für lvalues ​​und rvalues ​​überladen.

+0

Ah. Na sicher. Ich habe versucht, das Copy-Swap-Idiom zu verwenden und den Copy-Constructor zu verwenden, aber natürlich wird nur eine Kopie von "Base" erstellt. Bedeutet das aber, dass Copy-Swap in einem solchen Fall nicht funktioniert? Ich kann 'swap()' nicht für eine konstante Referenz oder für einen rvalue verwenden. – Wasabi

+0

Oder sollte ich die const-Referenz verwenden, um ein temporäres Objekt zu erstellen und das im 'swap' zu verwenden, was die [SO C++ FAQ auf copy-swap] (http://stackoverflow.com/a/3279550/2175231) aufruft eine "naive Umsetzung des Idioms"? – Wasabi