模板的分離編譯

2021-08-07 15:43:40 字數 2031 閱讀 6868

模板不支援分離編譯

我們來分析一下模板為什麼不支援分離編譯呢,所謂的分離編譯就是我們在編寫程式的時候可能會出現如下的一種情況就是,(我下面就是舉具體的例子了)

**

//*****************template.h***********//

#includeusing namespace std;

templateclass a

;//*****************template.cpp***********//

#include"template.h"

templatevoid a::show()

//*****************test.cpp***********//

#define _crt_secure_no_warnings 1

#include"template.h"

int main()

現象一

上面的程式中,我們呼叫的時候會出現如下的報錯

1>test.obj : error lnk2019: 無法解析的外部符號 "public: void __thiscall a::show(void)" (?show@?$a@h@@qaexxz),該符號在函式 _main 中被引用

1>w:\code\c++\temptlateseparatecompilation\debug\temptlateseparatecompilation.exe : fatal error lnk1120: 1 個無法解析的外部命令

現象二

我們改一下**再來看乙個現象,如果我們在主函式中把a.show給注釋掉,然後在template.cpp把cout<<"hello"《在進行編譯的時候,發現竟然沒有報錯,這就奇怪了吧

從預處理,編譯,彙編,鏈結的角度來分析問題

我們知道模板的乙個特性,只有當呼叫的時候才會例項化它,而我們的程式從一開始的文字到最後的可執行程式經歷了四個過程,分別是預處理,編譯,彙編,鏈結,最後是在鏈結的時候出現了錯誤

一.預處理

在預處理的時候,會進行標頭檔案展開,這個時候會把頭檔案中的函式宣告展開到test.cpp和template.cpp中

二.編譯

在編譯test.cpp時由於只能看到模板宣告而看不到實現,因此不會例項化模板函式,但此時不會報錯,因為編譯器認為模板定義在其它檔案中,就把問題留給鏈結程式處理。

在編譯template.cpp的時候,編譯的時候會進行一些檢查,比如一些語法的檢查,然後生成彙編**,因為我們的模板函式是在呼叫的時候才會進行例項化,即只有在呼叫模板函式的時候才會生成**,但是在我們的編譯的時候,在template.cpp這個檔案中是沒有對函式進行例項化,所以並沒有生成彙編的**,這也是上面的第二種情況為什麼我們的**錯誤從卻沒有被檢查出來的原因,因為我們的根本就沒有生成彙編**

三.彙編

再來接著分析,在彙編的時候就是生成二進位制**,然後是乙個.obj檔案,在linux下面是.o檔案,同時生成乙個符號表,符號表中放置的就是我們所有函式的位址。

四.鏈結.

當我們進行最後一步鏈結的時候,執行到a.show();會去.ob檔案中查詢我們的函式位址,這裡有乙個符號表,但是因為我們沒有生成乙個函式**,所以這個函式表是查詢不到的,所以這個時候就會報上面的錯誤。

還需要分析的乙個問題就是,為什麼我們把函式的宣告和定義放置在乙個檔案中的時候就可以呢,因為如果我們把函式宣告和定義放置在乙個標頭檔案中的話,我們在編譯的時候,就會標頭檔案展開了,這個時候呼叫了我們的函式,然後又是在乙個檔案內如就會直接直接生成**,然後在查詢的時候就會很容易的查詢到這個內容。

解決辦法

方法一:

使用上面說的內容,放模板函式的宣告和定義放在乙個標頭檔案下面

但是這樣會出現一些問題

(1)放置在標頭檔案中,暴露了模板函式的 內容

(2)不符合分離編譯的原則

方法二我們可以在函式宣告的時候加上乙個export,就是下面的這種形式

export void show();

但是很多的編譯器是不支援的

方法三我們可以顯示的例項化,就是我們可以在標頭檔案中對我們需要的內容 進行乙個顯式的例項化

模板的分離編譯

模板為什麼不支援分離編譯 要了解這個問題,我們先來看一下程式在計算機中的執行過程,用一幅圖簡單說明。在乙個規範的c 檔案中,我們通常把乙個檔案分為 檔案宣告,檔案實現和檔案測試三個部分。在一般的編譯環境中,h檔案的 都會擴充套件到.cpp裡面,然後編譯器對.cpp檔案編譯形成.obj檔案,cpp以分...

類模板的分離編譯

一直覺得模板類是特別神奇的東西,它可以構造出不同型別的物件,使 更加的靈活。這個過程就是類模板的例項化。我們使用類的模板寫乙個stack類 include include seqlist1.h using namespace std templateclass container seqlist c...

模板的分離編譯問題

所謂的分離編譯是指將宣告和定義分開來寫,即將乙個函式的宣告和定義放在.h和.cpp檔案中。寫過模板的人應該都會發現當我們用上面的方式寫乙個函式的時候,只要在.cpp中包.h的標頭檔案,就沒什麼問題,但是如果寫模板的時候,就編譯鏈結不過去,就如下面這個例子 include template void ...