條款31:將檔案間的編譯依存關係降至最低
(minimize compilation dependencies between files.)
內容:在你們的開發團隊中,一些有經驗的工程師時不時地會教導新手一些基本的程式設計原則,其中"將介面從實現中
分離"可能是他(她)要你必須牢記原則,因為c++並沒有把它做的很好,這只能靠我們在平時的編寫**中注意這
一點了,如果你不小心違背了這一原則,可能招致的後果就是:當你輕微的修改了某個類的實現,注意不是介面的
時候,再次重新build一次你的工程,oh,my god!很多檔案被重新編譯和鏈結了,build的時間大大超出你的預期,
而這種事情的發生,估計你當時就會只恨編譯器的build的速度太慢,效率太低.呵呵.避免陷入這種窘境的一種有
效的方法就是本條款要提出的內容:將檔案間的編譯依存關係降至最低.
現在假設你寫了乙個person類,一般你會這麼構思你的**:
#include
#include "date.h"
#include "address.h"
class person;
這樣寫顯然在person定義檔案和其含入檔案之間形成了一種編譯依存關係(compilation dependency).
可能就會導致開頭我們提到的使你陷入窘境的情形出現.所以這裡我們採取了另外一種實現方式,即將物件
實現細則隱藏與乙個指標背後.具體這樣做:把person類分割為兩個類,乙個只提供介面,另乙個負責實現該
介面.//person.h
#include
#include
using std::string;
class date;
class address;
class person;
//person.cpp
#include "person.h"
struct person:impl
string name()const
...string thename_;
date thebirthdate_;
address theaddress_;
};person::person(const string& name,const date& birthday,const address& addr)
:pimpl_(new impl(name,birthday,addr))
string person::name()const
...
以上這種設計常被稱為pimpl idiom("pointer to implementation"),而這種class往往被稱為handle classes
這樣任何實現修改都不需要person客戶端的重新編譯,此外由於客戶無法看到person的實現細目,也就不可能
寫出什麼"取決於那些細目"的**.這是真正的"介面與實現的分離"!這裡的關鍵在於以
"宣告的依存性"替換"定義的依存性",那正是編譯依存性最小化的本質:現實中讓頭文
件盡可能的自我滿足,萬一做不到,則讓它與其他檔案內的宣告式相依.其他每一件事都源自這個簡單的設計
策略:(1)如果使用object references或object pointers可以完成任務,就不要使用objects.
(2)如果能夠,盡量以class宣告式替換class定義式.
(3)為宣告式和定義式提供不同的標頭檔案.(在模板類中常用到.)
另乙個製作handle class的辦法是,令person成為一種特殊的abstract base class稱之為inte***ce
class.這種class只有乙個virtual析構函式以及一組pure virtual函式,用來敘述整個介面.乙個針對person而
寫的inte***ce class或許看起來這樣:
//person.h
...using std::string;
class date;
class address;
class person;
...//person.cpp
...class realperson:public person
string name()const;
...private:
string name_;
date thebirthdate_;
address theaddress_;
};std::tr1::shared_ptrperson::create(const string& name,
const date& birthday,
const address& addr)
handle classes和inte***ce classes解除了介面和實現之間的耦合關係,從而降低檔案間的編譯依存性.
注意一點,兩種class的實現方案帶來的執行成本也是不容忽視的(由於篇幅問題,我就不具體闡述,相信你們
也能自己分析的出來).如果你應該從你的實際出發,考慮用漸近方式去使用這些技術.
請記住:
■ 支援"編譯依存性最小化"的一般構想是:相依於宣告式,而不要相依於定義式.基於此構想的兩個
手段是handle classes和inte***ce classes.
■ 程式庫標頭檔案應該以"完全且僅有的宣告式"的形式存在.這種做法不論是否涉及templates都適用.
C 將檔案間的編譯依存關係降到最低
20180320 c 將檔案間的編譯依存關係降到最低 當對c 程式的某個class實現檔案做了些微修改,再重新建置這個檔案,會花費很長時間,因為c 沒有把 將介面從實現中分離 這事做的很好。class的定義式不只詳細敘述了class介面,還包括十足的實現細節,eg class person 這裡的c...
C 檔案依存關係 提高編譯速度
原文 1 什麼叫檔案依存關係 1 include 2 include date.h 3 inblude image.h 4 class peopel 那麼這樣people定義檔案與該三個檔案之間就形成了一種編譯依存關係。如果這些標頭檔案任何乙個檔案被改變,或這些標頭檔案所依賴其他標頭檔案任何改變,那...
將檔案間的編譯依存關係降至最低(第三部分)
出處 下面來談談書中的第二部分,用inte ce classes來降低編譯的依賴。從上面也可以看出,避免重編的訣竅就是保持標頭檔案 介面 不變化,而保持介面不變化的訣竅就是不在裡面宣告編譯器需要知道大小的變數,handler classes的處理就是把變數換成變數的位址 指標 標頭檔案只有class...