Operator= und Objektinitialisierung
-
CodeWalker schrieb:
also folgendes Schema habe ich gelernt:
Wo lernt man sowas?
Bei mir nicht...1. Jede Klasse in einer Vererbungshierarchie soll die Zuweisung aller ihrer Attribute mit Ausnahme der geerbten in einer eigenen Methode kapseln. Diese Methode kann bei Einfachvererbung privat sein.
Zuweisung? Also der op=?
Ob der private ist oder nicht, hängt nicht davon ab ob die Klasse in einer Hierachie aufscheint, sondern einfach davon, ob man das Objekt kopieren darf.2. Der Zuweisungsoperator muß virtual sein. Er ist verantwortlich für die zuweisung eines vollständigen Objekts der betreffenden Klasse und hat als Rückgabetyp eine Referenz dieser Klasse.
Ich kenne mich mit den Problemen von virtuellen op= nicht aus - deswegen habe ich auch nichts dazu geschrieben - aber ich habe das noch nie gebraucht, ich wüsste nicht einmal wo es Sinn machen würde...
3. Der Zuweisungsoperator einer abgeleiteten Klasse, egal an welcher Stelle der Vererbungshierarchie, hat die oben angegebene Struktur, wobei die abgeleitete Klasse von der direkten Oberklasse abgeleitet wird.
Den Satz verstehe ich nicht.
siehe auch: U. Breymann, C++ Eine Einführung, 5. Auflage 1999, pg. 336 ff.
Ich hab das Buch leider nicht

