Symbian OS 中的Class命名約定(C類)
C前綴[1]的類皆由CBase類(定義于e32base.h)派生(直接或間接)。CBase類通過繼承確保了所有的C類都具有如下兩個特征。
首先,CBase有一個虛析構函數(shù),所以C類對象都應該通過刪除CBase的指針進行銷毀。通常清潔棧就使用這一方法,在將C類對象壓入清潔棧時需要重載調(diào)用CCleanupStack::PushL(CBase* aPtr)函數(shù)。
如果對對象調(diào)用CCleanupStack::PopAndDestroy()(或在發(fā)生leave時),對象會通過刪除CBase指針被刪除。 CBase 的虛析構函數(shù)確保了對派生類的析構函數(shù)的正序調(diào)用(由***層派生類起,逐層向上調(diào)用)。所以應當認識到,C類在這一點上有別于T類,它們通常都有一個析構函數(shù)。
還有一點需要注意的是,如果需要將非CBase的派生類壓入清潔棧,將重載 CCleanupStack::PushL(TAny*aPtr)函數(shù)而不是CCleanupStack::PushL(CBase* aPtr)。正象上面說的那樣,當調(diào)用PopAndDestroy()或發(fā)生leave時,將會釋放對象的內(nèi)存但并不會調(diào)用對象的析構函數(shù)。所以如果不直接或間接地繼承CBase類,即使你的基類有一個虛析構函數(shù),你的類的對象也不會象你所期待
1這里可能讓你覺得詫異,'C'表示'Class','C class'多少讓人覺得有點羅嗦,但以T類的"Type'作為參照系,'C class'是一個正確的表示方法。
的那樣可以順利清除。
CBase 類及其派生類的第二個特征,是當***在heap上建立對象時,將重載new操作符來對對象進行零初始化。這意味著C類對象的所有數(shù)據(jù)成員在***創(chuàng)建時皆為零。而不必由你親自在構造函數(shù)中顯式地進行這項工作。因為stack的分配不使用new操作符,所以零初始化也就不會在stack對象上發(fā)生作用。這間接的導致了基于heap的零初始化和基于stack的非零始化的不同行為。由于這一原因,特別就leave發(fā)生時的清潔處理而言,C類對象必須在heap上進行分配。
顯而易見,基于heap的對象在失去使用價值后必須銷毀。C類對象通常作為另一個類的指針成員或局部指針變量使用。如果C類對象是一個成員變量,則應在C 類的所有者的析構函數(shù)中使用delete操作來銷毀。如果是一個臨時性的局部指針變量,那么必須在任何可能產(chǎn)生leave的代碼之前將其壓入清潔?!駝t一旦發(fā)生leave就會導致內(nèi)存泄露。第3章將詳細論述這一問題。
如果觀察一下e32base.h,你將注意到CBase聲明了一個private的復制構造函數(shù)和賦值運算符。這是一個較常用的策略,可以防止用戶意外地 C類對象進行淺表復制(shallow copy)。如果一定要對你的類進行復制操作,那么必須顯式聲明并定義一個public復制構造函數(shù)和賦值運算符,因為在基類中復制構造函數(shù)和賦值運算符被聲明為private,所以不能進行隱式調(diào)用。但是,一個深層復制(deep copy)有可能導致潛在的leave發(fā)生,而就C類的本性而言,你又決不能允許在一個構造(或析構)函數(shù)中產(chǎn)生leave(參見第4章)。所以如果需要為C類提供復制操作,就不要定義并實現(xiàn)一個公共的復制構造函數(shù),而應加入一個允許leave的函數(shù),例如CloneL()或CopyL(),這樣既遵守了 C類的規(guī)則同時又完成了復制操作的任務。
因為大多數(shù)C類往往不足以直接提供逐位復制,所以***避免隱式復制,這是派生于CBase的另外一個優(yōu)點。CBase類中的復制構造函數(shù)和賦值操作符的private聲明意味著你可以不必在每個C類中都親自聲明它們,以防止這種具有潛在危險的淺表復制。
基本原則----C類對象必須基于heap分配
【編輯推薦】