nochmal Zuweisung ;)
-
Hallo!
Folgendes Problem: Ich habe eine Klasse B, die von A abgeleitet wird:class A { //... private: int a; public: const A &operator =(const A &src) { a = src.a; return *this; } //... }; class B : public A { //... private: int b; public: const B &operator =(const B &src) { A::operator =(src); b = src.b; return *this; } //... };
Und jetzt diese Funktion:
void assign(A &a1, const A &a2) { a1 = a2; }
Wenn man dieser Funktion jetzt aber zwei B-Objekte übergibt, gibt es Probleme, weil B::b nicht zugewiesen wird, da der Zuweisungsop. beider Klassen ja nicht virtual ist, was IMHO ja auch gar nicht geht. Wie kann ich den Zuweisungsop. so ändern, dass dieses Problem nicht mehr auftritt?
-
beider Klassen ja nicht virtual ist, was IMHO ja auch gar nicht geht
Sicher geht das:
class A { //... private: int a; public: virtual const A &operator =(const A &src) { a = src.a; return *this; } //... }; class B : public A { //... private: int b; public: const A &operator =(const A &src) // oder falls dein Compiler covariante return types erlaubt: // const B &operator =(const A &src) { // und jetzt kommt das Problem: const B* other; if ((other = dynamic_cast<const B*>(&src))) return *this = *other; else throw "Mixed typed assignment sucks balls on duck!"; return *this; } const B &operator =(const B &src) { A::operator =(src); b = src.b; return *this; } }; void assign(A &a1, const A &a2) { a1 = a2; } int main() { B a; B b; assign(a, b); }
Du holst dir damit allerdings alle Probleme von mixed-type Zuweisungen ins Haus. Die Probleme beschreibt Scott Meyers sehr schön in seinem Buch "Effective C++". Sie haben nicht unerheblich zur Formulierung der Regel "make non leaf classes abstract" beigetragen. Früher gab es dieses Item mal im Netz. Habe es jetzt aber auf die schnelle nicht mehr gefunden.
-
Original erstellt von HumeSikkins:
**Sicher geht das:class A { //... private: int a; public: virtual const A &operator =(const A &src) { a = src.a; return *this; } //... }; class B : public A { //... private: int b; public: const A &operator =(const A &src) // oder falls dein Compiler covariante return types erlaubt: // const B &operator =(const A &src) { // und jetzt kommt das Problem: const B* other; if ((other = dynamic_cast<const B*>(&src))) return *this = *other; else throw "Mixed typed assignment sucks balls on duck!"; return *this; } const B &operator =(const B &src) { A::operator =(src); b = src.b; return *this; } }; void assign(A &a1, const A &a2) { a1 = a2; } int main() { B a; B b; assign(a, b); }
**
Hmm, da war ich wohl falsch informiert...
**Du holst dir damit allerdings alle Probleme von mixed-type Zuweisungen ins Haus. Die Probleme beschreibt Scott Meyers sehr schön in seinem Buch "Effective C++". Sie haben nicht unerheblich zur Formulierung der Regel "make non leaf classes abstract" beigetragen. Früher gab es dieses Item mal im Netz. Habe es jetzt aber auf die schnelle nicht mehr gefunden.
**
Ja, das mach' ich schon auch so, bloß kann es auch vorkommen, dass man von einer nicht abstrakten Klasse ableiten will. (in meinem Fall std::string). Manchmal weiß man halt vorher nicht, dass von dieser Klasse mal abgeleitet wird...
Sollte man eigentlich dann den Zuweisungsoperator virtual machen?
-
bloß kann es auch vorkommen, dass man von einer nicht abstrakten Klasse ableiten will. (in meinem Fall std::string).
Wer von std::string öffentlich ableitet macht was falsch.
Sollte man eigentlich dann den Zuweisungsoperator virtual machen?
Ich halte davon nichts. Solange du nicht weißt, was genau bei einer mixed-type Zuweisung passieren soll, würde ich den op= niemals virtuell machen. Es mag Ausnahmen geben, wo ein virtueller op= sinn macht. Generell ist das aber nicht der Fall.
[ Dieser Beitrag wurde am 30.04.2003 um 20:44 Uhr von HumeSikkins editiert. ]
-
Danke erstmal!
Original erstellt von HumeSikkins:
Wer von std::string öffentlich ableitet macht was falsch.Zwar OT, aber: Warum? Wie soll man dann die std::string-Klasse an eigene Bedürfnisse anpassen (z.B Serialisierung über Pointer)?
-
Zwar OT, aber: Warum?
Technisch: std::string hat keinen virtuellen Destruktor. Erbt eine Klasse X öffentlich von std::string und wird ein dynamich erzeugtes Objekt x der Klasse X über einen std::string-Zeiger (oder eine std::string-Referenz) gelöscht, produziert dies undefiniertes verhalten.
Logisch:
1. std::string bietet *keine* virtuelle Methode. Eine abgeleitete Klasse kann also transparent keinerlei Verhalten ändern.2. std::string bietet *keine* hilfreiche protected-Schnittstelle. Eine abgeleitete Klasse gewinnt also keinen neuen Zugriff.
3. std::string hat keine virtuellen Basisklassen und leer ist std::string auch nicht (empty base class optimization)
Demzufolge gibt es keinen Grund (öffentlich) von std::string zu erben, da sich neue Eigenschaften, bei geringeren Abhängigkeiten, auch über Containment bzw. freie Funktionen realisieren lassen.
Der einzige Grund ist Schreibfaulheit und das ist kein guter Ratgeber. Außerdem kann dann auch, wenn es unbedingt sein muss, private Vererbung verwenden.
-
Aber wenn ich nur eine neue Membervariable und ein paar neue Funktionen einbau, dann geht's doch?
Ich möchte keine Methode von std::string überschreiben.
Faulheit liegt doch in der Natur des Menschen...[ Dieser Beitrag wurde am 01.05.2003 um 11:58 Uhr von Steven editiert. ]
-
Original erstellt von Steven:
Faulheit liegt doch in der Natur des Menschen...Fehler machen auch...
-
"Wenn man dieser Funktion jetzt aber zwei B-Objekte übergibt, gibt es Probleme, weil B::b nicht zugewiesen wird, da der Zuweisungsop. beider Klassen ja nicht virtual ist, was IMHO ja auch gar nicht geht."
Ist ja klar das es Probleme gibt:
Die Funktion erwartet ja eine Referenz vom Typ A (!);
Wenn du mit B daherkommst, weiß ich nicht genau was passiert, aber sicher NICHT das, was du erwartest;
Möglichkeiten: 1.) Wird auf A konvertiert -> Informationen gehen verloren;
2.) Compiler schreit (Typen passen nicht);Was sagt er denn?