C++类模版源文件与头文件分离易错点
考虑下面的一个自定义泛型类:
Person.h
#ifndef C_LEARNING_类模版源文件与H分离_H
#define C_LEARNING_类模版源文件与H分离_H
template <typename T>
class Person{
public:
T age;
public:
void Show();
Person(T age);
};
#endif
Person.cpp
#include "Person.h"
#include <iostream>
using namespace std;
template <typename T>
Person<T>::Person(T age){
this->age = age;
}
template <typename T>
void Person<T>::Show(){
cout<<age<<endl;
}
主调文件main.cpp
#include <iostream>
#include "Person.cpp"
int main()
{
Person<int> p(20);
p.Show();
}
编译时编译器会报错,表示没有找到对应 Person<int> p(20);
的符号表。这是为什么呢?
原来,根据C++的编译机制,以上三个文件都是由编译器分别独立编译再用链接器将各种调用连接起来。在main.cpp里,编译器发现有 Person<int> p(20);
这条语句,但是在本文件中未找到相应的Person构造函数实现,所以先将它置入编译期的符号表(Symbols table)里,然后在include进的 Person.h
中查找。
而.h中仅仅是Person模版类的声明,具体实现仍在 Person.cpp
文件中。而 Person.cpp
中的类模版以及函数模版在定义的地方被编译器编译过了一次,但是在main.cpp
中的操作需要根据具体的int类型再次编译从而生成出对应的具体类与函数。此时链接器找不到具体实现,从而编译失败。
此时我们建议,写类模版的时候,将声明与实现写在一个文件里,并且这个文件后缀为 .hpp
,相当于源文件与头文件的合并。