More Effective C++ 條款28(下) (轉)
條款28:靈巧(smart)指標(下)
譯者注:由於我無法在文件區貼上圖片(在論壇詢問,結果無人回答),所以只能附上此譯文的文件。/FileBBS/files/2001_12/T_967_1.zip">
這種技術能給我們幾乎所有想要的行為特性。假設我們用一個新類CasSingle來擴充MusicProduct類層次,用來表示cassette singles。修改後的類層次看起來象這樣::namespace prefix = o ns = "urn:schemas--com::office" />
現在考慮這段程式碼:
template class SmartPtr { ... }; // 轉換運算子的成員模板 void displayAndPlay(const SmartPtr int howMany); void displayAndPlay(const SmartPtr int howMany); SmartPtr displayAndPlay(dumbMusic, 1); // 錯誤! 在這個例子裡,displayAndPlay被過載,一個帶有 透過成員模板來實現靈巧指標的型別轉換有還有兩個缺點。第一,支援成員模板的編譯器較少,所以這種技術不具有可移植性。以後情況會有所改觀,但是沒有人知道這會等到什麼時候。第二,這種方法的工作原理不很明瞭,要理解它必須先要深入理解函式呼叫的引數匹配,隱式型別轉換函式,模板函式隱式例項化和成員函式模板。有些員以前從來沒有看到過這種技巧,而卻被要求維護使用這種技巧的程式碼,我真是很可憐他們。這種技巧確實很巧妙,這自然是肯定,但是過於的巧妙可是一件危險的事情。 不要再拐彎抹角了,直接了當地說,我們想要知道的是在繼承類向基類進行型別轉換方面,我們如何能夠讓靈巧指標的行為與dumb指標一樣呢?答案很簡單:不可能。正如Daniel Edelson所說,靈巧指標固然靈巧,但不是指標。最好的方法是使用成員模板生成型別轉換函式,在會產生二義性結果的地方使用casts(參見條款2)。這不是一個完美的方法,不過也很不錯,在一些情況下去除二義性,所付出的代價與靈巧指標提供複雜的功能相比還是值得的。 靈巧指標和const 對於dumb指標來說,const既可以針對指標所指向的東西,也可以針對於指標本身,或者兼有兩者的含義(參見Effective C++條款21): CD goodCD("Flood"); const CD *p; // p 是一個non-const 指標 //指向 const CD 物件 CD * const p = &goodCD; // p 是一個const 指標 // 指向non-const CD 物件; // 因為 p 是const, 它 // 必須被初始化 const CD * const p = &goodCD; // p 是一個const 指標 // 指向一個 const CD 物件 我們自然想要讓靈巧指標具有同樣的靈活性。不幸的是只能在一個地方放置const,並只能對指標本身起作用,而不能針對於所指物件: const SmartPtr &goodCD; // 指向 non-const CD 物件 好像有一個簡單的補救方法,就是建立一個指向cosnt CD的靈巧指標: SmartPtr &goodCD; // 指向const CD 物件 現在我們可以建立const和non-const物件和指標的四種不同組合: SmartPtr // non-const 指標 SmartPtr // non-const 指標 const SmartPtr // const指標 const SmartPtr // const 指標 但是美中不足的是,使用dumb指標我們能夠用non-const指標初始化const指標,我們也能用指向non-cosnt物件的指標初始化指向const物件的指標;就像進行賦值一樣。例如: CD *pCD = new CD("Famous MovThemes"); const CD * pConstCD = pCD; // 正確 但是如果我們試圖把這種方法用在靈巧指標上,情況會怎麼樣呢? SmartPtr SmartPtr 包括const的型別轉換是單向的:從non-const到const的轉換是的,但是從const到non-const則不是安全的。而且用const指標能的事情,用non-const指標也能做,但是用non-const指標還能做其它一些事情(例如,賦值操作)。同樣,用指向const的指標能做的任何事情,用指向non-const的指標也能做到,但是用指向non-const的指標能夠完成一些使用指向const的指標所不能完成的事情(例如,賦值操作)。 這些規則看起來與public繼承的規則相類似(Effective C++ 條款35)。你能夠把一個派生類物件轉換成基類物件,但是反之則不是這樣,你對基類所做的任何事情對派生類也能做,但是還能對派生類做另外一些事情。我們能夠利用這一點來實作靈巧指標,就是說可以讓每個指向T的靈巧指標類public派生自一個對應的指向const-T的靈巧指標類: template class SmartPtrToConst { // 靈巧指標 ... // 靈巧指標通常的 // 成員函式 protected: union { const T* constPointee; // 讓 SmartPtrToConst 訪問 T* pointee; // 讓 SmartPtr 訪問 }; }; template class SmartPtr: // 的靈巧指標 public SmartPtrToConst ... // 沒有資料成員 }; 使用這種設計方法,指向non-const-T物件的靈巧指標包含一個指向const-T的dumb指標,指向const-T的靈巧指標需要包含一個指向cosnt-T的dumb指標。最方便的方法是把指向const-T的dumb指標放在基類裡,把指向non-const-T的dumb指標放在派生類裡,然而這樣做有些浪費,因為SmartPtr物件包含兩個dumb指標:一個是從 SmartPtr SmartPtrToConst 評價 有關靈巧指標的討論該結束了,在我們離開這個話題之前,應該問這樣一個問題:靈巧指標如此繁瑣麻煩,是否值得使用,特別是如果你的編譯器缺乏支援成員函式模板時。 經常是值得的。例如透過使用靈巧指標極大地簡化了條款29中的引用計數程式碼。而且正如該例子所顯示的,靈巧指標的使用在一些領域受到極大的限制,例如測試空值、轉換到dumb指標、繼承類向基類轉換和對指向const的指標的支援。同時靈巧指標的實作、理解和維護需要大量的技巧。De使用靈巧指標的程式碼也比Debug使用dumb指標的程式碼困難。無論如何你也不可能設計出一種通用目的的靈巧指標,能夠替代dumb指標。SmartPtr
引數,其它函式的引數為SmartPtr
,我們期望SmartPtr
,因為CasSingle是直接從Cassette上繼承下來的,而它僅僅是間接繼承自MusicProduct。當然這是dumb指標的工作方法,我們的靈巧指標不會這麼靈巧。它們把成員函式做為轉換運算子來使用,就C++而言,所有型別轉換運算子都一樣,沒有好壞的分別。因此displayAndPlay的呼叫具有二義性,因為從SmartPtr
到SmartPtr
的型別轉換並不比到SmartPtr
的型別轉換好。SmartPtr
與SmartPtr
CD>
是完全不同的型別。在編譯器看來,它們是毫不相關的,所以沒有理由相信它們是賦值相容的。到目前為止這是一個老問題了,把它們變成賦值相容的惟一方法是你必須提供函式,用來把SmartPtr
CD>
型別。如果你使用的編譯器支援成員模板,就可以利用前面所說的技巧自動生成你需要的隱式型別轉換操作。(我前面說過,只要對應的dumb指標能進行型別轉換,靈巧指標也就能進行型別轉換,我沒有欺騙你們。包含const型別轉換也沒有問題。)如果你沒有這樣的編譯器,你必須克服更大的困難。SmartPtrToConst
繼承來的,一個是SmartPtr自己的。
一種在C世界裡的老式武器可以解決這個問題,這就是union,它在C++中同樣有用。Union在protected中,所以兩個類都可以訪問它,它包含兩個必須的dumb指標型別,SmartPtrToConst
利用這種新設計,我們能夠獲得所要的行為特性:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991213/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- More Effective C++ 條款28(中) (轉)C++
- More Effective C++ 條款28(上) (轉)C++
- More effective c++ 條款10(下) (轉)C++
- More Effective C++ 條款27(下) (轉)C++
- More Effective C++ 條款26(下) (轉)C++
- More Effective C++ 條款4 (轉)C++
- More Effective C++ 條款19 (轉)C++
- More Effective C++ 條款6 (轉)C++
- More effective C++ 條款14 (轉)C++
- More Effective C++ 條款15 (轉)C++
- More Effective C++ 條款2 (轉)C++
- More Effective C++ 條款3 (轉)C++
- More Effective C++ 條款11 (轉)C++
- More effective C++ 條款13 (轉)C++
- More effective C++ 條款12 (轉)C++
- More Effective C++ 條款5 (轉)C++
- More Effective C++ 條款一 (轉)C++
- More Effective C++ 條款17 (轉)C++
- More Effective C++ 條款18 (轉)C++
- More Effective C++ 條款20 (轉)C++
- More Effective C++ 條款21 (轉)C++
- More Effective C++ 條款22 (轉)C++
- More Effective C++ 條款23 (轉)C++
- More Effective C++ 條款24 (轉)C++
- More Effective C++ 條款25 (轉)C++
- More Effective C++ 條款7 (轉)C++
- More Effective C++ 條款8 (轉)C++
- More effective c++ 條款10(上) (轉)C++
- Effective Modern C++ 系列之 條款2: autoC++
- Effective C++ 條款08_不止於此C++
- Effective c++條款11:在operator=中處理“自我賦值”C++賦值
- Guru of the Week 條款28:“Fast Pimpl”技術 (轉)AST
- [讀書筆記][effective C++]條款30-inline的原理筆記C++inline
- Effective C++: Item 32 (轉)C++
- Effective C++: Item 21 (轉)C++
- Effective C++: Item 24 (轉)C++
- more effective entity bean(新的改進entity bean的效能的七條(EJB2.0版)) (轉)Bean
- Effective STL之條款2:謹防容器無關程式碼的假象 (轉)