出處:
下面來談談書中的第二部分,用inte***ce classes來降低編譯的依賴。從上面也可以看出,避免重編的訣竅就是保持標頭檔案(介面)不變化,而保持介面不變化的訣竅就是不在裡面宣告編譯器需要知道大小的變數,handler classes的處理就是把變數換成變數的位址(指標),標頭檔案只有class ***的宣告,而在cpp裡面才包含***的標頭檔案。inte***ce classes則是利用繼承關係和多型的特性,在父類裡面只包含成員方法(成員函式),而沒有成員變數,像這樣:
1而這些方法的實現放在其子類中,像這樣:2 #include
3using
namespace
std;45
class
myaddress;
6class
mydate;
7class
realperson;89
class
person
1016 };
1在realperson.cpp裡面去實現getname()等方法。從這裡我們可以看到,只有子類裡面才有成員變數,也就是說,如果address的標頭檔案變化了,那麼子類一定會重編,所有用到子類標頭檔案的檔案也要重編,所以為了防止重編,應該盡量少用子類的物件。利用多型特性,我們可以使用父類的指標,像這樣person* p = new realperson(***),然後p->getname()實際上是呼叫了子類的getname()方法。2 #include "
person.h
"3 #include "
myaddress.h
"4 #include "
mydate.h"5
6class realperson: public
person714
virtual
string getname() const;15
virtual
string getaddress() const;16
virtual
string getbirthday() const
;17 };
但這樣還有乙個問題,就是new realperson()這句話一寫,就需要realperson的建構函式,那麼realperson的標頭檔案就要暴露了,這樣可不行。還是只能用person的方法,所以我們在person.h裡面加上這個方法:
1注意這個方法是靜態的(沒有虛特性),它被父類和所有子類共有,可以在子類中去實現它:2static person* createperson(string name, const myaddress& addr, const mydate& date);
1這樣在客戶端**裡面,可以這樣寫:2#include 「person.h」
3 person* person::createperson(string name, const myaddress& addr, const mydate&date)
4
12class
myaddress;
3class
mydate;
4void processperson(const
string& name, const myaddress& addr, const mydate& date);
//就可以減少編譯依賴了。main.cpp
#include "
person.h
"#include 「myaddress.h」;
#include 「mydate.h」;
void processperson(const
string& name, const myaddress& addr, const mydate&date)
總結一下,handler classes與inte***ce classes解除了介面和實現之間的耦合關係,從而降低檔案間的編譯依存性。減少編譯依存性的關鍵在於保持.h檔案不變化,具體地說,是保持被大量使用的類的.h檔案不變化,這裡談到了兩個方法:handler classes與inte***ce classes。
handler classes化類的成員變數為指標,在.h檔案裡面只包含class ***的外來類宣告,而不包含其標頭檔案,在.cpp涉及到具體外來類的使用時,才包含***.h的標頭檔案,這樣最多隻影響本身類的cpp重編,但因為.h檔案沒有變化,所以此類的物件存在的檔案不必重編。
當然,書上說的handler classes更想讓我們在類a的基礎上另造乙個中間類aimp(成員函式完全與類a一致),這個中間類的成員中裡面放置了所有類a需要的外來類的物件,然後類的邏輯細節完全在almp.cpp中實現,而在a.cpp裡面只是去呼叫almp.cpp的同名方法。a.h的成員變數只有almp的指標,這看上去好像乙個handler,因此而得名。
inte***ce classes則是將細節放在子類中,父類只是包含虛方法和乙個靜態的create函式宣告,子類將虛方法實現,並實現create介面。利用多型特性,在客戶端只需要使用到person的引用或者指標,就可以訪問到子類的方法。由於父類的標頭檔案裡面不包含任何成員變數,所以不會導致重編(其實由於父類是虛基類,不能構造其物件,所以也不用擔心由於父類標頭檔案變化導致的重編問題)。
請記住:
1. 支援「編譯依存性最小化」的一般構想是:相依於宣告式,不要相依於定義式,基於此構想的兩個手段是handler classes和inte***ce classes。
2. 程式庫標頭檔案應該以「完全且僅有宣告式」的形式存在,這種做法不論是否涉及templates都適用。
條款31 將檔案間的編譯依存關係降至最低
條款31 將檔案間的編譯依存關係降至最低 minimize compilation dependencies between files.內容 在你們的開發團隊中,一些有經驗的工程師時不時地會教導新手一些基本的程式設計原則,其中 將介面從實現中 分離 可能是他 她 要你必須牢記原則,因為c 並沒有把...
C 將檔案間的編譯依存關係降到最低
20180320 c 將檔案間的編譯依存關係降到最低 當對c 程式的某個class實現檔案做了些微修改,再重新建置這個檔案,會花費很長時間,因為c 沒有把 將介面從實現中分離 這事做的很好。class的定義式不只詳細敘述了class介面,還包括十足的實現細節,eg class person 這裡的c...
將檔案之間的編譯依賴關係降至最低
考慮這樣幾個類,a a1 a2 b,其中a和b是要暴露給使用者的類。1.最初組織關係如下 a1.h include class a1 a.cpp include a.h void a dosomething b a returnb user.cpp include a.h int main 因此,u...