Verwirrung in der Ausgabe

8

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?

    
Prasoon Saurav 04.10.2009, 12:03
quelle

4 Antworten

7

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:

%Vor%

(Beachten Sie, dass ich auch Ihren Code geändert habe, um die idiomatischen I / O-I / O-Iteratoren von C ++ zu verwenden.)

    
sbi 04.10.2009, 12:38
quelle
11

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.

    
sepp2k 04.10.2009 12:11
quelle
3

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.

    
user49117 04.10.2009 12:17
quelle
1

Neben dem, was sepp2k sagte, haben Sie _bval im Konstruktor der abgeleiteten Klasse nicht initialisiert. Sie sollten es mit base constructor initialisieren.

    
AraK 04.10.2009 12:18
quelle

Tags und Links