C++學(xué)習(xí)筆記之pimpl用法詳解

前言

創(chuàng)新互聯(lián)建站是一家集網(wǎng)站建設(shè),驛城企業(yè)網(wǎng)站建設(shè),驛城品牌網(wǎng)站建設(shè),網(wǎng)站定制,驛城網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,驛城網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。

本文主要給大家介紹了關(guān)于C++中pimpl用法的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細的介紹:

C++的pImpl可以說是最常見的慣用手法了,在很多的C++項目和C++開發(fā)庫中都有所見。plmp的縮寫就是Pointer to Implementor,顧名思義就是將真正的實現(xiàn)細節(jié)的Implementor從類定義的頭文件中分離出去,公有類通過一個私有指針指向隱藏的實現(xiàn)類,是促進接口和實現(xiàn)分離的重要機制。

在C++語言中,要定義某個類型的變量或者使用類型的某個成員,就必須知道這個類的完整定義,其例外情況是:如果定義這個類型的指針,或者該類型是函數(shù)的參數(shù)或者返回類型(即使是傳值類型的),那么就可以通過前置聲明引入這個類型的名字,而不需要提供暴露其完整的類型定義,從而類型的完整定義可以被隱藏在其他hpp頭文件或者cpp實現(xiàn)文件中,而這個指針也被稱為不透明指針(opaque pointer)。通常的pImp的手法是在API的頭文件中提供接口類的定義以及實現(xiàn)類的前置聲明,實現(xiàn)類的本身定義和成員函數(shù)的實現(xiàn)都隱藏在cpp文件中去,同時為了避免實現(xiàn)類的符號污染外部名字空間,實現(xiàn)類大多作為接口類的內(nèi)部嵌套類的形式。

一、pImpl手法的優(yōu)勢和目的

1.1 信息隱蔽

私有成員完全可以隱藏在共有接口之外,尤其對于閉源API的設(shè)計尤其的適合。同時,很多代碼會應(yīng)用平臺依賴相關(guān)的宏控制,這些瑣碎的東西也完全可以隱藏在實現(xiàn)類當中,給用戶一個間接明了的使用接口再好不過了。

1.2 加速編譯

這通常是用pImpl手法的最重要的收益,稱之為編譯防火墻(compilation firewall),主要是阻斷了類的實現(xiàn)和類的實現(xiàn)兩者的編譯依賴性。這樣,類用戶不需要額外include不必要的頭文件,同時實現(xiàn)類的成員可以隨意變更,而公有類的使用者不需要重新編譯。

C++學(xué)習(xí)筆記之pimpl用法詳解

1.3 更好的二進制兼容性

承接上面說的,通常對一個類的修改,會影響到類的大小、對象的表示和布局等信息,那么任何該類的用戶都需要重新編譯才行。而且即使更新的是外部不可訪問的private部分,雖然從訪問性來說此時只有類成員和友元能否訪問類的私有部分,但是由于C++的特性是名字查找先于名字查找和重載解析的(即使不可訪問也會返回調(diào)用失敗,而不是視而不見),私有部分的修改也會影響到類使用者的行為,這也迫使類的使用者需要重新編譯。而對于使用pImpl手法,如果實現(xiàn)變更被限制在實現(xiàn)類中,那公有類只持有一個實現(xiàn)類的指針,所以實現(xiàn)做出重大變更的情況下,pImpl也能夠保證良好的二進制兼容性。

因此,獨立和自由是pImpl的精髓所在。

1.4 惰性分配

實現(xiàn)類可以做到按需分配或者實際使用時候再分配,從而節(jié)省資源提高響應(yīng)。如果你意識到這點了,那是很不錯的。

二、公有類和實現(xiàn)類的隔離程度

由于公有類是實現(xiàn)類的抽象,實現(xiàn)類是公有類的封裝隱藏,推薦的隔離方式是:將所有非virtual的private成員都放置到impl中去,同時將private成員函數(shù)需要調(diào)用的公有函數(shù)也放置到impl中去,virtual函數(shù)和protected的成員不應(yīng)當放到impl中去。

