类模板
1 类模板语法
类模板作用: 建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。
语法: template<typename T>
解释:
- template — 关键字,声明创建模板
- typename — 关键字,表面其后面的符号是一种数据类型,可以用class代替。即
template<typename T>
或者template<class T>
- T — 通用的数据类型,名称可以替换,通常为大写字母
场景描述: 写一个类,成员属性,比如姓名和年龄的类型通用化,不具体定义成员属性的类型
//类模板
template<class NameType, class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mname = name;
this->mage = age;
}
void showPerson()
{
cout << "姓名:" << this->mname << "\t年龄:" << this->mage << endl;
}
NameType mname;
AgeType mage;
};
void test1()
{
Person<string, int> p1("西施", 25);
p1.showPerson();
}
由于成员函数有两个,并且都是不同的类型,所以类模板中需要两种参数类型,即NameType和AgeType;
类的成员属性以及有参构造函数的形参都使用类模板的通用化数据类型,即NameType和AgeType;
在实例化类对象时,需要声明类模板的参数类型,即声明有参构造函数的形参类型,NameType的类型是string,AgeType的类型是int,因此在类名后加上“<string, int>”。
**总结:**类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板。
2 类模板与函数模板区别
类模板与函数模板区别主要有两点:
- 类模板没有自动类型推导的使用方式
- 类模板在模板参数列表中可以有默认参数
//类模板
template<class NameType, class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->mname = name;
this->mage = age;
}
void showPerson()
{
cout << "姓名:" << this->mname << "\t年龄:" << this->mage << endl;
}
NameType mname;
AgeType mage;
};
void test1()
{
Person<string, int> p1("西施", 25);//只能显示指定类型方式调用类模板
//Person p2("西施", 25);//错误, 类模板没有自动类型推导方式
p1.showPerson();
}
如果在类模板的参数列表,即类模板template<class NameType, class AgeType>
在<>里的内容,即class NameType, class AgeType
加上数据类型,变成template<class NameType, class AgeType = int>
,此时在实例化对象时,可以不声明AgeType的类型。
//类模板
template<class NameType, class AgeType = int>//参数列表<>内容 class NameType, class AgeType
class Person1
{
public:
Person1(NameType name, AgeType age)
{
this->mname = name;
this->mage = age;
}
void showPerson()
{
cout << "姓名:" << this->mname << "\t年龄:" << this->mage << endl;
}
NameType mname;
AgeType mage;
};
void test2()
{
Person1<string> p2("貂蝉", 22);//只在类模板中使用
p2.showPerson();
}
总结:
- 类模板使用只能用显示指定类型方式
- 类模板中的模板参数列表可以有默认参数
3 类模板中成员函数创建时机
成员函数在类模板和普通类中的创建时机是有区别的,普通类中的成员函数一开始就可以创建,类模板中的成员函数在调用时才创建。
class Person1
{
public:
void showPerson1()
{
cout << "Person1 调用" << endl;
}
};
class Person2
{
public:
void showPerson2()
{
cout << "Person2 调用" << endl;
}
};
template<class T>
class MyClass
{
public:
T obj;
//类模板的成员函数
//在没有创建对象时,以下两个函数都不会调用,因为obj无法确定数据类型
//创建对象时,以下两个函数才会调用。此时才确定obj是什么类型的数据,再决定调用哪个成员函数
void fun1()
{
obj.showPerson1();
}
void fun2()
{
obj.showPerson2();
}
};
void test()
{
MyClass<Person1> m1;
m1.fun1();
//m1.fun2();//创建m1时,确定m1是Person1类型,只能调用showPerson1函数
MyClass<Person2> m2;
//m2.fun1();//创建m2时,确定m2是Person2类型,只能调用showPerson2函数
m2.fun2();
}
注意点
- 普通类中成员函数一开始就可以创建,类模板的成员函数在调用时才创建。所以在没有创建类模板的obj对象时,fun1和fun2函数不会报错;
- 类模板的成员函数在调用时才创建,是因为类模板的对象没有创建的话,无法确定类模板对象的数据类型,无法确定调用哪一个成员函数。比如,MyClass类中,不创建obj,就无法确定obj的数据类型,也就无法确定是调用fun1还是fun2。
- 确定了类模板的对象的类型后,无法调用另一个类的成员函数。针对以上代码的情形,MyClass创建的对象m1是Person1类型,只能调用fun1函数,即调用showPerson1函数;创建m2是Person2类型,只能调用fun2函数,即调用showPerson2函数。