編譯依存關係最小化

最近在做一個不算大的項目,編寫的頭文件也就6-7個左右,再加上用上了OpenCV庫與Eigen庫,所以編譯的時候特別蛋疼,一堆的warning,而且都是一樣的warning,因爲一個頭文件裏有warning出現,然後又有其他幾個頭文件包含了這個出現“warning”的頭文件,所以這編譯的輸出又刷屏了!這樣我想起當初玩WOW的時候用自動宏刷屏。- -

關鍵的是,這拖慢了編譯速度。還好<<Effective C++>>這本書看到了條款31,有降低編譯依存關係的方法。書裏介紹了兩種方法:Handle class,Interface class.下面我重點介紹一下Handle class的方法。

這個方法設計到class的定義與聲明。有的情況下,必須給出class的定義,才能使用該class及其相關的東西,如:

Date birthday;
這種情況下就必須給出Date類的定義,如包含定義其的頭文件:
#include "Date.h"
否則無法通過編譯。

有的情況下,給出class的聲明即可。如該class的對象當形參,或者定義一個該class的指針或引用:

class Date;  //聲明
Date today();  //沒問題
void getWeather(Date d);   //當形參
Date *someOneBirthday;   //定義指針
以上都能通過編譯,而僅僅作class的聲明就可以。

所以,儘量跟着這條光明大道走:

1. 如果能使用對象引用(object references)或者對象的指針(object pointers)可以完成任務,就不用使用對象(objects)。

2. 如果能夠,儘量以class聲明式代替class的定義式。

還有一個技巧就是: 

爲聲明式和定義式提供不同的頭文件。

如:

#include "datefwd.h"
即剛纔class Date的聲明頭文件。

下面舉一個血淋淋的例子。

#include <memory>
#include <string>
#include "Address.h"
#include "Date.h"
using namespace std;
class Person
{
	//tr1::shared_ptr<PersonImpl> pImpl;
	string	mName;
	Date	mBirthDate;
	Address	mAddress;
public:
	Person(const string& name, const Date& birthday, 
		const Address& address);
	/* 偷偷懶,只寫一個get函數 */
	string getmName() const;
};
看我的Person class裏,由於跟Date與Address關聯,所以必須包含着兩個class的頭文件,如果跟更多的類關聯的話,你就要包含更多的頭文件,然後,你就可以享受被刷屏的樂趣了。

Handle class的方法則是把Person類分割成2個classes,一個提供接口一個提供實現。下面可以看到,如何把那些煩人的與外部類關聯的成員封裝到另外一個實現類(PersonImpl),然後在Person類風騷地定義一個指向PersonImpl的指針。好吧,有了這個指針,我就對那些外部關聯的class作一個聲明就行了。

Person的定義:

#include "DependFwd.h"	//我是聲明頭文件
#include <memory>
#include <string>
using namespace std;
class Person
{
	tr1::shared_ptr<PersonImpl> pImpl;  //這個是智能指針
public:
	Person(const string& name, const Date& birthday, 
		const Address& address);
	/* 偷偷懶,只寫一個get函數 */
	string getmName() const;
};
來看看PersonImpl類怎麼定義:

/* 包含其定義式才能使用 */
#include "Date.h"
#include "Address.h"
using namespace std;
/* Person接口實現類 */
class PersonImpl
{
	/* 原來Person的成員都在這定義了 */
	string	mName;		
	Date	mBirthDate;
	Address	mAddress;
public:
	/* 構造函數 */
	PersonImpl(const string& name, const Date& birthday, 
		const Address& address)
		:mName(name), mBirthDate(birthday), mAddress(address)
	{}
	/* 獲取姓名 */
	string getmNmae() const{ return mName;}
	/* 生日和地址的獲取函數就不寫了 */
};


Date與Address我就省略了,來看看聲明頭文件DependFwd.h:

class Address;
class Date;
class PersonImpl;
只有三行。

測試一下:

#include <iostream>
#include "Person.h"
#include "Date.h"
#include "Address.h"
using namespace std;
int main()
{
    Date	birthday;
    Address 	address;
    Person	p("John", birthday, address);
    cout << p.getmName() << endl;
    system("pause");
    return 0;
}

輸出

John

當然,使用這些最小化編譯依存關係的方法,對程序運行效率還是有所影響的,而且消耗的內存量也有所增加。不過這也解除了接口和實現之間的耦合關係。

如果大家還記得80-20原則:

80%的運行時間都消耗在其中20%的代碼上。

所以,還是不要放棄上面提到的技術,如果願意的話,還是對那80%對效率影響不大的代碼作一些結構上的優化,而把提高效率的重心放在另外那20%的代碼上。


以後有空的話會寫一些Interface classes的方法。



發佈了59 篇原創文章 · 獲贊 13 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章