任何人都可以詳細說明原因?爲什麼聲明/定義必須都在C++模板類的源文件中?
回答
源文件彼此獨立編譯爲可執行代碼,然後再鏈接到主程序。另一方面,模板函數不能在沒有模板參數的情況下編譯。因此,使用它們的文件需要有該代碼才能編譯。因此這些函數需要在頭文件中可見。
應許例如:
template<class T>
void swap(T & a, T & b)
{
T temp = a;
a = b;
b = temp;
}
T類這裏的唯一的要求是,它有一個公共的賦值運算符(=)。這就是所有曾經實施或設想過的課程。但是,每個類都以自己的方式實現賦值運算符。不能爲交換生成相同的機器代碼<int>,交換<雙重>和交換<字符串>。這些功能中的每一個都必須是唯一的。同時,編譯器不可能預見到可能傳遞給該函數的所有不同類型,因此它不能提前生成函數。所以它必須等到函數被調用,然後它才能被編譯。
例如,假設我具有上面定義在「swap.h」中的那個函數。然後在「main.cpp」中,我這樣做:
int main()
{
int a=5, b=10;
double c=3.5, d=7.9;
string s1="hello";
string s2="world";
swap(a,b);
swap(c,d);
swap(s1,s2);
}
在此示例中,創建了3個不同的函數。一個交換ints,一個交換雙打,一個交換字符串。爲了創建這些函數,編譯器需要能夠看到模板代碼。如果它是在一個單獨的源文件中,例如「swap.cpp」,編譯器將無法看到它,因爲就像我之前所說的那樣,每個源文件都是相互獨立編譯的。
你問爲什麼模板體必須在頭文件?這是因爲編譯器需要同時知道主體和模板參數以生成機器代碼。模板參數在使用模板(實例化)的位置是已知的。這給你一個平凡的例子和兩個非平凡的例子:
- (Trivial)該模板只在一個源文件中使用,所以正文可以在同一個源文件中。
- 使身體在每次使用時都可用,這通常意味着在頭文件中。
- 在包含正文的源文件中,顯式實例化每個需要的模板參數組合。
你的問題的簡短答案是沒有義務聲明和定義模板類在同一個源文件中。
事實上,我認爲這是一件壞事,但它是完全可以理解的,因爲分開使用它們非常困難(但它可以完成!)。
編輯
假設你有
- myTemplateClass。爲h,它聲明瞭一個模板類MyTemplateClass
- myTemplateClass.hpp定義其類成員(包括myTemplateClass.h)
- 使用MyTemplateClass的內部的main.cpp
只需包括在myTemplateClass.h main.cpp中和創建myTemplateClassInt.cpp如下:
#include "myTemplateClass.hpp"
template MyTemplateClass<int>;
這樣做,你告訴編譯器實例MyTemplateClass的模板參數「INT」的所有模板方法。由於它可以訪問myTemplateClass.hpp,所以這些方法將被完美地生成......並且鏈接器不會發生抱怨。
當然,這種方法要求您使用一些地方定義您的模板類的實例化版本。
-----------如何? – lurscher 2011-07-12 18:31:51
@lurscher:查看我的答案的編輯版本。 – 2011-07-13 07:51:00
- 1. 爲什麼必須在C++類定義中聲明一個方法?
- 2. 爲什麼必須'自動'聲明都是相同的類型?
- 3. 爲什麼模板必須在類
- 4. 爲什麼我必須在包含文件中重新聲明我的類?
- 5. 爲什麼我必須聲明var = Class.new?
- 6. 模板類中的模板構造函數必須在類定義中定義?
- 7. requireJS爲什麼每個定義都必須在不同的文件中?
- 8. 爲什麼C++模板參數應該聲明爲類類型?
- 9. C++ - 在模板類模板函數獨立聲明/定義
- 10. 爲什麼模板必須在每個使用函數之前聲明?
- 11. 爲什麼我必須重新聲明C++派生類中的重寫函數?
- 12. 什麼時候必須要在C++類中定義析構函數,爲什麼?
- 13. 爲什麼我明確地必須在這裏聲明函數?
- 14. C++中的模板,爲什麼必須使用enum
- 15. 屬性「頁」必須聲明爲元素類型「定義」
- 16. 爲什麼jsp中的EL函數必須聲明爲靜態?
- 17. ASP.NET C#必須聲明
- 18. 必須聲明?
- 19. 類必須聲明爲抽象或?
- 20. 爲什麼在相同的頭文件中聲明一個類爲類聲明
- 21. 爲什麼模板類函數必須在同一個翻譯單元中聲明?
- 22. C++模板類聲明
- 23. 爲什麼我們必須明確指定ClassTag類型類
- 24. 在Linux中隱式聲明timersub()函數 - 我必須定義什麼?
- 25. 組件必須聲明
- 26. C++:將模板聲明爲類成員
- 27. 爲什麼在__init__中調用類函數時必須聲明自己?
- 28. 爲什麼原型必須在構造函數之外聲明?
- 29. 在類定義中聲明的C++宏?
- 30. 爲什麼必須在靜態類中定義C#擴展方法?
我剛剛意識到我沒有真正回答你的問題。但那只是因爲你說錯了。我知道你的意思,因爲我記得曾經有過同樣的問題,所以我對這個問題很熟悉。問題應該是「爲什麼聲明/定義必須都在C++模板類的頭文件中」?不幸的是,我沒有編輯問題的代表。 – 2010-10-15 07:58:56
因此,在我的問題中'source'應該改爲'header',對吧? – tem 2010-10-15 08:02:37
是的。在C++中,源文件是包含函數體(.cpp)的文件。標題是包含你的原型和你的類體(.h或.hpp)的標題。 – 2010-10-15 08:16:23