案例
类头文件(Person.h)
#pragma once
template<class T>
class Person
{
public:
Person(T age);
void show();
T age;
};
类的实现(Person.cpp)
#include "Person.h"
template<class T>
Person<T>::Person(T age)
{
this->age = age;
};
template<class T>
void Person<T>:: show()
{
cout << "Age:" << age << endl;
}
主函数(test.cpp)
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include"Person.h"
using namespace std;
int main()
{
Person<int>P(10);
P.show();
getchar();
return 0;
}
编译结果
原因分析
1.模板的编译机制
模板需要两次编译
第一次编译是在实例化之前:用来分析基本的语法错误,
第二次编译是在实例化之后,当把这个类型替换之后,判断有没有语法错误.
编译器在看到模板的定义的时候。并不马上产生代码,仅仅有在看到用到模板时,比方调用了模板函数 或者 定义了类模板的
对象的时候。编译器才产生特定类型的代码。进行实例化
2.c++的编译机制
C++的编译机制是对每一个cpp文件进行单独编译,在单独编译时如果发现一个函数调用,如果在当前文件找不到函数体,则可能在其他cpp文件中实现了此函数的声明.编译器会在函数位置生成符号代替此函数,在最终的链接阶段由链接器来寻找函数体进行链接
因此,类模板在编译时,无法知道其他cpp文件中对类模板是否有实例化,因此只进行第一步编译,没有进行实例化,而链接器在链接过程中没有找到实例化的类模板与之对应,因此链接失败,编译错误.
解决方法
方法一:将主函数中的头文件(.h)改写为(.cpp)
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include"Person.cpp"
using namespace std;
int main()
{
Person<int>P(10);
P.show();
getchar();
return 0;
}
方法二:将类模板的声明与定义写入同一文件中,并将(.cpp)改为(.hpp)便于与其他文件作出区别(推荐使用)
template<class T>
class Person
{
public:
Person(T age);
void show();
T age;
};
template<class T>
Person<T>::Person(T age)
{
this->age = age;
};
template<class T>
void Person<T>:: show()
{
cout << "Age:" << age << endl;
}
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include"Person.hpp"
using namespace std;
int main()
{
Person<int>P(10);
P.show();
getchar();
return 0;
}