class OberKlasse { public: OberKlasse() { //Initliste! privateData_1=new int(0); privateData_2=new int(0); //nicht exception safe }; virtual ~OberKlasse() { delete privateData_1; delete privateData_2; }; virtual OberKlasse& operator=(const OberKlasse& rhs) { if (this!=&rhs) { localCopy(rhs); } return *this; } //op= lehre ich so: OberKlasse& operator=(OberKlasse other) { swap(other); } //wobei dies einen CopyCtor erforder //swap sieht dann so aus: void swap(OberKlasse& other) { std::swap(privateData_1, other.privateData_1); std::swap(privateData_2, other.privateData_2); } private: int* privateData_1; int* privateData_2; int localCopy(const OberKlasse& rhs) { //das int übersehe ich mal ;) *privateData_1=*rhs.privateData_1; *privateData_2=*rhs.privateData_2; //nicht exception safe } }; class Abgeleitet1 : public OberKlasse { public: Abgeleitet1() { //Initliste! privateData_3 = new int(0); privateData_4 = new int(0); //nicht exception safe }; virtual ~Abgeleitet1() { delete privateData_3; delete privateData_4; } Abgeleitet1& operator=(const Abgeleitet1& rhs) { const OberKlasse& rs = dynamic_cast<const OberKlasse&>(rhs); //ein dynamic_cast? sinnlose kosten if (this!=&rhs) { OberKlasse::operator=(rs); localCopy(rhs); //nicht exception safe }; return *this; } private: int* privateData_3; int* privateData_4; int localCopy(const Abgeleitet1& rhs) { *privateData_3=*rhs.privateData_3; *privateData_4=*rhs.privateData_4; //nicht exception safe } };btw: der Test auf selbstzuweisung ist nicht ganz unproblematisch. ich würde ihn deshalb lieber weglassen. zumal er ja nix bringt. denn wenn jemand
x=x; schreibt, wird er damit leben müssen dass x sich selbst kopiert.
-
lassen wir mal diesen lästigen selbstzuweisungstest weg (ist in dem fall egal):
class base { int foo_; public: base (int i) : foo_(i) {} int foo () const { return foo_; } virtual base &operator = (const base &b) { foo_ = b.foo_; return *this; } virtual ~base () {} }; class derived : public base { int own_foo_; public: derived (int a, int b) : base(a), own_foo_(b) {} int own_foo () const { return own_foo_; } derived &operator = (const derived &d) { const base& b = dynamic_cast<const base&>(d); //warum so umständlich? base::operator=(b); own_foo_ = d.own_foo_; return *this; } }; int main() { derived d(1,2); base *b = new derived(0,0); *b = d; //das sollte ja wohl das anwendungsgebiet sein... cout << b->foo() << " und " << static_cast<derived*>(b)->own_foo() << endl; delete b; }und, was liefert die ausgabe?
deklariere den operator= in base einmal als rein virtuell und schau dir die fehlermeldung deines compilers an.
-
Shade Of Mine schrieb:
btw: der Test auf selbstzuweisung ist nicht ganz unproblematisch. ich würde ihn deshalb lieber weglassen. zumal er ja nix bringt. denn wenn jemand
x=x; schreibt, wird er damit leben müssen dass x sich selbst kopiert.Das eigentliche Problem mit der Selbstzuweisung ist ein anderes.

MyClass& operator=(const MyClass& other) { delete bla; bla = new ... // Initialisiert mit dem Wert von other. Aber hey, den Wert haben wir gerade gelöscht! }Und was gibt es an dem Adressenvergleich auszusetzen? Ich sehe kein Problem.
CodeWalker:
Wozu man allerdings nen virtuellen Zuweisungsoperator braucht, entzieht sich meiner Kenntnis. AFAIK implementiert der Compiler sowieso automatisch für jede Klasse einen Zuweisungsoperator, den man halt bei Bedarf redefinieren kann. Und wenn man ihn redefiniert, sollte man natürlich auch den operator= der Basisklasse aufrufen.
-
Optimizer schrieb:
Und was gibt es an dem Adressenvergleich auszusetzen? Ich sehe kein Problem.
Ich muss gestehen, dass ich es vergessen habe. Da war irgendwas mit Basisklasse und sonstwas.
Sorry - ich weiss es nicht mehr.
Einfach meine exception safe Variante nehmen und man hat das Problem nicht mehr.
Ausserdem ist meine Variante so schön kurz

-
Das Problem ist, daß Zuweisungsoperatoren, die um korrekt zu sein auf Selbstzuweisung testen müssen meist nicht stark exception sicher sind.
MfG Jester
-
Shade Of Mine schrieb:
Optimizer schrieb:
Und was gibt es an dem Adressenvergleich auszusetzen? Ich sehe kein Problem.
Ich muss gestehen, dass ich es vergessen habe. Da war irgendwas mit Basisklasse und sonstwas.
Sorry - ich weiss es nicht mehr.
Scott Meyers schreibt sowas in einem seiner "Effective C++" Bücher. Er irrt sich damit aber. Der Code den er da präsentiert macht dem Vergleich keinerlei Probleme.
Sowohl und mehrfacher, als auch unter virtueller Vererbung macht der Test, dass was er soll.Unter mehrfacher (nicht virtueller) Vererbung kann er allerdings zu auf den ersten Blick merkwürdigen Ergebnissen kommen:
class A { public: A& operator = (const A& rhs) { if(this!=&rhs) cout << "ungleich" << endl; else cout << "gleich" << endl; return *this; } }; class B: public A { }; class C: public A { }; class D: public B, public C { }; int main() { D d; A& aOverB = static_cast<B&>(d); A& aOverC = static_cast<C&>(d); aOverB = aOverC; }Hier erhält man als Ausgabe "ungleich", obwohl doch letztlich nur ein einziges D-Objekt verglichen wird. Genauer betrachtet macht das aber sinn. d enthält zwei A-Objekte, die natürlich zwei unterschiedliche Adressen besitzen und genau die Adressen dieser beiden unterschiedlichen A-Objekte vergleichen wir.
Jesters Punkt ist der Entscheidene.
-
also der aufruf
matrix m = matrix(10,10);funktioniert jetzt, nicht jedoch
matrix m; m = matrix(10,10);
edit: jetzt läufts, hatte nen syntax-fehler bei der überladung des konstruktors...
-
aber ein anderes problem hab ich noch mit dem destruktor:
matrix::matrix(int x, int y):size_x(x), size_y(y) { m = new double[x*y]; } matrix::~matrix() { delete [] m; }wenn ich nun das programm aufrufe stürzt es am ende ab, wenn ich das delete im destruktor wegnehme nicht! woran liegts?
-
Zeig mal Deinen Copy-Ctor.
-
danke aber hat sich schon erledigt.

allerdings chrasht das programm jetzt an anderer stelle, aber dazu kann ich erst mittwoch was sagen wenn ich wieder dran arbeite.