C++檔案依存關係介紹

來源:互聯網
上載者:User

如果你覺得重新編譯檔案的時間很短或者時間長一點無所謂,反正需要重新編譯,那麼你也可以選擇略過此文,不過也建議瀏覽。
如果你想學習或者關心這塊內容,那麼此文必定會給你帶來收穫。
首先我不給出依存關係的定義,我給出一個例子。

複製代碼 代碼如下: class Peopel{
public:
People(const std::string & name,const Date& brithday,Image Img)
std::string name( ) const;
Date birthDate( ) const;
Image img( ) const;
...
private:
std::string theName; //名字
Date theBirthDate; //生日
Image img; //圖片
};

如果編譯器沒有知道類string,Date和Image的定義,class People是無法通過編譯的。一般該定義式是由#include包含的標頭檔所提供的,所以一般People上面有這些預先處理命令複製代碼 代碼如下: #include <string>
#include "date.h"
#inblude "image.h"
class Peopel{
public:
People(const std::string & name,const Date& brithday,Image Img)
std::string name( ) const;
Date birthDate( ) const;
Image img( ) const;
...
private:
std::string theName; //名字
Date theBirthDate; //生日
Image img; //圖片
};

那麼這樣People定義檔案與該三個檔案之間就形成了一種編譯依存關係。如果這些標頭檔任何一個檔案被改變,或這些標頭檔所依賴其他標頭檔任何改變,那麼每一個包含People類的檔案就需要重新編譯,使用People類檔案也需要重新編譯。想想如果一個項目包含一個上千的檔案,每個檔案包含其他幾個檔案,依次這樣下來,改動一個檔案內容,那麼就需要幾乎重新編譯整個項目了,這可以說很槽糕了。

我們可以進行如下改動

複製代碼 代碼如下: namespace std {
class string;
}
class Date;
class Image;

class Peopel{
public:
People(const std::string & name,const Date& brithday,Image& Img)
std::string name( ) const;
Date birthDate( ) const;
Image img( ) const;
...
private:
std::string theName; //名字
Date theBirthDate; //生日
Image img; //圖片
};

這樣只有People該介面被改變時才會重新編譯,但是這樣有連個問題,第一點string不是class,它是個typedef basic_string<char> string。因此上述前置聲明不正確(附其在stl完全代碼);,正確的前置聲明比較複雜。其實對於標準庫部分,我們僅僅通過#include預先處理命令包括進來就可以了。 複製代碼 代碼如下: #ifndef __STRING__
#define __STRING__

#include <std/bastring.h>

extern "C++" {
typedef basic_string <char> string;
// typedef basic_string <wchar_t> wstring;
} // extern "C++"

#endif

前置聲明還有一個問題,就是編譯器必須在編譯期間知道對象的大小,以便分配空間。
例如: 複製代碼 代碼如下: int main(int argv,char * argc[ ])
{
int x;
People p( 參數 );
...
}

當編譯器看到x的定義式,它知道必須分配多少記憶體,但是看到p定義式就無法知道了。但是如果設定為指標的話,就清楚了,因為指標本身大小編譯器是知道的。複製代碼 代碼如下:#include <string>
#include <memory>

class PeopleImpl;
class Date;
class Image;
class People{
public:
People(const std::string & name, const Date& brithday, const Image &Img);
std::string name( ) const;
Date birthDate( ) const;
Imge img( ) const;
...
private:
PeopleImpl * pImpl;
}

PeopleImpl包含下面這三個資料,而People的成員變數指標指向這個PeopleImpl,那麼現在編譯器通過People定義就知道了其分配空間的大小了,一個指標的大小。複製代碼 代碼如下: public PeopleImpl
{
public:
PeopleImple(...)
...
private:
std::string theName; //名字
Date theBirthDate; //生日
Image img; //圖片

這樣,People就完全與Date、Imge以及People的實現分離了上面那些類任何修改都不需要重新編譯People檔案了。另外這樣寫加強了封裝。這樣也就降低了檔案的依存關係。
這裡總結下降低依存性方法:

1.如果可以類聲明就不要使用類定義了。
2.將資料通過一個指向該資料的指標表示。
3.為聲明式和定義式提供不同的標頭檔。
  這兩個檔案必須保持一致性,如果有個聲明式被改變了,兩個檔案都得改變。因此一般會有一個#include一個聲明檔案而不是前置聲明若干函數。
  像People這樣定

複製代碼 代碼如下: #include "People.h"
#include "PeopleImpl.h"

People::People(const std::string& name, const Date& brithday, const Image& Img)
:pImpl(new PersonImpl(name,brithday,addr))
{ }
std::string People::name( ) const
{
return pImpl->name( );
}

而另外一種Handle類寫法是令People成為一種特殊的abstract base class稱為Interface類。看到interface這個關鍵字或許熟悉C#、java的同學可能已經恍然大悟了。這種介面它不帶成員變數,也沒有建構函式,只有一個virtual解構函式,以及一組純虛函數,用來表示整個介面。針對People而寫的interface class看起來是這樣的。複製代碼 代碼如下: class People{
public:
virtual ~People( );
virtual std::string name( ) const = 0;
virtual Date brithDate( ) const =0;
virtual Image address( ) const =0;
...
};

怎麼建立對象呢?它們通常調用一個特殊函數。這樣的函數通常稱為工廠函數或者虛建構函式。它們返回指標指向動態分配所得對象,而該對象支援interface類的介面。複製代碼 代碼如下: class People {
public:
...
static People* create(const std::string& name,const Date& brithday, const Image& Img);
};

支援interface類介面的那個類必須定義出來,而且真正的建構函式必須被調用複製代碼 代碼如下: class RealPeople:public People{
public:
RealPeople(const std::string& name,const Date& birthday,const Image& Img)
:theName(name),theBrithDate(brithday),theImg(Img)
{}
virtual ~RealPeople() { }
std::string name( ) const;
Date birthDate( ) const;
Image img( ) const;
private:
std::string theName;
Date theBirthDate;
Image theImg;
}

有了RealPeople類,我們People::create可以這樣寫複製代碼 代碼如下: People* People::create(const std::string& name, const Date& birthday, const Image& Img)
{
return static_cast<People *>(new RealPerson(name,birthday,Img));
}

Handle類與interface類解除了介面和實現之間的耦合關係,從而降低了檔案間的編譯依存性。但同時也損耗了一些效能與空間。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.