2016-07-22 18 views
2

Ich habe einen seltsamen Fall von Objekt Slicing. Ich arbeite an Projekt, wo ich Singleton-Klassen brauche, so dass meine Basis und abgeleitete Klasse beide Singleton sind. Der folgende Beispielfall beschreibt meine Situation.Kurioser Fall von C++ - Objekt-Slicing-Verhalten auf statische Datenbasiselement der Basisklasse

Dies ist meine Basisklasse

// Base.h 
class Base 
{ 
    public: 

     static Base& base; 

     virtual void doSomething(){ cout<<"Base Do Something"<<endl; } 

    protected: 

     Base(); 
     virtual ~Base(); 
     static Base& getBaseInstance(); 

    private: 
}; 

//Base.cpp 
Base::Base() 
{ 
    //ctor 
} 

Base::~Base() 
{ 
    //dtor 
} 

Base& Base::getBaseInstance() 
{ 
    static Base object; 
    return object; 
} 
Base& Base::base=Base::getBaseInstance(); 

Das ist meine Abgeleitete Klasse

class Derived: public Base 
{ 
    public: 

    static Derived& derived; 
    virtual void doSomething(){ cout<<"Derive Do Something"<<endl; } 

    static Derived& getDerivedInstance(); 
    protected: 
     Derived(); 
     virtual ~Derived(); 

    private: 
}; 

Derived::Derived() 
{ 
    //ctor 
} 

Derived::~Derived() 
{ 
    //dtor 
} 

Derived& Derived::derived=Derived::getDerivedInstance(); 

Derived& Derived::getDerivedInstance() 
{ 
    static Derived object; 
    return object; 
} 

Und schließlich das ist meine Hauptfunktion

int main() 
{ 
    cout << "Hello world!" << endl; 
    Base::base.doSomething(); 
    Derived::derived.doSomething(); 

    Base::base=Derived::derived; 

    Base::base.doSomething(); 

    Base::base=Derived::getDerivedInstance(); 

    Base::base.doSomething(); 

    Base& r = Derived::derived; 

    r.doSomething(); 

    Base::base=Derived::getDerivedInstance(); 
    Base::base.doSomething(); 
    return 0; 
} 

Und ich bin immer dafür folgende Ausgabe

Also meine Frage ist, da Objekt Slicing nicht auf Referenzen funktionieren sollte, warum kann ich nicht Base::base Referenz überschrieben werden, die ich als statisches Datenelement der Basisklasse mit abgeleitetem Objekt erstellt habe? Das funktioniert gut auf Base& r = Derived::derived;

Ich meine, wenn ich etwas mit r.doSomething() aufrufen, bekomme ich DoSomething der abgeleiteten Klasse. Aber das ist nicht so mit

Base::base=Derived::derived;  
    Base::base.doSomething(); 

oder

Base::base=Derived::getDerivedInstance();  
    Base::base.doSomething(); 

werden Jede Art von Klärung geschätzt. Danke.

+0

Sie können Referenzen nicht zurücknehmen. Wenn es so aussieht, als ob Sie dann sind, was passiert ist Schneiden. –

+0

Danke Kumpel. Ich habe so einen dummen Fehler gemacht (Codierung seit 2 Nächten gerade, ich schätze ich sollte einfach schlafen) Danke nochmal. –

Antwort

3

Wenn Sie das tun

Base::base=Derived::derived; 

Sie sind nicht die Basisreferenz Einstellung der abgeleiteten Klasse zu verweisen. Dies ist der Zuweisungsoperator und es wird nur der Base Teil von derived zu base zugeordnet.

base ist nach wie vor vom Typ Base und kann niemals als Referenz kann immer nur einmal sein ändern initialisiert und Sie tun, mit

Base& Base::base=Base::getBaseInstance(); 

Wenn Sie diese Neuzuordnung Verhalten möchten Sie einen Zeigertyp verwenden, gehen zu müssen, .

+0

