不要對(duì)數(shù)組使用多態(tài)

  • 類繼承的最重要的特性是你可以通過基類指針或引用來操作派生類。這樣的指針或引用
    具有行為的多態(tài)性,就好像它們同時(shí)具有多種形態(tài)。C++允許你通過基類指針和引用來操作
    派生類數(shù)組。不過這根本就不是一個(gè)特性
  • 假設(shè)你有一個(gè)類 BST(比如是搜索樹對(duì)象)和繼承自 BST 類的派生類 BalancedBST:
class BST { ... };
class BalancedBST: public BST { ... };
  • 有這樣一個(gè)函數(shù),它能打印出 BST 類數(shù)組中每一個(gè) BST 對(duì)象的內(nèi)容:
void printBSTArray(ostream& s,
const BST array[],
int numElements)
{
  for (int i = 0; i < numElements; )
     s << array[i]; //假設(shè) BST 類重載了操作符<<
}
  • 當(dāng)你傳遞給該函數(shù)一個(gè)含有 BST 對(duì)象的數(shù)組變量時(shí),它能夠正常運(yùn)行:
BST BSTArray[10];
...
printBSTArray(cout, BSTArray, 10); // 運(yùn)行正常

當(dāng)你把含有 BalancedBST 對(duì)象的數(shù)組變量傳遞給 printBSTArray
函數(shù)時(shí),會(huì)產(chǎn)生什么樣的后果

BalancedBST bBSTArray[10];
...
printBSTArray(cout, bBSTArray, 10); // 還會(huì)運(yùn)行正常么
你的編譯器將會(huì)毫無警告地編譯這個(gè)函數(shù),但是再看一下這個(gè)函數(shù)的循環(huán)代碼:
for (int i = 0; i < numElements; ) {
s << array[i];
}
  • 這里的 array[I]只是一個(gè)指針?biāo)惴ǖ目s寫:它所代表的是(array),我們知道 array是一個(gè)指向數(shù)組起始地址的指針,但是 array 中各元素內(nèi)存地址與數(shù)組的起始地址的間隔究竟有多大呢?
    它們的間隔是 i
    sizeof(一個(gè)在數(shù)組里的對(duì)象),因?yàn)樵?array 數(shù)組[0]到[I]
    間有 I 個(gè)對(duì)象。編譯器為了建立正確遍歷數(shù)組的執(zhí)行代碼,它必須能夠確定數(shù)組中對(duì)象的大小,這對(duì)編譯器來說是很容易做到的。參數(shù) array 被聲明為 BST 類型,所以 array 數(shù)組中每一個(gè)元素都是 BST 類型,因此每個(gè)元素與數(shù)組起始地址的間隔是 i*sizeof(BST)
    至少你的編譯器是這么認(rèn)為的。但是如果你把一個(gè)含有 BalancedBST 對(duì)象的數(shù)組變量傳遞給 printBSTArray 函數(shù),你的編譯器就會(huì)犯錯(cuò)誤。在這種情況下,編譯器原先已經(jīng)假設(shè)數(shù)組中元素與 BST 對(duì)象的大小一致,但是現(xiàn)在數(shù)組中每一個(gè)對(duì)象大小卻與 BalancedBST 一致。
    派生類的長度通常都比基類要長。我們料想 BalancedBST 對(duì)象長度的比 BST 長。
    如果如此的話,printBSTArray 函數(shù)生成的指針?biāo)惴▽⑹清e(cuò)誤的,沒有人知道如果用 BalancedBST 數(shù)組來執(zhí)行 printBSTArray 函數(shù)將會(huì)發(fā)生什么樣的后果。不論是什么后果都是令人不愉快的

  • 如果你試圖刪除一個(gè)含有派生類對(duì)象的數(shù)組,將會(huì)發(fā)生各種各樣的問題。以下是一種你可能采用的但不正確的做法。
//刪除一個(gè)數(shù)組, 但是首先記錄一個(gè)刪除信息
void deleteArray(ostream& logStream, BST array[])
{
logStream << "Deleting array at address "
<< static_cast<void*>(array) << '\n';
delete [] array;
}
BalancedBST *balTreeArray = // 建立一個(gè) BalancedBST 對(duì)象數(shù)組
new BalancedBST[50];
...
deleteArray(cout, balTreeArray); // 記錄這個(gè)刪除操作

這里面也掩藏著你看不到的指針?biāo)惴ā.?dāng)一個(gè)數(shù)組被刪除時(shí),每一個(gè)數(shù)組元素的析構(gòu)函
數(shù)也會(huì)被調(diào)用。當(dāng)編譯器遇到這樣的代碼:

delete [] array;
它肯定象這樣生成代碼:
// 以與構(gòu)造順序相反的順序來
// 解構(gòu) array 數(shù)組里的對(duì)象
for ( int i = 數(shù)組元素的個(gè)數(shù) 1; i >= 0;--i)
{
array[i].BST::~BST(); // 調(diào)用 array[i]的
} // 析構(gòu)函數(shù)

因?yàn)槟闼帉懙难h(huán)語句根本不能正確運(yùn)行,所以當(dāng)編譯成可執(zhí)行代碼后,也不可能正
常運(yùn)行。語言規(guī)范中說通過一個(gè)基類指針來刪除一個(gè)含有派生類對(duì)象的數(shù)組,結(jié)果將是不確
定的。這實(shí)際意味著執(zhí)行這樣的代碼肯定不會(huì)有什么好結(jié)果。多態(tài)和指針?biāo)惴ú荒芑旌显谝?br> 起來用,所以數(shù)組與多態(tài)也不能用在一起。
值得注意的是如果你不從一個(gè)具體類(concrete classes)(例如 BST)派生出另一個(gè)
具體類(例如 BalancedBST),那么你就不太可能犯這種使用多態(tài)性數(shù)組的錯(cuò)誤

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容