一、类模板的形式
例如:
template<typename T>
class student{
T name;
public:
student(T name):name(name){}
};
模板参数T,可以出现在类中的任何位置,未必是作为成员变量(不过最好不要这么写)
二、类模板的实例化
与函数模板不同,类模板无法进行参数推断,实例化的时候必须声明类型。
三、类模板成员函数的定义
类内定义,没什么好说的。类外定义格式如下:
template<模板形参表>
函数返回类型 类名<模板形参名>::函数名(参数列表){}
例如:
using namespace std;
template<typename T>
class student{
T name;
public:
student(T name);
};
template<typename T>
student<T>::student(T name) {
this->name = name;
}
四、类模板中成员函数的实例化
和普通函数模板一个原则,不用不会实例化,即使类模板实例化了,其中的成员函数不用也不会被实例化。
这个对于后续要讨论的模板函数分文件定义有影响。
#include <iostream>
using namespace std;
template<typename T>
class student{
T name;
public:
student(T name):name(name){}
void display(){
cout<<name.f();
}
};
int main(){
student<int> stu(1); //明显与display函数有冲突,但是也能编译通过。因为没有使用。
return 0;
}
部分误人子弟的博客说:
“类模板在实例化时,带有模板形参的成员函数并不会跟着实例化,这些成员函数只有在被调用时才会被实例化。”
扯淡,类模板中的所有成员函数,只要不用,就不会实例化。
五、类模板中的静态成员
静态成员函数为一个class所公有。但是类模板不是一个实际的类,必须要先实例化才能使用静态成员。否则编译器不知道这个成员属于哪一个类。
#include <iostream>
using namespace std;
template<typename T>
class student{
T name;
public:
student(T name):name(name){}
void display(){
cout<<name.f();
}
static int a;
};
template<typename T>
int student<T>::a = 0;
int main(){
int a = student::a; //错误,student没有实例化
int b = student<string>::a;
int c= student<int>::a;
student<int> stu(1);
int d = stu.a;
return 0;
}
六、类模板编译错误检查
类模板其实是有个二次编译的机制,未实例化(展开)的情况下,只会检查基本语法是否错误。实例化后会根据展开情况再次检查语法是否有错误。看代码:
template<typename T1, typename T2>
class Base
{
T1 t1;
T2 t2;
public:
Base(T1 a, T2 b):t1(b),t2(a){}
void display(){
cout<<t1<<" "<<t2<<endl;
}
};
int main() {
Base<int,char> base(1,3);
}
我把两个模板参数类型赋值故意搞成颠倒的了,编译没有任何问题。因为编译器不知道你要实例化成什么样子,之后检查基本语法是否正确。
后面我在实例化的时候,故意把T1和T2设置为相同的类型,展开后,作为实际的类,编译也是没有问题的。