Betrachten Sie das folgende Programm.
%Vor% Die Ausgabe des obigen Programms ist 01010.
Ich dachte, die Ausgabe wäre 00000, weil der Wert von _bval von dem Basisklassenkonstruktor auf 0 (jedes Mal) initialisiert wurde.
Aber warum unterscheidet sich die Ausgabe von 00000? Was vermisse ich?
Kurze Antwort: In C ++ sind Arrays von Werten niemals polymorph, selbst wenn ihr Inhalt dies ist und können nicht so behandelt werden. Das heißt, Sie können ein derived ad[N]
nicht so behandeln, als wäre es ein base ab[N]
.
Lange Antwort: Der Grund dafür liegt in der Zeigerarithmetik von C. Wenn Sie ein int* pi
haben und es um ++pi
erhöhen, wird es nicht einfach auf die nächste Speicheradresse erhöht. Wenn dies der Fall wäre, würde es nicht auf die nächste int
zeigen, da diese nicht bei der nächsten Adresse beginnt. Stattdessen werden sizeof(int)
Bytes zum Zeiger hinzugefügt. (Ein konkretes Beispiel könnte hilfreich sein: Auf Architekturen mit 8bit char
types - char
ist definitionsgemäß C und C ++ berücksichtigen die Bytegröße der Architektur - und 32bit int
types, int
hat die Größe von 4 Bytes. Daher fügt ++pi
der Zeigeradresse 4 hinzu, so dass es auf die nächste int
zeigt. Die gleiche Arithmetik gilt für alle anderen Zeigeroperationen. So wird zum Beispiel mit int* pi2=pi+1
, pi2
sizeof(int)
bytes auf pi
zeigen, obwohl pi2-pi
1 ergibt.
Wenn Sie also den letzten Absatz verstanden haben, gehen wir zurück zu Arrays. Wenn Sie ein Array derived ad[N]
haben, ist die Adresse von ad[1]
sizeof(derived)
Bytes größer als die Adresse von ad[0]
. (Das heißt, man ignoriert die Ausrichtung, um das Problem nicht weiter zu komplizieren.) Wenn Sie jedoch ein base* pb
auf ad[0]
zeigen, wird es beim Inkrementieren sizeof(base)
hinter die Adresse des ersten Elements zeigen - was, wenn (wie in Ihrem Beispiel) sizeof(base) < sizeof(derived)
, ist nicht die Adresse von ad[1]
, aber irgendwo in der Mitte von ad[0]
.
Das Einzige, was Sie tun können, um den Array-Inhalt so zu behandeln, als ob es alle Basisklassen wären, besteht darin, mit einem derived*
über das Array zu iterieren und diesen Zeiger innerhalb von auf base*
zu setzen Schleife:
(Beachten Sie, dass ich auch Ihren Code geändert habe, um die idiomatischen I / O-I / O-Iteratoren von C ++ zu verwenden.)
p[i]
gibt Ihnen den Wert bei sizeof(base) * i
bytes nach p
. So wird p[1]
Ihnen nicht das zweite Element von d
geben, es wird Ihnen die zweite Hälfte des ersten Elements geben.
Mit anderen Worten: Wenn Sie einen Zeiger auf die Basisklasse verwenden, um über ein Array der abgeleiteten Klasse zu iterieren, erhalten Sie falsche Ergebnisse, wenn die abgeleitete Klasse eine größere Größe als die Basisklasse hat, weil sie schrittweise durchlaufen wird von sizeof(baseclass)
bytes.
Denken Sie an das Speicherlayout von d-Array.
d- & gt; 0101010101
Wo jedes Paar von 01 einem abgeleiteten Objekt entspricht.
Nun lasst p darauf zeigen:
p- & gt; 0101010101
Da die Größe der Basisobjekte die eines int ist. Dieses Speichersegment wird als 10 Basisobjekte betrachtet: das erste mit _bval 0, das zweite mit _bval 1, ... etc.
Tags und Links c++