如果将类模板的声明和实现写在两个独立的文件中,在构建时会出现“error LNK2019: 无法解析的外部符号 ”的错误。
现象:当单独编译每个.cpp文件时,都可以编译过,但是当程序运行时,也就是链接时就报“无法解析的外部符号 ”的错误
原因:链接时,没有找到函数的实现部分,这个跟函数模板实现机制和C++编译机制有关,C++每个cpp单独编译 ,.h文件不编译, 比如下面的例子,有MyClass.cpp和Main.cpp,当编译Main.cpp时,发现MyClass<int, int> class1(3, 5) 和class1.Show()这两个函数调用,此时先编译过,先生成2个函数符号,当链接的时候去找这2个函数的实现部分。然后编译MyClass.cpp时,发现有2个模板函数,但是此时编译不会生成具体的函数,只有模板函数在调用的时候才生成具体的函数,所以也编译后,但是其实没有2个函数的具体实现部分,所以链接时找不到。
实例:
MyClass.h:
#ifndef _CLASS_TEMPLATE_H_ #define _CLASS_TEMPLATE_H_ template<typename T1, typename T2> class MyClass { public: MyClass(T1 tOne, T2 tTwo);//Constructor void Show(); private: T1 mOne; T2 mTwo; }; #endif
MyClass.cpp:
#include "MyClass.h" #include <iostream> using namespace std; template <typename T1, typename T2> MyClass<T1, T2>::MyClass(T1 tOne, T2 tTwo)
{
mOne = tOne;
mTwo = tTwo;
} template <typename T1, typename T2> void MyClass<T1, T2>::Show() { cout << "mOne=" << mOne << ", mTwo=" << mTwo << endl; }
Main.cpp
#include<iostream> #include "MyClass.h" using namespace std; int main() { MyClass<int, int> class1(3, 5); class1.Show(); system("pause"); return 0; }
这样写会报错:
解决办法:
办法1:将函数实现和函数声明合并在一起,即将MyClass.cpp和MyClass.h相合并,即直接写为MyClass.h,去掉MyClass.cpp文件,如下
MyClass.h
#ifndef _CLASS_TEMPLATE_H_ #define _CLASS_TEMPLATE_H_ template<typename T1, typename T2> class MyClass { public: MyClass(T1 tOne, T2 tTwo) { mOne = tOne; mTwo = tTwo; } void Show() { cout << "mOne=" << mOne << ", mTwo=" << mTwo << endl; } private: T1 mOne; T2 mTwo; }; #endif
Main.cpp:
#include<iostream> #include "MyClass.h" using namespace std; int main() { MyClass<int, int> class1(3, 5); class1.Show(); system("pause"); return 0; }
办法2:还是包含Main.cpp,Main.h和Main.cpp,但是Main.cpp里面的#include "MyClass.h"换成#include "MyClass.cpp",
注意:一般情况下写类模板时,没有.h和.cpp文件,是创建一个命名为 ***.hpp的文件,并将声明和实现同时写在里面,其他地方调用时添加#include " ***.hpp "。