模板的宣告和定義 標頭檔案與原始檔

2021-08-17 08:15:36 字數 1161 閱讀 8397

今天,寫了乙個list的模板類,然後把它的宣告和定義分別放在標頭檔案和原始檔中,發現編譯不通。然後,就有疑問了,一是為什麼那些普通類我們分為標頭檔案和原始檔能編譯通過,二是模板為什麼不行,所以這個編譯究竟做了什麼,這才是我的問題。

當我們對乙個solution右鍵選擇生成的時候,會對所有的.cpp進行編譯(我感覺哈),每個對應生成乙個.obj檔案。當cpp進行編譯時,那種有include標頭檔案的,就是將標頭檔案中的內容直接copy到cpp。隱約記得之前上彙編的課的時候講過,會生成一些symbol和位址的對應的表,那麼應該是在標頭檔案的宣告中,那些函式方法的入口位址就已經確定了,然後當呼叫時,鏈結器會在不同的obj中進行鏈結,找到具體的實現。

但是,在模板中,在編譯時他需要被例項化。比如說我在a.cpp中用到了b.h裡宣告的乙個模板類,但是在b.h裡並沒有該模板的實現,那在編譯a.cpp時,它include了b.h,但是b.cpp並不知道自己要被例項化成哪種型別,於是鏈結器並不能找到對應的位址,所以,編譯不通過。

感覺應該是這個樣子……

參考:c++ 模板類 宣告和定義都放在.h檔案的原因

模板類宣告和定義為何要寫一起

抄抄:乙個編譯單元(translation  unit)是指乙個.cpp檔案以及它所#include的所有.h檔案,.h檔案裡的**將會被擴充套件到包含它的.cpp檔案裡,然後編譯器編譯該.cpp檔案為乙個.obj檔案(假定我們的平台是win32),後者擁有pe(portable  executable,即windows可執行檔案)檔案格式,並且本身包含的就已經是二進位製碼,但是不一定能夠執行,因為並不保證其中一定有main函式。當編譯器將乙個工程裡的所有.cpp檔案以分離的方式編譯完畢後,再由聯結器(linker)進行連線成為乙個.exe檔案。

c++標準明確表示,當乙個模板不被用到的時侯它就不該被例項化出來。(如果用分離的cpp實現,他不會例項化)

在分離式編譯的環境下,編譯器編譯某乙個.cpp檔案時並不知道另乙個.cpp檔案的存在,也不會去查詢(當遇到未決符號時它會寄希望於聯結器)。這種模式在沒有模板的情況下執行良好,但遇到模板時就傻眼了,因為模板僅在需要的時候才會例項化出來,所以,當編譯器只看到模板的宣告時,它不能例項化該模板,只能建立乙個具有外部連線的符號並期待聯結器能夠將符號的位址決議出來。然而當實現該模板的.cpp檔案中沒有用到模板的例項時,編譯器懶得去例項化,所以,整個工程的.obj中就找不到一行模板例項的二進位制**,於是聯結器也黔驢技窮了。

標頭檔案和原始檔

一.例1 test.h void show test.cpp include using namespace std void show includeproblem.cpp include test.h int main 可以看到 includeproblem.cpp檔案彙總 include te...

標頭檔案和原始檔的區別

一 原始檔如何根據 include來關聯標頭檔案 1,系統自帶的標頭檔案用尖括號括起來,這樣編譯器會在系統檔案目錄下查詢。include 2,使用者自定義的檔案用雙引號括起來,編譯器首先會在使用者目錄下查詢,然後在到c 安裝目錄 比如vc中可以指定和修改庫檔案查詢路徑,unix和linux中可以通過...

標頭檔案和原始檔的區別

一 原始檔如何根據 include來關聯標頭檔案 1,系統自帶的標頭檔案用尖括號括起來,這樣編譯器會在系統檔案目錄下查詢。include 2,使用者自定義的檔案用雙引號括起來,編譯器首先會在使用者目錄下查詢,然後在到c 安裝目錄 比如vc中可以指定和修改庫檔案查詢路徑,unix和linux中可以通過...