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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 20條IPTables防火牆規則用法!防火牆
- WAb防火牆與傳統防火牆防火牆
- 防火牆防火牆
- 完全私有化部署!一款開源輕量級網站防火牆!網站防火牆
- 雲防火牆如何玩轉公有云引流防火牆
- 防火牆入侵於檢測——————3、思科 PIX 防火牆和 ASA 防火牆產品線防火牆
- 防火牆iptables防火牆
- 防火牆配置防火牆
- 防火牆(firewall)防火牆
- iptables防火牆防火牆
- 【推薦】4款Linux開源防火牆軟體!Linux防火牆
- 超級實用的 iptables 防火牆指令碼防火牆指令碼
- 資料庫防火牆商業化的前提條件資料庫防火牆
- Rust 條件編譯Rust編譯
- 五款實用性非常高的Linux防火牆工具!Linux防火牆
- 體驗iptables 企業級的防火牆實戰防火牆
- 24暑集訓Week1
- Linux配置防火牆Linux防火牆
- 防火牆部署案例防火牆
- Linux防火牆命令Linux防火牆
- 防火牆介紹防火牆
- LINUX 防火牆 firewalldLinux防火牆
- CentOS 防火牆操作CentOS防火牆
- CentOS 7.0防火牆CentOS防火牆
- Rust 交叉編譯與條件編譯總結Rust編譯
- ubuntu 關閉防火牆命令 ubuntu怎樣關閉防火牆Ubuntu防火牆
- 高 級防火牆軟體 Vallum啟用最新版防火牆
- 超級好用的mac防火牆軟體:Little Snitch for MacMac防火牆
- 防火牆 搜尋 釋出 防火牆是什麼?怎麼理解?防火牆
- iptables防火牆簡介,原理,規則編寫,常見案例防火牆
- CentOS防火牆設定CentOS防火牆
- 防火牆的分類防火牆
- Linux防火牆基礎Linux防火牆
- Firewalld防火牆基礎防火牆
- 資料庫防火牆資料庫防火牆
- Iptables防火牆應用防火牆
- CentOS 7 防火牆操作CentOS防火牆
- Linux 防火牆配置使用Linux防火牆
- iptables防火牆規則防火牆