06模板学习之模板类的实现(包含如何实现模板类的分离)
概述:
使用过模板编写的人都知道,当我们将一个模板类声明在.h,实现在.cpp后,然后在另一个.cpp文件中调用(一般在main.cpp),编译的时候会报错,为什么呢,留着下面解答。
类似错误如下:
1 代码如下
1)模板的.h文件
#pragma once
#include<iostream>
using namespace std;
template<class T>
class Person{
public:
Person(T age);
void Show();
public:
T age;
};
2)模板的.cpp文件
#include "Person.h"
//若.h,.cpp分离时且调用的文件中只包含.h,会导致经过2次编译后,并没有生成具体的函数
template<class T>
Person<T>::Person(T age){
this->age = age;
}
template<class T>
void Person<T>::Show(){
cout << "Age:" << age << endl;
}
3)调用模板的函数,.cpp文件。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//错误写法
//需要改成.cpp或者放在同一文件内实现模板类
#include "Person.h"
int main(void) {
//若.h,.cpp分离时且调用的文件中只包含.h时,
//构造函数定义在当前文件没有找到,编译认为这个函数在其他文件中定义
//让链接器在链接的时候,去找这个函数的具体位置,没找到就报错
Person<int> p(10);
p.Show();
return 0;
}
那么一运行为什么会出现上面开头的错误呢?
这是因为,C++在编译多个文件时,每个文件的编译都是独立的。所以当编译器编译main.cpp时,由于main.cpp只包含了Person.h头文件,只有声明,而没有实现,导致Person.cpp无法在二次编译时生成具体的函数,所以在链接的时候编译器就报出了与缺少相应静态库里的函数一样的错误。
编译时不报错的原因是因为呢包含了头文件,做了声明。
所以现在懂了吧。
还是再总结一次上面的错误,因为我当时项目也试过,所以印象比较深:
main.cpp只包含头文件导致调用的具体类型无法传送到Person.cpp去生成具体函数(因为两个文件编译时是毫不相关的独立的),导致模板的二次编译即Person.cpp无法生成具体函数,最后导致链接时无法找到可以调用的函数而造成编译器报错。
2 那么如何解决呢?
- 1)方法1:
在main.cpp的#include"Person.h"改成#include"Person.cpp"即可
这样做是为了让它们在二次编译时有关联,就能让Person.cpp生成正确的函数
- 2)方法2:一般推荐这种,也是目前C++主流的模板类编写方法。
将模板类.h和.cpp文件合成同一个文件,也就是类内实现,不做分离
并且该模板类的文件名为了区别普通类的.h,.cpp,一般起名为.hpp。
实际上你也可以起名为.h,或者.cpp
这里为了方便改了第一种,可以成功运行,不过开发时最好写在同一文件,不仅能养成良好的代码习惯也提升自己。