2012-12-05 13 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; 
} 

我想創建一個3表類的數組。要求是我必須使用Base對象來做到這一點。如何在C++中創建一個具有多態性的數組?

Base1 * pBase = new table[3]; 

看起來不錯。但是當我試圖訪問每個表時,編譯器說它是訪問衝突。我不知道這段代碼有什麼問題。雖然我使用Visual Studio 2010。

回答

13

在C++中,多態和數組不會混合。

由於通常派生類的大小與基類的大小不同,因此多態和指針算術不能很好地一起玩。由於數組訪問涉及指針算術,因此諸如pBase[1]之類的表達式無法按預期工作。

一種可能性是將指針指向您的對象,甚至可能使用智能指針來簡化內存管理。但是不要忘記在Base1中定義一個虛擬析構函數。

3

您需要創建(與new)所有的數組元素,像這樣做:

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

你得到的錯誤,因爲該數組是靜態類型到Base1。這意味着,這條線:

pBase[1].GetRow(); 

增加了Base1字節大小pBase並解釋這是另一Base1對象的開頭,但其實這點某處進入第一table實例的中間。

如果您需要一個多態實例數組,您必須通過指針(或最好是某種形式的智能指針)將它們存儲在數組中(或最好在std::vector中)。

4

阿格紐的迴應是現貨。讓我再解釋一下。通過增加你的代碼,我打印出Base1的大小和table對象以及三個table對象的地址,因爲它們是由new運營商創建:

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 

正如你可以看到這些對象在存儲器中彼此間隔12個字節。

現在,讓我們打印出PBASE [0],P基準[1]和PBASE [2]給出了地址:

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

現在看看會發生什麼:我們回來間隔8個字節的指針分開。這是因爲指針算術是在類型爲Base1的指針上完成的,並且因爲Base1長度爲8個字節,編譯器所做的就是將pBase[n]轉換爲pBase + (n * sizeof(Base1))

現在你應該能夠明白爲什麼第一個GetRow()工作,爲什麼你在第二個崩潰。

+0

and shhh ..但鑄造到正確的類型,然後調用鑄造類型的方法將防止崩潰 – johnathon

+0

你的意思是'((table)pBase)[1] .GetRow()'?這將會起作用,但這是一件可怕的事情,幾乎肯定會回來並咬你。 –

+0

是的,我確實是這個意思。是的,它非常「可怕」,但它是哄騙編譯器訪問正確地址處的多態對象的一種非常有效的方式。 – johnathon

相關問題