最近在做一個不算大的項目,編寫的頭文件也就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;}
/* 生日和地址的獲取函數就不寫了 */
};
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的方法。