欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++學習筆記之pimpl用法詳解

 更新時間:2017年08月31日 10:44:15   作者:taozj  
在編寫穩(wěn)定代碼是,管理好代碼間的依賴性是不可缺少的一個環(huán)節(jié)。特別是庫文件的編寫中,減少代碼間的依賴性可以提供一個“干凈”的接口。下面這篇文章主要給大家介紹了關(guān)于C++中pimpl用法的相關(guān)資料,需要的朋友可以參考下。

前言

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

  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)類的成員可以隨意變更,而公有類的使用者不需要重新編譯。

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)的比較無趣和雜亂,而且無法被繼承復用。

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

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

  b. 顯式定義復制語義,創(chuàng)建新的實現(xiàn)類對象,執(zhí)行深度復制操作。此處需要記住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)容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • C++實現(xiàn)PyMysql的基本功能實例詳解

    C++實現(xiàn)PyMysql的基本功能實例詳解

    這篇文章主要介紹了C++實現(xiàn)PyMysql的基本功能,本文通過實例代碼給大家介紹的非常詳細,對大家的工作或?qū)W習有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • C語言實現(xiàn)班級成績管理系統(tǒng)

    C語言實現(xiàn)班級成績管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)班級成績管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • C++11 寫一個只觸發(fā)一次槽函數(shù)的Qt connect函數(shù)

    C++11 寫一個只觸發(fā)一次槽函數(shù)的Qt connect函數(shù)

    這篇文章主要為大家介紹了C++11 寫一個只觸發(fā)一次槽函數(shù)的Qt connect函數(shù)實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • C++中的數(shù)據(jù)內(nèi)存分布原理

    C++中的數(shù)據(jù)內(nèi)存分布原理

    這篇文章主要介紹了C++中的數(shù)據(jù)內(nèi)存分布,主要從動態(tài)內(nèi)存管理方式,內(nèi)存泄漏等方面介紹的,文中也有相關(guān)的示例代碼,需要的朋友可以參考下
    2023-05-05
  • VS2017中配置QT5.12.0的圖文教程

    VS2017中配置QT5.12.0的圖文教程

    本文主要介紹了VS2017中配置QT5.12.0的圖文教程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • C語言實現(xiàn)三子棋游戲含完整代碼

    C語言實現(xiàn)三子棋游戲含完整代碼

    本文詳細講解了C語言實現(xiàn)三子棋游戲內(nèi)含完整代碼,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11
  • C++中的動態(tài)分派在HotSpot?VM中的應(yīng)用小結(jié)

    C++中的動態(tài)分派在HotSpot?VM中的應(yīng)用小結(jié)

    多態(tài)是面向?qū)ο缶幊陶Z言的重要特性,它允許基類的指針或引用指向派生類的對象,而在具體訪問時實現(xiàn)方法的動態(tài)綁定,這篇文章主要介紹了C++的動態(tài)分派在HotSpot?VM中的重要應(yīng)用,需要的朋友可以參考下
    2023-09-09
  • C++如何將運行結(jié)果保存到txt中

    C++如何將運行結(jié)果保存到txt中

    這篇文章主要介紹了C++如何將運行結(jié)果保存到txt中問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C++實現(xiàn)十進制數(shù)轉(zhuǎn)換為二進制數(shù)的數(shù)學算法

    C++實現(xiàn)十進制數(shù)轉(zhuǎn)換為二進制數(shù)的數(shù)學算法

    這篇文章和大家分享一下我個人對十進制數(shù)轉(zhuǎn)換為二進制數(shù)的想法,目前暫時更新只整數(shù)十進制的轉(zhuǎn)換,后續(xù)會更新帶有小數(shù)的進制轉(zhuǎn)換,代碼使用c++實現(xiàn)
    2021-09-09
  • C語言斷言函數(shù)assert()的學習筆記

    C語言斷言函數(shù)assert()的學習筆記

    在C語言庫函數(shù)中提供了一個輔助調(diào)試程序的小型庫,它是由assert()宏組成,本文就詳細的介紹了一下如何使用,感興趣的可以了解一下
    2021-11-11

最新評論