一、模版的概念
- 特点
- 模版只是一个框架,不可以直接使用
- 模版不是万能的
二、模版的基本语法
- 泛型编程的主要技术就是模版
- C++中提供两种模版机制:函数模版和类模版
- 作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型代表
- 语法
template<typename T>
函数声明或者定义
- 解释
- template - 声明创建模版
- typename - 表明其后边的符号是一种数据类型,可以用class代替
- T - 通用的数据类型,名称可以替换,通常为大写字母
- 模版的使用有两种方式:自动类型推导、显示指定类型
- 模版的目的是为了提高复用性,将类型参数化
三、函数模版
- 注意事项
- 自动类型推导,必须推导出一致的数据类型T才可以使用
- 模版必须要确定出T的数据类型才可以使用
- 函数模版案例:对整数数组和字符串进行排序
四、普通函数和函数模版的区别
- 普通函数调用可以发生隐式类型转换
- 函数模板用自动类型推导不可以发生隐式类型转换
- 函数模版用显示指定类型可以发生隐式类型转换
- 建议使用显示指定类型使用函数模版
五、普通函数和函数模版的调用规则
- 如果函数模版和普通函数都可以调用,优先调用普通函数
- 可以通过空模板参数列表强制调用函数模版
- 函数模版可以发生函数重载
- 如果函数模版可以产生更好的匹配,优先调用函数模板
- 提供了函数模版就不要提供普通函数,容易出现二义性
六、模版的局限性
- 有些特定的数据类型需要用具体化的方式做特殊实现
- 利用具体化的模版,可以解决自定义类型的通用化
- 学习模版不是为了写模版,而是在STL能够运用系统提供的模版
七、类模版
7.1 类模板的语法
template<typename T1, typename T2, ...> 类
7.2 类模版和函数模版的区别
- 类模版没有自动类型推导使用方式
- 类模板在参数列表中可以有默认值
7.3 类模板中的成员函数创建时机
- 普通类中成员函数在一开始就创建
- 类模版中的成员函数在被调用时才会创建
7.4 类模版对象做函数参数
- 指定传入的类型(最常用) ```Cpp template<class T1, class T2> class Person{ public: void showPerson(){ cout « “姓名:” « m_Name « ” 年龄:” « m_Age « endl; } T1 m_Name; T2 m_Age; };
void printPerson(Person
&p){ p.showPerson(); } 1. 参数模版化 ```Cpp void printPerson(Person<T1, T2>&p){ p.showPerson(); // 查看T1和T2的数据类型 cout << "T1的数据类型为:" << typeid(T1).name() << endl; cout << "T2的数据类型为:" << typeid(T2).name() << endl; }
1. 整个类模版化 ```Cpp template<class T> void printPerson(T &p){ p.showPerson(); } ``` #### 7.5 类模板与继承
- 必须知道父类中的T类型,才能继承父类
- 如果想灵活指定父类中的T类型,子类也需要变成类模板
7.6 类模板成员函数类外实现
- 类模板类成员函数类外实现时,需要加上模版参数列表
7.7 类模板分文件编写问题以及解决
- 类模板分文件编写时由于成员函数后创建,可能连接不到文件
- 解决方法:
- 直接包含源文件.cpp
- 头文件和实现文件写在一起.hpp
7.8 类模板与友元
7.8.1 全局函数类内实现(推荐)
7.8.2 全局函数类外实现
7.8 类模板案例
- 案例描述:实现一个通用的数组类,要求如下:
- 可以对内置数据类型以及自定义的数据类型的数据进行存储
- 将数组中的数据存储到堆区
- 构造函数中可以传入数组的容量
- 提供对应的拷贝构造函数以及operator=防止浅拷贝问题
- 提供尾插法和尾删法对数组中的数据进行增加和删除
- 可以通过下标的方式访问数组中的元素
- 可以获取数组中当前元素的个数和数组的容量