protected的成員放到impl中沒有任何的意義,因為protected是相對于繼承關(guān)系而生效的;同樣的,virtual成員也不應(yīng)該放到impl中去,因為virtual函數(shù)需要被繼承鏈中的派生類去override。這里需要提到,virtual函數(shù)也可以是private的,函數(shù)的virtual和access兩者是正交毫無關(guān)聯(lián)的,即使派生類無法訪問基類的虛函數(shù),但是派生類仍然可以override基類的虛函數(shù)!這引出了一個Template Method的設(shè)計模式。

將private函數(shù)需要調(diào)用到的public方法也放到impl中去,是為了避免下面所描述的back pointer帶來開銷的妥協(xié)。當然,還有一種極端的方式是除此以外將所有的public成員都丟到impl中去,那么公有類就相當于一個接口類,進而所有接口都需要一個wrapper進行調(diào)用的轉(zhuǎn)發(fā),此時公有類會實現(xiàn)的比較無趣和雜亂,而且無法被繼承復(fù)用。

三、pImpl實現(xiàn)需要注意事項

3.1 資源管理

盡可能避免的使用原始指針來創(chuàng)建和delete釋放實現(xiàn)類對象,使用boost::scoped_ptr或者std::unique_ptr來管理實現(xiàn)類對象,而且如果確實需要實現(xiàn)類共享,可以使用boost::shared_ptr來管理。同時scoped_ptr、unique_ptr實現(xiàn)上要比shared_ptr高效的多。

如果使用智能指針管理實現(xiàn)類對象的話,使用unique_ptr則需要手動在實現(xiàn)文件中定義共有類的析構(gòu)函數(shù),這是因為雖然unique_ptr和shared_ptr都可以在類型不完全的情況下定義其智能指針,但是unique_ptr其析構(gòu)函數(shù)則需要具有持有類型的完全定義,而shared_ptr比較智能則沒有這個限制。

3.2 拷貝語義

pImpl最需要關(guān)注的就是共有類的復(fù)制語義,因為實現(xiàn)類是以指針的方式作為共有類的一個成員,而默認C++生成的拷貝操作只會執(zhí)行對象的淺復(fù)制,這顯然違背了pImpl的原本意圖,除非是真的想要底層共享一個實現(xiàn)對象。針對這個問題,解決方式有:

a. 禁止復(fù)制操作,將所有的復(fù)制操作定義為private的,或者繼承boost::noncopyable,或者在新標準中將這些復(fù)制操作定義為delete的即刻;

b. 顯式定義復(fù)制語義,創(chuàng)建新的實現(xiàn)類對象,執(zhí)行深度復(fù)制操作。此處需要記住0-3-5法則哦,要么不定義拷貝、移動操作符,要定義就需要將他們?nèi)恐匦露x。

3.3 impl對公有類的反向引用

實現(xiàn)類中的私有成員如果需要訪問公有類的公共、保護的成員,就必須要能夠引用到公有類對象,實現(xiàn)其手段有:

a. impl持有一個對公有類對象的指針或者引用。雖然方便但是往往會有問題:如果持有的是引用,則拷貝賦值就難以實現(xiàn),如果持有的是指針,則需要小心指針有效性的同步負擔(比如移動操作)。

b. 推薦的方式,是impl中的這些函數(shù)都增加一個對公有類的引用或者指針,那么其調(diào)用方法類似于:

pimpl->func(this, params);

3.4 pImpl手法的缺點:

a. 該手法需要在調(diào)用和實現(xiàn)之間插入了一個指針,公有類在訪問私有成員的時候都需要增加mImpl->前綴的方式,使用、閱讀和調(diào)試都可能有所不便;

b. pImpl對拷貝操作比較敏感,要么你禁止拷貝操作,要么就需要自定義拷貝操作;

c. 編譯器將不再能夠捕獲const方法中對成員變量的修改,因為私有成員變量已經(jīng)從公有類脫離到了實現(xiàn)類當中了,公有類的const只能保護指針值本身是否改變,而不再能進一步保護其所指向的數(shù)據(jù)。如果要達到類似的保護效果,可以使用std::experimental::propagate_const技術(shù)。

pImpl是一個很重要、實用的編程技巧,強烈建議掌握之!

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對創(chuàng)新互聯(lián)的支持。

網(wǎng)頁題目:C++學(xué)習(xí)筆記之pimpl用法詳解
轉(zhuǎn)載注明:http://muchs.cn/article36/jpdgpg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)品牌網(wǎng)站制作、品牌網(wǎng)站建設(shè)App設(shè)計、定制網(wǎng)站、

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化