和函数模板类似,类也可以使用模板。
类模板
使用template <typename T ...> class A{} ,这样就声明了一个类模板。我们就可以在成员函数和成员属性中使用虚拟类型T了
1. 成员函数在类内部进行实现
/*类模板
*/
template <typename T>
class A {
public:A(const T& a = 10) {this->a = a;}T getA()const {return a;}
private:T a;
};int main(void) {A<int> a(100);cout << a.getA() << endl;system("pause");return 0;
}
上面我们定义了一个类模板,类模板在定义类对象的时候,必须使用<>传入相应的类型,用来实例化定义的虚拟类型。
2. 成员函数在类外部进行实现,在类内进行声明。
/*类模板
*/
template <typename T>
class A {
public:A(const T& a = 10);T getA(const A& a1)const;
private:T a;
};template <typename T>
A<T>::A(const T& a) {this->a = a;
}template <typename T>
T A<T>::getA(const A& a1)const {A tmp;return a;
}int main(void) {A<int> a(100);cout << a.getA() << endl;system("pause");return 0;
}
我们在函数的外部实现成员函数的时候,
1. 需要在每个函数实现前都写上template <typename T ...>,并且<>中的参数应该和类模板中的参数一样。
2. 我们在实现函数时,应该在函数作用域前,使用<>显示传入参数T。为什么传入的是T呢而不是实际的参数?
函数模板是在函数调用时传入实际类型参数,而类模板是在我们定义对象的时候传入实际的类型参数。 所以我们在类的声明和成员函数定义的<>中,只需要传入虚拟类型参数就行。
为什么要传入呢?
因为我们是在类的外部实现的函数,所以我们要告诉编译器这个函数也使用了模板,所以我们需要在每一个函数实现的前面都加上一个模板的定义,而且类型参数应该和类模板的类型参数相同。
3. 我们在作用域<>中显示传入类型参数后,在函数的参数和内部,就不需要再显示的传入类型参数了。(当然显示传入也没问题)
3.类声明写在头文件中,相应的函数定义写在cpp源文件中。
// A.h
template <typename T>
class A {
public:A(const T& a);T getA()const;
private:T a;
};// A.hpp
#include "A.h"template <typename T>
A<T>::A(const T& a) {this->a = a;
}template <typename T>
T A<T>::getA()const {return a;
}
main.cpp
#include "A.hpp"using namespace std;int main(void) {A<int> a(100);cout << a.getA() << endl;system("pause");return 0;
}
当我们分文件写的时候,和在类外定义是一样的。
只不过,我们一般情况再main.cpp只需要导入头文件就行了,但是在使用了类模板之后,我们导入头文件就不行了,我们应该将函数模板成员函数实现所在的文件导入到使用类模板的源程序中去。
就像上面的代码中: 我们在main.cpp中导入的是"A.hpp",而不是"A.h",导入"A.h"会出问题。
有一个不成文的规定,我们将类模板的函数实现所在的源程序的文件结尾设置为.hpp,这样代码的阅读者,就很容易知道是类模板的函数实现的源程序。