Ohhh ich habe total vergessen, dass Referenzen nur einmal initialisiert werden können. Danke noch einmal. –

+1

@ Dr.Xperience Kein Problem. Froh, dass ich Helfen kann. – NathanOliver

1

Eine Referenz ist für alle Zwecke das Objekt, auf das verwiesen wird. Die Zuordnung zur Referenz erfolgt über das Objekt, auf das verwiesen wird. In Ihrem Fall haben die Objekte keine Datenelemente, daher gibt es keine Auswirkungen.

Insbesondere ist kein Aufschneiden feststellbar.

Die Erklärung

Base& r = Derived::derived; 

& hellip; ist ein ganz anderer Fall: eine Initialisierung, keine Zuweisung.

Eine Initialisierung bewirkt, dass sich die Referenz auf das angegebene Objekt bezieht.

Die Referenz kann danach nicht mehr geändert werden.


In anderen Nachrichten:

  • Die Globals (die Referenzen) die Gefahr statischen Initialisierungsreihenfolge Fiasko führen. Sie dienen nur dazu, den Vorteil der Singleton-Getter-Funktionen zunichte zu machen. Bei den Globals sind die Funktionen nur eine überflüssige Worzusoftlichkeit.

  • Veränderliche Singletons mit Datenelementen ermöglichen die Kommunikation zwischen weit getrennten und scheinbar nicht verbundenen Teilen des Codes. Dies macht es schwierig, sich auf Annahmen über den aktuellen Zustand und darüber, was was beeinflusst, zu verlassen. Das ist auch der Grund, warum globale Variablen in jeder Programmiersprache als böse ™ angesehen werden, also verwenden Sie Singletons mit Vorsicht.

+0

Dies ist nur ein Beispiel. Mein tatsächlicher Fall hat viele Mitglieder in abgeleiteter Klasse. Danke für die Hilfe. Ich habe so einen dummen Fehler gemacht. –

+0

Mein Projekt hat nur zwei Singletons. Sie agieren als Dienstleister. Für einen Fahrerdienstleister ist eh viel Aufwand. –

1

Base::base ist eine statische Referenz. Sie intialize es hier:

Base& Base::base=Base::getBaseInstance(); 

Von diesem Punkt an (das heißt, bevor Sie Ihren Code mit base ausgeführt wird), base auf die Basisinstanz bezieht (das heißt die statische Instanz in Base::getBaseInstance() deklariert).

Wenn Sie dann die Zuweisung durchführen, werden Sie die Referenz nicht mehr ändern, aber Sie werden das Objekt in das Objekt base kopieren (das vom Typ base ist, daher das Slicing!).

Eine Abhilfe könnte sein, Base :: Base einen Zeiger zu machen. Auf diese Weise könnten Sie es ändern und auf das abgeleitete Objekt zeigen. Aber passt das zu unserem Ansatz von Singleton (weil Sie dann das Basisobjekt irgendwo UND das abgeleitete Objekt haben).

+0

Re "daher die Slicing", gibt es keine Daten Mitglieder, so dass es keine nachweisbaren Slicing sein kann. –

+0

Danke Kumpel, ich kenne den Zeiger Ansatz. Vermeiden Sie es nur, um eine minimale Anzahl von Spuren zu haben (Intel-Spuren/Vordekodierung). Danke noch einmal. –

+0

@ Cheersandhth.-Alf gibt es möglicherweise keine Datenelemente, aber es gibt virtuelle Funktionen. Da es sich bei den Zuweisungen um ein einfaches Objekt handelt, ist der Abgeleitete Typ verloren, so dass die erwarteten virtuellen Funktionen nicht mehr verwendet werden. Ich bin nicht Natike Englisch Sprecher: Ich benutze "Slicing" [mit dieser Definition] (http://stackoverflow.com/questions/274626/what-is-object-slicing), wenn immer einige Informationen verloren gehen, aber vielleicht Sie sein kann eine bessere Formulierung vorschlagen. – Christophe