- 論壇徽章:
- 0
|
原帖由 lnfxcf 于 2007-1-12 17:45 發(fā)表
那為什么delete p;就沒有問題?
這個問題是根據(jù)自己的想法回復的, 不能以理服人.hehe
昨晚無意中翻開more effective c++, 找到了大師的說法:
3.3 Item M3:不要對數(shù)組使用多態(tài)
類繼承的最重要的特性是你可以通過基類指針或引用來操作派生類。這樣的指針或引用具有行為的多態(tài)性,就好像它們同時具有多種形態(tài)。C++允許你通過基類指針和引用來操作派生類數(shù)組。不過這根本就不是一個特性,因為這樣的代碼幾乎從不如你所愿地那樣運行。
假設你有一個類BST(比如是搜索樹對象)和繼承自BST類的派生類BalancedBST:
class BST { ... };
class BalancedBST: public BST { ... };
在一個真實的程序里,這樣的類應該是模板類,但是在這個例子里并不重要,加上模板只會使得代碼更難閱讀。為了便于討論,我們假設BST和BalancedBST只包含int類型數(shù)據(jù)。
有這樣一個函數(shù),它能打印出BST類數(shù)組中每一個BST對象的內容:
- void printBSTArray(ostream& s,
- const BST array[],
- int numElements)
- {
- for (int i = 0; i < numElements; ) {
- s << array[i]; //假設BST類重載了操作符 < <
- }
- }
復制代碼 當你傳遞給該函數(shù)一個含有BST對象的數(shù)組變量時,它能夠正常運行:
BST BSTArray[10];
...
printBSTArray(cout, BSTArray, 10); // 運行正常
然而,請考慮一下,當你把含有BalancedBST對象的數(shù)組變量傳遞給printBSTArray函數(shù)時,會產生什么樣的后果:
- BalancedBST bBSTArray[10];
- ...
- printBSTArray(cout, bBSTArray, 10); // 還會運行正常么?
復制代碼
你的編譯器將會毫無警告地編譯這個函數(shù),但是再看一下這個函數(shù)的循環(huán)代碼:
- for (int i = 0; i < numElements; ) {
- s << array[i];
- }
復制代碼
這里的array[I]只是一個指針算法的縮寫:它所代表的是*(array)。我們知道array是一個指向數(shù)組起始地址的指針,但是array中各元素內存地址與數(shù)組的起始地址的間隔究竟有多大呢?它們的間隔是i*sizeof(一個在數(shù)組里的對象),因為在array數(shù)組[0]到[I]間有I個對象。編譯器為了建立正確遍歷數(shù)組的執(zhí)行代碼,它必須能夠確定數(shù)組中對象的大小,這對編譯器來說是很容易做到的。參數(shù)array被聲明為BST類型,所以array數(shù)組中每一個元素都是BST類型,因此每個元素與數(shù)組起始地址的間隔是i*sizeof(BST)。
至少你的編譯器是這么認為的。但是如果你把一個含有BalancedBST對象的數(shù)組變量傳遞給printBSTArray函數(shù),你的編譯器就會犯錯誤。在這種情況下,編譯器原先已經假設數(shù)組中元素與BST對象的大小一致,但是現(xiàn)在數(shù)組中每一個對象大小卻與BalancedBST一致。派生類的長度通常都比基類要長。我們料想BalancedBST對象長度的比BST長。如果如此的話,printBSTArray函數(shù)生成的指針算法將是錯誤的,沒有人知道如果用BalancedBST數(shù)組來執(zhí)行printBSTArray函數(shù)將會發(fā)生什么樣的后果。不論是什么后果都是令人不愉快的。
如果你試圖刪除一個含有派生類對象的數(shù)組,將會發(fā)生各種各樣的問題。以下是一種你可能采用的但不正確的做法。
//刪除一個數(shù)組, 但是首先記錄一個刪除信息
- void deleteArray(ostream& logStream, BST array[])
- {
- logStream << "Deleting array at address "
- << static_cast<void*>(array) << '\n';
- delete [] array;
- }
- BalancedBST *balTreeArray = // 建立一個BalancedBST對象數(shù)組
- new BalancedBST[50];
- ...
- deleteArray(cout, balTreeArray); // 記錄這個刪除操作
復制代碼
這里面也掩藏著你看不到的指針算法。當一個數(shù)組被刪除時,每一個數(shù)組元素的析構函數(shù)也會被調用。當編譯器遇到這樣的代碼:
delete [] array;
它肯定象這樣生成代碼:
- // 以與構造順序相反的順序來
- // 解構array數(shù)組里的對象
- for ( int i = 數(shù)組元素的個數(shù) 1; i >= 0;--i)
- {
- array[i].BST::~BST(); // 調用 array[i]的
- } // 析構函數(shù)
復制代碼
因為你所編寫的循環(huán)語句根本不能正確運行,所以當編譯成可執(zhí)行代碼后,也不可能正常運行。語言規(guī)范中說通過一個基類指針來刪除一個含有派生類對象的數(shù)組,結果將是不確定的。這實際意味著執(zhí)行這樣的代碼肯定不會有什么好結果。多態(tài)和指針算法不能混合在一起來用,所以數(shù)組與多態(tài)也不能用在一起。
值得注意的是如果你不從一個具體類(concrete classes)(例如BST)派生出另一個具體類(例如BalancedBST),那么你就不太可能犯這種使用多態(tài)性數(shù)組的錯誤。正如條款M33所解釋的,不從具體類派生出具體類有很多好處。我希望你閱讀一下條款M33的內容。
[ 本帖最后由 yulc 于 2007-1-16 11:00 編輯 ] |
|