2011-06-07 59 views
0

我有一個抽象基類和2個不同的類,它們實現了基類中的虛函數。如果派生類具有私有變量,派生類的數組就不起作用

我把這些放在一個數組中,而對於「derived1」類來說,這是可行的。 但是,如果我創建一個具有一些額外私有變量的「derived2」類的數組,代碼將在運行時進行編譯,但會發生錯誤。

#include <iostream> 
class base{ 
protected: 
    int inner_a; 
    int inner_b; 
public: 
    void setInner(int a,int b){inner_a=a;inner_b=b;}; 
    virtual int doStuff()=0; 
}; 


class derived1: public base{ 
public: 
    virtual int doStuff(); 
}; 



class derived2: public base{ 
private: 
    int tmpVar;//works if I remove 
public: 
    int doStuff(); 
}; 


int derived2::doStuff(){ 

    return inner_a-inner_b; 
} 

int derived1::doStuff(){ 
    return inner_a+inner_b; 
} 



int main(){ 
    base *classAry1 = new derived1[3];//this works 
    base *classAry2 = new derived2[2];//derived2 has extra private variables 


    classAry1[0].setInner(1,3); 
    classAry1[1].setInner(10,7); 
    std::cout <<classAry1[0].doStuff() <<std::endl;; 
    std::cout <<classAry1[1].doStuff() <<std::endl; 


    classAry2[0].setInner(1,3); 
    classAry2[1].setInner(10,7); 
    std::cout <<classAry2[0].doStuff() <<std::endl;; 
    std::cout <<classAry2[1].doStuff() <<std::endl; 


    return 0; 
} 

任何人都可以幫助我,關於如何把派生類放在一個std數組?

感謝

編輯:

的代碼段錯誤,並Valgrind的告訴我

-2

==25096== Use of uninitialised value of size 8 
==25096== at 0x400AC9: main (abc.cpp:52) 
==25096== 
==25096== Invalid read of size 8 
==25096== at 0x400AC9: main (abc.cpp:52) 
==25096== Address 0x0 is not stack'd, malloc'd or (recently) free'd 
==25096== 
==25096== 
==25096== Process terminating with default action of signal 11 (SIGSEGV) 
==25096== Access not within mapped region at address 0x0 
==25096== at 0x400AC9: main (abc.cpp:52) 
+1

什麼是「錯誤在運行時」是什麼意思? 「不起作用」是什麼意思? – AnT 2011-06-07 23:23:25

回答

7

一種陣列derived1對象(或derived2對象)的不能被解釋爲陣列base對象。數組不是多態的。只有獨立對象可以是多態的,即derived1base具有IS-A關係。但array of derived1array of base沒有IS-A關係。您的陣列(既不classAry1也不classAry2)都不能真正「工作」。

換句話說,這

base *classAry1 = new derived1[3]; 
base *classAry2 = new derived2[2]; 

已經沒有任何意義,即使它的正式結構良好的代碼。

第一個陣列「似乎正常工作」,只是純粹的意外。您的代碼行爲未定義,即使您使用classAry1

如果您想要一個存儲多態實體的數組(或容器),則必須將指針存儲到該數組中的實際對象,而不是存儲實際對象本身。

在您的具體情況下,代碼可以通過以下方式重寫。 (它看起來並不很漂亮,我只是做它來說明的原則,因爲不知道你的意圖完全是很難選擇最好的方法)

int main(){ 
    derived1 *d1s = new derived1[2]; 
    base **classAry1 = new base *[2]; 
    classAry1[0] = &d1s[0]; 
    classAry1[1] = &d1s[1]; 

    derived2 *d2s = new derived2[2]; 
    base **classAry2 = new base *[2]; 
    classAry2[0] = &d2s[0]; 
    classAry2[1] = &d2s[1]; 

    classAry1[0]->setInner(1,3); 
    classAry1[1]->setInner(10,7); 
    std::cout << classAry1[0]->doStuff() << std::endl;; 
    std::cout << classAry1[1]->doStuff() << std::endl; 

    classAry2[0]->setInner(1,3); 
    classAry2[1]->setInner(10,7); 
    std::cout << classAry2[0]->doStuff() << std::endl;; 
    std::cout << classAry2[1]->doStuff() << std::endl; 

    delete[] classAry2; 
    delete[] d2s; 
    delete[] classAry1; 
    delete[] d1s; 

    return 0; 
} 
+0

+ 1-這只是平坦的未定義。 – Puppy 2011-06-07 23:29:26

+0

我會補充說,這是因爲索引一個數組,你必須知道元素的大小,而你不能這樣做,因爲你不知道類型。 – 2011-06-07 23:29:27

+0

謝謝AndreyT的完整示例。我瞭解問題並立即解決。 – monkeyking 2011-06-07 23:51:02

1

一般來說,你不能做你正在嘗試做的。您正在調用未定義的行爲。當一個系統面臨未定義的行爲時,它可以自由地執行任何想要的操作(包括擦除硬盤驅動器),並且仍然符合標準。問題是你的代碼。

-1

嘗試使用std :: vector < base *>而不是原始數組。

0

你不能做到這一點。一個類型爲T1的數組不能轉換爲另一個類型爲T2的數組,即使其中一個是從另一個類型派生的。

您的線路上

base *classAry1 = new derived1[3];//this works 

你確實有什麼是數組的第一元素的基類指針,只有。其他元素是「迷失」。使用基類指針訪問除第一個之外的數組成員是未定義的行爲。

1

classAry2 [1] => & classAry2 + sizeof(base),它不等於實際派生的2的大小 ,它是> sizeof(base)或derived1。 您需要到達classAry2的正確地址(第二個元素),即 classAry2 + sizeof(derived2)。

最簡單的解決方法是使用指向base *的指針數組訪問它們。 使用基準** =分配基準數組* 然後爲每個元素分配正確的實例(派生或派生2或基準) 這樣當您使用classAry [n]或classAry ++時,它將始終指向正確的地址。

相關問題