In den meisten Antworten wird nicht erklärt, was das eigentliche Problem beim Slicing ist. Sie erklären nur die harmlosen Fälle von Slicing, nicht aber die tückischen. Gehen Sie, wie die anderen Antworten, davon aus, dass Sie es mit zwei Klassen zu tun haben A
y B
, wobei B
leitet sich (öffentlich) ab von A
.
In dieser Situation können Sie in C++ eine Instanz von B
zu A
Zuweisungsoperator (und auch zum Kopierkonstruktor). Dies funktioniert, weil eine Instanz von B
umgewandelt werden in eine const A&
Das ist das, was Zuweisungsoperatoren und Kopierkonstrukteure von ihren Argumenten erwarten.
Der gutartige Fall
B b;
A a = b;
Dort passiert nichts Schlimmes - Sie haben nach einer Instanz von A
die eine Kopie ist von B
und das ist genau das, was Sie bekommen. Klar, a
enthält nicht einige der b
Mitglieder, aber wie soll das gehen? Es ist ein A
schließlich nicht ein B
also hat es nicht einmal gehört über diese Mitglieder, geschweige denn in der Lage sein, sie zu speichern.
Der verräterische Fall
B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!
Man könnte meinen, dass b2
wird eine Kopie sein von b1
nachher. Aber, leider, es ist no ! Wenn Sie es untersuchen, werden Sie feststellen, dass b2
ist eine Frankenstein'sche Kreatur, die aus einigen Stücken von b1
(die Klumpen, die B
erbt von A
), und einige Brocken von b2
(die Chunks, die nur B
enthält). Autsch!
Was ist passiert? Nun, C++ behandelt standardmäßig Zuweisungsoperatoren nicht als virtual
. Somit ist die Linie a_ref = b1
ruft den Zuweisungsoperator von A
, nicht die von B
. Dies liegt daran, dass bei nicht-virtuellen Funktionen die erklärt (förmlich: statisch ) Typ (das ist A&
) bestimmt, welche Funktion aufgerufen wird, im Gegensatz zur aktuell (förmlich: dynamisch ) Typ (das wäre dann B
ya que a_ref
verweist auf eine Instanz von B
). Jetzt, A
kennt der Zuweisungsoperator offensichtlich nur die Mitglieder, die in A
kopiert, so dass nur diese kopiert werden, während die Mitglieder, die in B
unverändert.
Eine Lösung
Die Zuweisung nur an Teile eines Objekts macht in der Regel wenig Sinn, doch bietet C++ leider keine eingebaute Möglichkeit, dies zu verbieten. Sie können jedoch Ihre eigene Methode entwickeln. Der erste Schritt besteht darin, den Zuweisungsoperator virtuell . Damit ist gewährleistet, dass es immer die aktuell Zuweisungsoperator des Typs, der aufgerufen wird, und nicht der erklärt Typs. Der zweite Schritt ist die Verwendung von dynamic_cast
um zu überprüfen, ob das zugewiesene Objekt einen kompatiblen Typ hat. Der dritte Schritt besteht darin, die eigentliche Zuweisung in einem (geschützten!) Member vorzunehmen assign()
ya que B
's assign()
werden wahrscheinlich verwenden wollen A
's assign()
zum Kopieren A
Mitglieder.
class A {
public:
virtual A& operator= (const A& a) {
assign(a);
return *this;
}
protected:
void assign(const A& a) {
// copy members of A from a to this
}
};
class B : public A {
public:
virtual B& operator= (const A& a) {
if (const B* b = dynamic_cast<const B*>(&a))
assign(*b);
else
throw bad_assignment();
return *this;
}
protected:
void assign(const B& b) {
A::assign(b); // Let A's assign() copy members of A from b to this
// copy members of B from b to this
}
};
Der Einfachheit halber sei darauf hingewiesen, B
's operator=
kovariant den Rückgabetyp außer Kraft setzt, da es kennt dass es eine Instanz von B
.