一、泛型编程
1. 泛型编程是什么?
泛型编程就是编写于类型无关的通用代码,是代码复用的一种方式。模板是泛型编程的基础
2. 模板是什么?
模板就是告诉编译器一个模子,让编译器根据不同的类型,根据这个模子生成对应类型的代码
3. 模板相较于函数重载有什么优点?
函数重载:形参列表不同的一类同名函数
优点:(个人理解)
- 灵活: 使用函数重载时,如果有新的类型出现就需要增加对应类型的重载函数。模板再出现新类型调用时会自动生成对应类型的代码
- 代码量少:不同类型调用同名函数,重载需要实现所有类型的代码。模板只有一份就可以实现内置类型或自定义类型的调用(模板在调用之后生成的代码和重载实现的代码相同–其实就是不想写那么多)
- 解决问题的难度降低:在函数重载中,如果有一个重载函数中出现问题,往往伴随着连锁反应,每一个重载函数都会报错。在模板中可以较快找到问题。
- 提高代码的利用率:重载的多个函数并不会立即被调用,甚至是整个程序运行期间都没有用到。模板会在需要的时候根据模板生成对应的代码。
注:用函数模板只能用于 函数的参数个数相同而类型不同的情况,如果参数个数不同,则不能使用函数模板。
二、函数模板
1. 函数模板实例化在什么时候?
编译阶段,编译器根据传入的实参类型就行推演生成对应类型的函数
2. 概念:
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型生成对应类型的特定类型版本。
3. 关键字
template <typename/class T>
typename或class都可以用来表示类型占用,常见的为class,但是不能用struct代替class
// 使用时与正常函数相同
// 返回值类型 函数名(参数列表){}
例:
template <class T>
void swap(T& a, T& b);
4. 实例化
用不同类型参数使用模板时,称为函数模板的实例化。
隐式实例化(相似于强转):让编译器根据实参类型推演模板参数的实际类型
显示实例化(函数名 <类型>(形参列表) ):在函数名后加<>中指定模板参数的实际类型
5. 匹配规则
非模板函数与模板函数共存时,优先非模板参数
非模板函数与模板函数共存时,模板函数生成的函数更加匹配参数类型,使用模板函数
非模板函数和模板函数共存时,指定显式实例化,使用模板函数
三、类模板
1. 定义方式
template <class T1, class T2, ..., class Tn>
class 类
{}
2. 使用
外部使用时,需要显示实例化,不能隐式实例化。
类 <类型> 变量; 例:data d1;
3. []重载
[] 的重载需要提供两种接口:
// 可读可写
T& operator[] (size_t pos)
// 只读
const T& operator[] (size_t pos) const
4. 普通类和模板类的区别
类模板名字不是真正的类,实例化的结果才是真正的类
普通类: 类名:SeqList 类型:SeqList
模板类: 类名:Vector 类型:Vector
模板类不是真正的类,时编译器根据实例化的类型生成具体类的模具