C++模板声明与实现分开--由此想到的编译,链接原理
問題來源:當模板文件的實現與聲明分開在不同文件中時,鏈接時會提示找不到相應模板函數,如下
一,編譯和鏈接的大概原理:
1,編譯,遍歷工程的所有代碼文件,進行文件分析,這里的分析與文件后綴無關,并不是說以CPP文件為依據,源文件后綴名可以改為任何名字。
編譯以文件為單位,將此文件#include的所有文件拿進來,寫進此文件中,包含進來的東西可能是函數聲明,也可能是函數的實現體。
如果#include "test.h",則包含進來的是一些函數和變量的聲明,如果 #include "test.cpp",則其中的函數實現代碼也被包含進來了。
編譯的結果是一個obj文件,如test.cpp編譯后是一個test.obj文件,里面是匯編指令。
同時,編譯器有了該文件的一個清單,里面保存了 【函數簽名(聲明)】到【函數體實現】的映射
2,鏈接,對所有的obj文件進行拼接。
為什么要拼接?對于每個obj文件,其中若調用了其它文件的函數(外部調用),就需要知道此外部函數的具體實現,這在編譯時是不關心的。
這時候去所有obj文件中查找此外部函數的實現體,若有兩個以上的obj都有此實現,則鏈接出錯,因為函數實現不唯一了,這不允許。此錯誤就是常見的
XXX?已經在 xxx.obj中定義了,如下:
若查找結果唯一,則將此外部函數的實現插入到調用處。
?二,實例分析
1,一個頭文件被多個CPP包含時編譯鏈接正確,一個CPP文件被多個其它CPP文件包含時編譯正確,鏈接出錯,報錯為 XXX?已經在 xxx.obj中定義。
因為CPP中有函數的實現體,每被包含一次就多了一個實現,導致一個函數在不同CPP文件中被多次實現,重復了。
頭文件被多次包含為什么沒問題?關鍵是每個頭文件開頭都有宏 #pragma once,該宏確保了頭文件只會被包含一次
2,模板文件的特殊性。
模板文件只有在實例化時才能確定其具體的實現體,所以如果將模板文件的聲明和函數體分開在.h和.cpp中,當編譯cpp時,并不會產生函數的具體實現體。當在其它文件中#include "template.h"時,會提示找不到函數的定義。
解決方法:在需要使用模板函數的地方,#include "template.cpp",即包含它的CPP文件,而不是.h文件。
原因:使用模板函數的地方,比如 addobj<cube>(),傳了具體的模板類型給函數,這樣模板函數就能到CPP文件中找到對應的實現體將cube傳給模板參數而實例化了。
3,綜合的例子,若一個類中既有模板函數,又有非模板函數,那么只能將模板函數的聲明與定義寫在一個文件中,分開到兩個文件是不行的。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的C++模板声明与实现分开--由此想到的编译,链接原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】C++ 模板类的声明与实现分离问题
- 下一篇: C++编译-链接错误集合