2011-07-03 70 views
1

大家好我只是想練習一些C++模板,但我得到鏈接器錯誤。有人可以幫我嗎? 這裏是我的代碼:C++模板類問題

// File: MyClass.h 
#ifndef _MYCLASS_H 
#define _MYCLASS_H 
template<class T> class MyClass { 
T value; 
public: 
MyClass(T v); 
~MyClass(); 
}; 
#endif // _MYCLASS_H 

// File: MyClass.cpp 
#include "MyClass.h" 
template<class T> MyClass<T>::MyClass(T v) { 
value = v; 
} 
template<class T> MyClass<T>::~MyClass() { 

} 

// File: main.cpp 
#include "MyClass.h" 
int main() { 
MyClass<int> test(10); 
return 0; 
} 

下面是命令行輸出:

g++ main.cpp -c 
g++ MyClass.cpp -c 
g++ main.o MyClass.o -o Out 
main.o: In function `main': 
main.cpp:(.text+0x1a): undefined reference to `MyClass<int>::MyClass(int)' 
main.cpp:(.text+0x2b): undefined reference to `MyClass<int>::~MyClass()' 
collect2: ld returned 1 exit status 
make: *** [all] Error 1 

正如你可以看到我使用Ubuntu 10.04和GNU C++編譯器。 我在這段代碼中遺漏了什麼嗎?


感謝您的回覆。它的工作原理,但沒有更好的方法來保護代碼? 例如,如果我想創建一個非開源庫? 我想將代碼導出到靜態庫。並將庫鏈接到其他項目...

+0

'MyClass.cpp'和'main.cpp'分別編譯(不同的翻譯單元),所以當你的編譯器編譯MyClass.cpp時,它不知道哪個參數需要實例化。您需要將定義和聲明移至'main.cpp'。 – 2011-07-03 20:47:01

回答

5

您必須將完整模板放入標題中。編譯器需要在模板實例化站點查看模板方法的主體 - main.cpp您的情況。例如,參見C++ FAQ

+0

對,我建議在'MyClass.h'的末尾將'MyClass.cpp'重命名爲'MyClass_impl.h'和#include'MyClass_impl.h''。這有助於仍然在單獨的文件中維護聲明和實現以便於閱讀。 –

1

您應該將模板類和內聯方法放入頭文件中。在他們的情況下,你不能單獨定義和執行。

1

@Nikolai N Fetissov有正確的解決方案。我想補充一點,一個很好的辦法做到這一點,如果你想保留的實施和模板函數定義分開的是,你可以把實現爲MyClass.hxx,包括它在您MyClass.h

// File: MyClass.h 
#ifndef _MYCLASS_H 
#define _MYCLASS_H 

template<class T> class MyClass 
{ 
    T value; 
public: 
    MyClass(T v); 
    ~MyClass(); 
}; 

#include "MyClass.hxx" /// <--- like this 
#endif // _MYCLASS_H 
結束
0

重要的是要記住模板是什麼。如果需要,它是用於生成代碼的模板;它本身不是代碼。

因此,聲明模板類併爲這些方法編寫實現不會爲該類生成任何對象代碼;它只是提供了一個模板,如果有必要的話。

當使用實際參數實例化模板類時,編譯器將從模板類生成代碼。爲了做到這一點,它需要能夠看到模板。但由於您只有#include ed.h文件以及.cpp文件中的方法實現,因此編譯器將無法爲函數實現生成目標代碼。然後,當鏈接器查找這些定義時,它不會找到它。

所有這些都是讓其他答案達到相同結果的冗長方式 - 您需要將實現放入頭文件中,並聲明類聲明。但它可能有助於知道這是爲什麼。