3 c++编程-提高篇-模版
重新系统学习c++语言,并将学习过程中的知识在这里抄录、总结、沉淀。同时希望对刷到的朋友有所帮助,一起加油哦!
生命就像一朵花,要拼尽全力绽放!死磕自个儿,身心愉悦!
系列文章列表:
写在前面,本篇章主要针对泛型编程学习。
1 模版
1.1 模版的概念
模版就是建立通用模具,减少重复工作量。
生活中也有很多使用模版的例子。例如:
ppt模版: 年度总结ppt模版
报表模版: 月度数据报表模版
模版的特点:
- 模版不可以直接使用,它只是一个框架。使用时需要自己填充业务特性的东西。
- 模版的通用并不是万能的,只适用于某些特定类型的场景。
1.2 函数模版
c++另一种编程思想称为 泛型编程,主要利用的技术就是模版。
c++提供两种模版机制: 函数模版 和 类模版
1.2.1 函数模版语法
函数模版的作用:
给定一个通用函数,其函数返回值类型和形参类型都可以不具体给定,用一个虚拟的类型来代替。
语法:
template<typename T>
函数声明或定义
解释:
- template:声明要创建模版
- typename:表明其后的符号是一种数据类型。告诉编译器不要报错。typename可用class代替
- T:通用数据类型。可以写成其他,通常为大写字母,例如 X或Y等。
调用使用模版函数的方式:
- 自动类型推导
- 显式指定数据类型
示例:
1.2.2 函数模版注意事项
注意事项:
- 自动类型推导,必须推导出一致的数据类型T,才可以使用
- 模板必须要确定出T的数据类型,才可以使用
示例:
1.2.3 函数模版案例
案例:
- 利用模版的技术封装一个排序函数,可以对不同数据类型进行排序;
- 排序规则从大到小,排序算法为选择排序;
- 用char数组和int数组进行测试;
示例:
1.2.4 普通函数与函数模版的区别
区别:
- 普通函数 调用可以发生隐式类型转换
- 函数模版 用自动类型推导,不可以发生隐式类型转换
- 函数模版 用显式指定类型,可以发生隐式类型转换
示例:
1.2.5 普通函数与函数模版的调用规则
调用规则:
- 如果普通函数和函数模版都有实现,优先调用普通函数;
- 可以通过空模版参数列表来强制调用函数模版;
- 函数模版也可以发生重载;
- 如果模版函数可以产生更好的匹配,优先调用函数模版;
示例:
1.2.6 模版的局限性
模版并不是万能的,有些特定的数据类型,需要用具体化模版方式来实现。
例如:
在上述a=b;的赋值代码中,如果传入的a和b是数组,就无法实现,编译会报错。
示例:
1.3 类模版
1.3.1 类模版语法
作用:建立一个通用类,类中的成员数据类型可以不固定,用虚拟类型来指定。
语法:
示例:
1.3.2 类模版与函数模版的区别
- 类模版没有自动堆导使用方式
- 类模版中的模版参数列表可以有默认数据类型
示例:
1.3.3 类模版中成员函数创建时机
普通类和类模版中成员函数的创建时机不同:
- 普通类中的成员函数在 一开始 就创建;
- 类模版中的成员函数在 调用时 才创建;
示例:
1.3.4 类模版对象做函数参数
类模版对象做函数参数共有三种形式:
- 指定传入类型--直接显式的使用数据类型做函数参数 (最常用的形式)
- 参数模版化--将类对象中的参数模版化来做函数参数
- 整个类模版化--将类对象模版化来做函数参数
示例:
1.3.5 类模版与继承
要继承类模版,需要注意:
- 当子类继承的父类是一个类模版时,子类在声明时,需要指定父类中T的数据类型。——如果不指定父类T的数据类型,编译器无法给子类分配内存,会编译不通过。
- 如果想灵活继承父类中T的数据类型,子类也需要定义成类模版。
示例:
1.3.6 类模版成员函数类外实现
示例:
1.3.7 类模版分文件编写
问题:
普通类分文件编写,会直接将类分成头文件a.h文件和源文件a.cpp文件。然后在调用程序中添加#include "a.h",程序就直接调用类成员函数。但是,如果是类模版,该方式分文件编写及调用会出现编译问题。
原因:
类模版中成员函数是在调用时才创建,直接添加 .h会找不到函数。
解决办法:
方法1:直接包含.cpp源文件。
方法2:将声明和实现写在一起,不要分文件编写,并将文件名后缀写成.hpp。.hpp是大家约 定的类模版文件名写法,不是强制的。——常用方式
1.3.8 类模版与友元
全局函数类内实现:
直接在类内声明是友元即可;
全局函数类外实现:
(1) 需要提前让编译器知道类模版;
(2) 需要提前让编译器知道全局函数存在;
示例: