目录
模板
一、定义:
模板是泛型编程的基础。(泛型:任意类型)
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。
二、分类:
模板分为两类:
- 函数模板
- 类模板
三、优缺点:
优点:
- 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生。
- 增强了代码的灵活性。
缺点:
- 模板让代码变得凌乱复杂且不易维护,编译代码时间变长。
- 模板编译出错时,错误信息非常凌乱,不易定位错误。
函数模板:
一、定义:
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
编译器根据传入的实参类型,来推演生成对应类型的函数。
二、函数模板格式:
template <typename 形参名,typename 形参名,......>其中,typename 可以用 class 关键字代替。
返回类型 函数名(参数列表) {函数体}
三、函数模板的实例化
编译器用模板产生指定的函数的特定类型版本,产生模板特定类型的过程称为函数模板实例化。函数模板必须由编译器根据程序员的调用类型实例化为可执行的函数。
模板参数实例化分为:
- 隐式实例化:让编译器根据实参推演模板参数的实际类型 add(1,2)
- 显式实例化:在函数名后的<>中指定模板参数的实际类型 add<int>(1,2)
例:add(1,2.0)
此时编译器将报错,因为当模板参数类型不同且使用的是隐式实例化时,模板不会像普通的函数一样进行隐式类型转化
解决方法:
1. 用户自己来强制转化 add(1,(int)2.0)
2. 使用显式实例化 add<int>(1,2.0)
编译器只会执行两种转化
- 1、const转换:接收const引用或者const指针的函数可以分别用非const对象的引用或者指针来调用
- 2、数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参应用常规指 针转换。数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针。
四、函数模板的编译
模板在这个过程中被编译了两次:
- ①实例化之前,检查模板代码本身,查看是否出现语法错误。
- ②在实例化期间,检查模板代码,查看是否所有的调用都有效,如:实例化类型不支持某些函数调用。
五、模板参数的匹配原则
- 1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
- 2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模 板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。
- 3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
类模板:
一、格式:
template<class形参名,class形参名,…> class类名 { ... }; 其中,class可以用typename关键字代替。
类模板中函数放在类外进行定义时,需要加模板参数列表:
template <class T> Vector<T>::~Vector() { if(_pData) { delete[] _pData; } }
二、类模板的实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
// vector是类名,vector<int>才是类型
vector<int> s1;
s1.PushBack(1);
s1.PushBack(2);
s1.PushBack(3);
三、类模板与函数模板的联系
- 类模板的成员函数都是函数模板
- 没使用过的成员函数(即函数模板)不会被实例化
四、C++使用模板类的好处
- 可用来创建动态增长和减小的数据结构
- 它是类型无关的,因此具有很高的可复用性。
- 它在编译时而不是运行时检查数据类型,保证了类型安全
- 它是平台无关的,可移植
- 可用于基本数据类型