Fragender schrieb:
Das CTwo Objekt, welches du hier erzeugst (und welches sich an dieser
Stelle seinen this Pointer merkt) ...
>
1 | COne container[2] = {COne(1), CTwo(2)};
|
2 | >
|
ist nicht dasselbe Objekt, wie das, welches dann im Array angelegt wird.
Das Array kann nur COne Objekte speichern. Keine CTwo Objekte. D.h. von
diesem CTwo Objekt wird, nachdem es erzeugt wurde, eine 'Kopie' gemacht,
welches nur aus dem COne-Anteil von CTwo besteht. Das CTwo Objekt wird
zu einem COne 'gestrippt' (so nennt man diesen Vorgang wenn ein Objekt
aus einer abgeleiteten Klasse in Richtung Basisklasse zurechtgestutzt
werden muss). Und da dazu ein neues Objekt erzeugt wird (erzeugt werden
muss), hat dieses neue Objekt danach logischerweise auch einen anderen
this Pointer.
Was da im Grunde steht bzw. passiert, kann man explizit so ausdrücken
1 | COne container[2] = {COne(1), COne( CTwo(2) ) };
|
Wenn du dir mal die Copy Konstruktoren überschreiben würdest, dann
müsste man eigentlich sehen, dass hier eine Kopie erzeugt wird.
Denn: die eigentlich interessante Frage ist eigentlich eine ganz andere.
Sie lautet: warum wird eigentlich vom COne(1) Objekt keine Kopie während
der Initialisierung gemacht? Denn eigentlich müsste das ja passieren!
Schreibe ich
1 | COne a(3);
|
2 | COne Container[] = { a };
|
dann muss ja von a eine Kopie erzeugt werden, die als Objekt im
Container weiterlebt. Es wird ja nicht das Objekt 'a' im Container
gespeichert, sondern eine Kopie davon. a liefert ja nur die Vorlage, wie
das Objekt im Container auszusehen hat.
Und prinzipiell ist es auch nicht das Objekt
1 | COne Container[] = { COne(4) };
|
das du hier in der Initalisierung angegeben hast, welches gespeichert
wird, sondern (völlig analog) eine Kopie davon. Der Fall unterscheidet
sich ja erst mal in nichts von dem Fall, in dem das Objekt a zur
Initialisierung benutzt wird. Dort war es ein Objekt mit einem Namen,
hier ist es ein temporäres Objekt. Aber der Vorgang ist der gleiche.
Hier in diesem Fall greift allerdings eine Optimierung, die in C++
zulässig ist. Sie besagt, dass in manchen Fällen der Compiler das
Erzeugen von Kopien weglassen kann, wenn er das Objekt quasi gleich am
Ziel erzeugen kann. Und genau das ist hier der Fall. Der aufwendige,
eigentlich richtige Prozess
erzeuge ein temporäres Objekt mit dem vorgesehenen Konstruktor
erzeuge das Objekt Container[0], wobei dieses Objekt mittels
Copy Constructor aus dem temporären Objekt erzeugt wird
zerstöre das temporäre Objekt
kann und darf vom Compiler zu
erzeuge das Objekt Container[0] mit dem vorgesehenen Konstruktor
abgekürzt werden. Das darf er auch dann tun, wenn der Copy-Konstruktor
Nebenwirkungen hat, die durch die Optimierung dann wegfallen.
D.h. die Frage lautet bei dir eigentlich nicht
* warum sind beim 2.ten Objekt die Pointer unterschiedlich?
Sondern die korrekte Fragestellung würde lauten
* warum sind sie es beim ersten Objekt nicht?
Und die Antwort lautet
weil der Compiler beim ersten Objekt das Erzeugen der Kopie mithilfe der
'Named Return Value Optimization' verhindern kann, während das im 2.ten
Fall aufgrund des Strippings nicht geht.
Das wäre die ausführliche technische Antwort, was da eigentlich abgeht.
Musst du dir so nicht merken, die Kurzform von oben ("wegen des
Strippings") reicht.