不要對陣列使用多型
類繼承的最重要的特性是你可以通過基類指標或引用來操作派生類。這樣的指標或引用具有行為的多型性,就好像它們同時具有多種形態。c++允許你通過基類指標和引用來操作派生類陣列。不過這根本就不是乙個特性,因為這樣的**幾乎從不如你所願地那樣執行。
假設你有乙個類bst(比如是搜尋樹物件)和繼承自bst類的派生類balancedbst:
class有這樣乙個函式,它能列印出bst類陣列中每乙個bst物件的內容:bst ;
class
balancedbst:
public
bst ;
void當你傳遞給該函式乙個含有bst物件的陣列變數時,它能夠正常執行:printbstarray(ostream
&s,
const
bst array,
intnumelements) //
過載了操作符<<
}
bst bstarray[然而,請考慮一下,當你把含有balancedbst物件的陣列變數傳遞給printbstarray函式時,會產生什麼樣的後果:10];
...printbstarray(cout, bstarray,
10);
//執行正常
balancedbst bbstarray[你的編譯器將會毫無警告地編譯這個函式,但是再看一下這個函式的迴圈**:10];
...printbstarray(cout, bbstarray,
10);
//還會執行正常麼?
for這裡的array[i]只是乙個指標演算法的縮寫:它所代表的是*(array)。我們知道array是乙個指向陣列起始位址的指標,但是array中各元素記憶體位址與陣列的起始位址的間隔究竟有多大呢?它們的間隔是i*sizeof(乙個在陣列裡的物件),因為在array陣列[0]到[i]間有i個物件。編譯器為了建立正確遍歷陣列的執行**,它必須能夠確定陣列中物件的大小,這對編譯器來說是很容易做到的。引數array被宣告為bst型別,所以array陣列中每乙個元素都是bst型別,因此每個元素與陣列起始位址的間隔是i*sizeof(bst)。(inti =
0; i
<
numelements; )
至少你的編譯器是這麼認為的。但是如果你把乙個含有balancedbst物件的陣列變數傳遞給printbstarray函式,你的編譯器就會犯錯誤。在這種情況下,編譯器原先已經假設陣列中元素與bst物件的大小一致,但是現在陣列中每乙個物件大小卻與balancedbst一致。派生類的長度通常都比基類要長。我們料想balancedbst物件長度的比bst長。如果如此的話,printbstarray函式生成的指標演算法將是錯誤的,沒有人知道如果用balancedbst陣列來執行printbstarray函式將會發生什麼樣的後果。不論是什麼後果都是令人不愉快的。
如果你試圖刪除乙個含有派生類物件的陣列,將會發生各種各樣的問題。以下是一種你可能採用的但不正確的做法。
//刪除乙個陣列, 但是首先記錄乙個刪除資訊
void
deletearray(ostream
&logstream, bst array)
balancedbst這裡面也掩藏著你看不到的指標演算法。當乙個陣列被刪除時,每乙個陣列元素的析構函式也會被呼叫。當編譯器遇到這樣的**:*baltreearray =//
建立乙個balancedbst物件陣列
newbalancedbst[
50];
...deletearray(cout, baltreearray);
//記錄這個刪除操作
delete array;它肯定象這樣生成**:
//因為你所編寫的迴圈語句根本不能正確執行,所以當編譯成可執行**後,也不可能正常執行。語言規範中說通過乙個基類指標來刪除乙個含有派生類物件的陣列,結果將是不確定的。這實際意味著執行這樣的**肯定不會有什麼好結果。多型和指標演算法不能混合在一起來用,所以陣列與多型也不能用在一起。以與構造順序相反的順序來
//解構array陣列裡的物件
for(
inti
=陣列元素的個數
1; i
>=0;
--i) //
析構函式
值得注意的是如果你不從乙個具體類(concrete classes)(例如bst)派生出另乙個具體類(例如balancedbst),那麼你就不太可能犯這種使用多型性陣列的錯誤。
不要對陣列和指標運算使用多型
先看下面的程式 includeusing namespace std class animal animal char tmp virtual animal friend ostream operator display wtarray,3 將派生類陣列傳遞給display函式,陣列名退化為指標,即...
Item M3 不要對陣列使用多型 無責任書評
其實是 more effective c 書上的,並非原文照搬,而是刪減無關的內容,補充了一些事實和看法。類繼承的最重要的特性是你可以通過基類指標或引用來操作派生類。這樣的指標或引用具有行為的多型性,就好像它們同時具有多種形態。c 允許你通過基類指標和引用來操作派生類陣列。不過這根本就不是乙個特性,...
不要使用多型性陣列
類繼承的最重要的特性是你可以通過基類指標或引用來操作派生類。這樣的指標或引用具有行為的多型性,就好像它們同時具有多種形態。c 允許你通過基類指標和引用來操作派生類陣列。不過這根本就不是乙個特性,因為這樣的 根本無法如你所願地那樣執行。假設你有乙個類bst 比如是搜尋樹物件 和繼承自bst類的派生類b...