Guru of the Week 條款24:編譯級防火牆 (轉)
[CAT*G Translation Project GotW#22-30: Draft]
GotW #24 Compilation s
著者:Herb Sutter
翻譯:CAT*G
[宣告]:本文內容取自網站上的Guru of the Week欄目,其著作權歸原著者本人所有。譯者CAT*G在未經原著者本人同意的情況下翻譯本文。本翻譯內容僅供自學和參考用,請所有閱讀過本文的人不要擅自轉載、傳播本翻譯內容;本翻譯內容的人請在閱讀瀏覽後,立即刪除其。譯者CAT*G對違反上述兩條原則的人不負任何責任。特此宣告。
Revision 1.0
Guru of the Week 條款24:編譯級
難度:6 / 10
(使用pimpl慣用法可以大大降低程式碼之間的相互依賴性,還可以減少的建立時間。但問題是,應該把那些東西放入pimpl裡呢?如何才能的使用它呢?)
[Problem]
[問題]
在C++中,如果類定義中的任何部分被改變了(即使是私有成員),那麼這個類所有的使用者代媽都必須重新編譯。為了降低這種依賴性,使用的一種常見的技術就是利用一個不透明指標(opaque pointer)來隱藏一部分實現細節:
class X {
public:
/* ... 公有成員 ... */
protected:
/* ... 保護成員?... */
private:
/* ... 私有成員?... */
class XImpl* pimpl_; // 指向一個被前置宣告瞭的(forward-declared)類
// 之不透明指標
};
[Questions]
[提問]
1.那些部分應該放入Ximpl?有四種常見的原則,它們是:
- 將全部私有資料(但不是)放入Ximpl;
- 將全部私有成員(譯註:即包括函式)放入Ximpl;
- 將全部私有成員和保護成員放入Ximpl;
- 使Ximpl完全成為原來的X,將X編寫為一個完全由簡單的前置函式(forwarding functions)(一個控制程式碼/本體的變體)組成的公共介面。
它們各有什麼優缺點?你如何從中選擇合適的?
2.Ximpl需要一個指向X物件的"反向指標(back pointer)"嗎?
[Solution]
[解答]
首先看兩個定義:
可見類(visible class):客戶代嗎所見並操縱的類(在這裡即是X)。
pimpl:可見類中隱藏在一個透明指標(也稱為pimpl_)下的類實現(在這裡即是XImpl)。
在C++中,如果類定義中的任何部分被改變了(即使是私有成員),那麼這個類所有的使用者代媽都必須重新編譯。為了降低這種依賴性,使用的一種常見的技術就是利用一個不透明指標(opaque pointer)來隱藏一部分實現細節:
這是"控制程式碼/本體"慣用法(handle/body idiom)的一種變體。如Coplien[注1]所記載,這種方法主要用於在共享程式碼的情況下進行引用計數(reference counting)。
正如Lakos[注2]所指出的那樣,"控制程式碼/本體"慣用法(表現為我所稱為的"pimpl慣用法"之形式;這樣的叫法緣自給其特意取的、易發音的"pimpl_"指標[注3])對於打破編譯期的依賴性也是非常有用的。本條款的解答集中討論這種用法,其中有些討論總的來講並不適從於"控制程式碼/本體"慣用法。
使用這個慣用法的主要代價是:
1.每一個構造操作都須分配。自己定製的分配器(custom allocator)或許可以緩解記憶體的額外消耗,但這還不是涉及到更多的工作。
2.每一個隱藏成員都需要一個額外的間接層來予以對其訪問。(如果被訪問的隱藏成員本身又使用到了一個"反向指標(back pointer)"來可見類中的函式,那麼就會有雙重的間接性。)
1.那些部分應該放入Ximpl?有四種常見的原則,它們是:
- 將全部私有資料(但不是函式)放入Ximpl;
這是個不錯的開端,因為現在我們得以對任何只用作資料成員的類進行前置宣告(forward-declare)(而不是使用#include語句來包含類的真正宣告--這會使客戶程式碼對其形成依賴)。當然,我們通常可以做得更好。
- 將全部私有成員(譯註:即包括函式)放入Ximpl;
這(幾乎)是我平常的用法。不管怎麼說,在C++中,"客戶程式碼不應該也並不關心這些部分"就意味著"私有(private)",而私有的東西則最好藏起來(在一些擁有更"自由寬大"之法律的北歐國家裡的情況除外)。
對此有兩條警告,其中的第一個也就是我在上一段中加上"almost"的原因:
1.即使虛擬函式是私有的,你也不能把虛擬成員函式隱藏在pimpl類中。如果想要虛擬函式覆寫基類中的同名虛擬函式,那麼該虛擬函式就必須出現在真正的派生類中。如果虛擬函式不是繼承而來的,那麼為了讓之後層級的派生類能夠覆寫它,其還是必須出現在可見類中。
2.如果pimpl中的函式要使用其它函式,其可能需要一個指向可見物件的"反向指標(back pointer)"--這又增加了一層間接性。這個反向指標通常被約定俗成的稱為self_。
- 將全部私有成員和保護成員放入Ximpl;
如此更進一步的做法其實是錯誤的。保護成員(protected members)絕不應該被放進pimpl,因為這樣做等於就是對其棄之不用。無論如何,保護成員(protected members)正是為了讓派生類看到並使用而存在的,因此如果派生類無法看到或使用它們的話,它們也就基本上全無用處了。
- 使Ximpl完全成為原來的X,將X編寫為一個完全由簡單的前置函式(forwarding functions)(一個控制程式碼/本體的變體)組成的公共介面。
這隻在少數幾個有限的情況下有用,其好處是可以避免使用反向指標,因為所有的服務全部都在pimpl類之中提供了。其主要的缺點是,這樣做一般會使得可見類對於繼承而言全無用處,無論是作為基類還是派生類。
2.Ximpl需要一個指向X物件的"反向指標(back pointer)"嗎?
很不幸,回答通常為"是的"。無論如何,我們會把每一個物件分裂成兩部分--只因為我們要隱藏其中一部分。
當可見類中的函式被呼叫的時候,經常需要使用隱藏部分(譯註:即pimpl部分)中的一些函式和資料,以便完成是呼叫著的請求。這挺好,也很合理。然而可能不太明顯的情況是:在pimpl中的函式也經常必須呼叫可見類中的函式--通常是因為需要呼叫的函式是公有成員或虛擬函式。
[注1]:James O. Coplien. Advanced C++ Programming Styles and Idioms (Addison-Wesley, 1992).
[注2]:J. Lakos. Large-Scale C++ Software Design (Addison-Wesley, 1996).
[注3]:我以前經常將其寫作impl_。與其等價的pimpl_寫法其實是有我的朋友和同事Jeff Sumner提出的;Jeff Sumner同我一樣對用於指標變數的匈牙利式"p"字首(譯註:即用於命名變數的匈牙利表示法;在該表示法中,指標變數名以"p"開頭,意即"pointer")頗為傾心,另外其還對恐怖的雙關語有著獨到的敏感(譯註:pimpl發音與單詞"pimple(意即痤瘡、丘疹、膿皰、疙瘩、粉刺)"相同)。
(完)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991108/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Guru of the Week 條款07:編譯期的依賴性 (轉)編譯
- Guru of the Week 條款19:自動轉換 (轉)
- Guru of the Week 條款27:轉呼叫函式 (轉)函式
- Guru of the Week 條款28:“Fast Pimpl”技術 (轉)AST
- Guru of the Week 條款09:記憶體管理(上篇) (轉)記憶體
- Guru of the Week 條款10:記憶體管理(下篇) (轉)記憶體
- Guru of the Week 條款30附錄:介面原則 (轉)
- Guru of the Week 條款05:覆寫虛擬函式 (轉)函式
- Guru of the Week 條款13:物件導向程式設計 (轉)物件程式設計
- Guru of the Week 條款11:物件等同(Object Identity)問題 (轉)物件ObjectIDE
- Guru of the Week 條款14:類之間的關係(上篇) (轉)
- Guru of the Week 條款15:類之間的關係(下篇) (轉)
- Guru of the Week 條款16:具有最大可複用性的通用Containers (轉)AI
- Guru of the Week 條款08:GotW挑戰篇——異常處理的安全性 (轉)Go
- Guru of the Week 條款23:物件的生存期(第二部分) (轉)物件
- Guru of the Week 條款22:物件的生存期(第一部分) (轉)物件
- Guru of the Week 條款21:程式碼的複雜性(第二部分) (轉)
- C++ articles:Guru of the Week #1 (轉)C++
- Guru of the week:#18 迭代指標. (轉)指標
- Guru of the Week 條款20:程式碼的複雜性(第一部分) (轉)
- Guru of the week:#17 型別對映. (轉)型別
- Guru of the week:#19 自動型別轉換. (轉)型別
- 八種防火牆產品評測(企業級防火牆)(轉)防火牆
- C++ articles:Guru of the Week #4 -- Class Mechantics (轉)C++
- Guru of The week #20 程式碼的複雜性 Ⅰ. (轉)
- More Effective C++ 條款24 (轉)C++
- C++ articles:Guru of the Week #3:使用標準庫 (轉)C++
- Linux防火牆配置初級入門(轉)Linux防火牆
- Guru of the Week #5:虛擬函式的重新定義 (轉)函式
- 全面分析防火牆及防火牆的滲透(轉)防火牆
- 企業級防火牆的七問七答(轉)防火牆
- 20條IPTables防火牆規則用法!防火牆
- 選用單防火牆DMZ還是雙防火牆DMZ(轉)防火牆
- Juniper防火牆簡介(轉)防火牆
- 防火牆介紹(1)(轉)防火牆
- 防火牆介紹(2)(轉)防火牆
- 動態 iptables 防火牆(轉)防火牆
- NAT iptables防火牆(script)(轉)防火牆