2012-12-05 11 views
6
class Base1 
{ 
    private: 
    int testInput; 
    public: 
     Base1(); 
     virtual int GetRow(void) = 0; 
}; 

Base1::Base1() 
{ 
    testInput = 0; 
} 

class table : public Base1 
{ 
    private: 
    int row;  
    public: 
    table(); 
    virtual int GetRow(void); 
}; 

table::table() 
{ 
    //Contructor 
    row = 5; 
} 

int table::GetRow() 
{ 
    return row; 
} 

int main() 
{ 
    Base1* pBase = new table[3]; 
    pBase[0].GetRow(); 
    pBase[1].GetRow(); //when i get to this line, the compiler keep saying access 
          // violation. 
    pBase[2].GetRow(); 

    return 0; 
} 

Ich versuche, ein Array von 3 Tabellenklasse zu erstellen. Die Voraussetzung ist, dass ich das Base-Objekt dazu verwenden muss.Wie erstellt man ein Array mit Polymorphismus in C++?

Base1 * pBase = new table[3]; 

gut für mich aussehen. Aber als ich versuchte, auf jede Tabelle zuzugreifen, sagte der Compiler, es sei Zugriffsverletzung. Ich weiß nicht, was mit diesem Code falsch ist. Ich verwende jedoch Visual Studio 2010.

Antwort

13

In C++, Polymorphismus und Arrays nicht vermischen.

Da die Größe der abgeleiteten Klasse im Allgemeinen von der Größe der Basisklasse abweicht, spielen Polymorphie und Zeigerarithmetik nicht gut zusammen. Da der Arrayzugriff die Zeigerarithmetik betrifft, funktionieren Ausdrücke wie pBase[1] nicht wie erwartet.

Eine Möglichkeit ist ein Array von Zeigern zu Ihren Objekten, vielleicht sogar Smart-Zeigern, um die Speicherverwaltung zu vereinfachen. Vergessen Sie aber nicht, einen virtuellen Destruktor in Base1 zu definieren.

3

Sie müssen erstellen (mit new) alle diese Array-Elemente, tun Sie es wie folgt aus:

for(int i = 0; i < 3; ++i) 
    pBase[i] = new table(); 
6

Sie bekommen den Fehler, da das Array statisch Base1 eingegeben wird. Das bedeutet, dass diese Zeile:

pBase[1].GetRow(); 

fügt die Größe von Base1 in Bytes pBase und interpretiert dies als den Beginn eines anderen Base1 Objekts, aber diese Punkte tatsächlich irgendwo in die Mitte der ersten table Instanz.

Wenn Sie ein Array von polymorphen Instanzen benötigen, müssen Sie diese im Array (oder vorzugsweise in einer std::vector) über Zeiger (oder vorzugsweise eine Form von Smartpointern) speichern.

4

Agnews Antwort war genau richtig. Lass mich etwas mehr erklären. Durch Code vermehren, ausdrucken ich die Größe eines Base1 und ein table Objekt sowie die Adressen der drei table Objekte, wie sie vom new Betreiber erstellt werden:

A Base1 object is 8 bytes 
A table object is 12 bytes 
A table object is being constructed at 0x002977C0 
A table object is being constructed at 0x002977CC 
A table object is being constructed at 0x002977D8 

Wie Sie diese Objekte zu sehen sind im Speicher 12 Byte voneinander beabstandet.

Nun lassen Sie uns die Adressen auszudrucken, die pBase [0], pBase [1] und pBase [2] geben:

pBase[0] is at 0x002977C0 
pBase[1] is at 0x002977C8 
pBase[2] is at 0x002977D0 

Jetzt schauen, was passiert: die Zeiger wir zurück sind 8 Bytes Abstand ein Teil. Dies liegt daran, dass die Pointerarithmetik für einen Zeiger ausgeführt wird, dessen Typ Base1 ist, und da Base1 8 Bytes lang ist, übersetzt der Compiler pBase[n] in pBase + (n * sizeof(Base1)).

Jetzt sollten Sie in der Lage sein zu verstehen, warum die ersteGetRow() funktioniert und warum Sie auf der zweiten abstürzen.

+0

und, shhh .. aber Casting auf den richtigen Typ, und dann Aufruf der Methode auf dem Gusstyp verhindert den Absturz – johnathon

+0

Sie meinen '((Tabelle) pBase) [1] .GetRow()'? Das wird funktionieren, aber es ist eine * schreckliche * Sache zu tun und wird mit ziemlicher Sicherheit zurückkommen und dich in den Arsch beißen. –

+0

ja ich meine genau das. Ja, es ist ziemlich "schrecklich", aber es ist eine ziemlich gute Möglichkeit, den Compiler dazu zu bringen, auf die polymorphen Objekte an den richtigen Adressen zuzugreifen. – johnathon

Verwandte Themen