【C++提高编程】C++全栈体系(十六)

news/2025/3/25 13:34:11/

C++提高编程

第一章 模板

一、模板的概念

模板就是建立通用的模具,大大提高复用性

例如生活中的模板

一寸照片模板:
在这里插入图片描述
PPT模板:
在这里插入图片描述
在这里插入图片描述
模板的特点:

  • 模板不可以直接使用,它只是一个框架
  • 模板的通用并不是万能的

二、函数模板

  • C++另一种编程思想称为 泛型编程 ,主要利用的技术就是模板

  • C++提供两种模板机制:函数模板类模板

1. 函数模板语法

函数模板作用:

建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。

语法:

template<typename T>
函数声明或定义

解释:

template — 声明创建模板

typename — 表面其后面的符号是一种数据类型,可以用class代替

T — 通用的数据类型,名称可以替换,通常为大写字母

示例:

//交换整型函数
void swapInt(int& a, int& b) {int temp = a;a = b;b = temp;
}//交换浮点型函数
void swapDouble(double& a, double& b) {double temp = a;a = b;b = temp;
}//利用模板提供通用的交换函数
template<typename T>
void mySwap(T& a, T& b)
{T temp = a;a = b;b = temp;
}void test01()
{int a = 10;int b = 20;//swapInt(a, b);//利用模板实现交换//1、自动类型推导mySwap(a, b);//2、显示指定类型mySwap<int>(a, b);cout << "a = " << a << endl;cout << "b = " << b << endl;}int main() {test01();system("pause");return 0;
}/*a = 10b = 20
*/

总结:

  • 函数模板利用关键字 template
  • 使用函数模板有两种方式:自动类型推导、显示指定类型
  • 模板的目的是为了提高复用性,将类型参数化

2. 函数模板注意事项

注意事项:

  • 自动类型推导,必须推导出一致的数据类型T,才可以使用

  • 模板必须要确定出T的数据类型,才可以使用

示例:

//利用模板提供通用的交换函数
template<class T>
void mySwap(T& a, T& b)
{T temp = a;a = b;b = temp;
}// 1、自动类型推导,必须推导出一致的数据类型T,才可以使用
void test01()
{int a = 10;int b = 20;char c = 'c';mySwap(a, b); // 正确,可以推导出一致的T//mySwap(a, c); // 错误,推导不出一致的T类型
}// 2、模板必须要确定出T的数据类型,才可以使用
template<class T>
void func()
{cout << "func 调用" << endl;
}void test02()
{//func(); //错误,模板不能独立使用,必须确定出T的类型func<int>(); //利用显示指定类型的方式,给T一个类型,才可以使用该模板
}int main() {test01();test02();system("pause");return 0;
}

总结:

  • 使用模板时必须确定出通用数据类型T,并且能够推导出一致的类型

3. 函数模板案例

案例描述:

  • 利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序
  • 排序规则从大到小,排序算法为选择排序
  • 分别利用char数组int数组进行测试

示例:

//交换的函数模板
template<typename T>
void mySwap(T &a, T&b)
{T temp = a;a = b;b = temp;
}template<class T> // 也可以替换成typename
//利用选择排序,进行对数组从大到小的排序
void mySort(T arr[], int len)
{for (int i = 0; i < len; i++){int max = i; //最大数的下标for (int j = i + 1; j < len; j++){if (arr[max] < arr[j]){max = j;}}if (max != i) //如果最大数的下标不是i,交换两者{mySwap(arr[max], arr[i]);}}
}
template<typename T>
void printArray(T arr[], int len) {for (int i = 0; i < len; i++) {cout << arr[i] << " ";}cout << endl;
}
void test01()
{//测试char数组char charArr[] = "bdcfeagh";int num = sizeof(charArr) / sizeof(char);mySort(charArr, num);printArray(charArr, num);
}void test02()
{//测试int数组int intArr[] = { 7, 5, 8, 1, 3, 9, 2, 4, 6 };int num = sizeof(intArr) / sizeof(int);mySort(intArr, num);printArray(intArr, num);
}int main() {test01();test02();system("pause");return 0;
}/*h g f e d c b a  9 8 7 6 5 4 3 2 1 
*/

总结:模板可以提高代码复用,需要熟练掌握

4. 普通函数与函数模板的区别

普通函数与函数模板区别:

  • 普通函数调用时可以发生自动类型转换(隐式类型转换)
  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显示指定类型的方式,可以发生隐式类型转换

示例:

//普通函数
int myAdd01(int a, int b)
{return a + b;
}//函数模板
template<class T>
T myAdd02(T a, T b)  
{return a + b;
}//使用函数模板时,如果用自动类型推导,不会发生自动类型转换,即隐式类型转换
void test01()
{int a = 10;int b = 20;char c = 'c';cout << myAdd01(a, c) << endl; //正确,将char类型的'c'隐式转换为int类型  'c' 对应 ASCII码 99//myAdd02(a, c); // 报错,使用自动类型推导时,不会发生隐式类型转换myAdd02<int>(a, c); //正确,如果用显示指定类型,可以发生隐式类型转换
}int main() {test01();system("pause");return 0;
}/*109
*/

总结:建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T

5. 普通函数与函数模板的调用规则

调用规则如下:

  1. 如果函数模板和普通函数都可以实现,优先调用普通函数
  2. 可以通过空模板参数列表来强制调用函数模板
  3. 函数模板也可以发生重载
  4. 如果函数模板可以产生更好的匹配,优先调用函数模板

示例:

//普通函数与函数模板调用规则
void myPrint(int a, int b)
{cout << "调用的普通函数" << endl;
}template<typename T>
void myPrint(T a, T b) 
{ cout << "调用的模板" << endl;
}template<typename T>
void myPrint(T a, T b, T c) 
{ cout << "调用重载的模板" << endl; 
}void test01()
{//1、如果函数模板和普通函数都可以实现,优先调用普通函数// 注意 如果告诉编译器  普通函数是有的,但只是声明没有实现,或者不在当前文件内实现,就会报错找不到int a = 10;int b = 20;myPrint(a, b); //调用普通函数//2、可以通过空模板参数列表来强制调用函数模板myPrint<>(a, b); //调用函数模板//3、函数模板也可以发生重载int c = 30;myPrint(a, b, c); //调用重载的函数模板//4、 如果函数模板可以产生更好的匹配,优先调用函数模板char c1 = 'a';char c2 = 'b';myPrint(c1, c2); //调用函数模板
}int main() {test01();system("pause");return 0;
}/*调用的普通函数调用的模板调用重载的模板调用的模板
*/

总结:既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性

6. 模板的局限性

局限性:

  • 模板的通用性并不是万能的

例如:

	template<class T>void f(T a, T b){ a = b;}

在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了

再例如:

	template<class T>void f(T a, T b){ if(a > b) { ... }}

在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行

因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板

示例:

#include<iostream>
using namespace std;#include <string>class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age;
};//普通函数模板
template<class T>
bool myCompare(T& a, T& b)
{if (a == b){return true;}else{return false;}
}//具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型
//具体化优先于常规模板
template<> bool myCompare(Person &p1, Person &p2)
{if ( p1.m_Name  == p2.m_Name && p1.m_Age == p2.m_Age){return true;}else{return false;}
}void test01()
{int a = 10;int b = 20;//内置数据类型可以直接使用通用的函数模板bool ret = myCompare(a, b);if (ret){cout << "a == b " << endl;}else{cout << "a != b " << endl;}
}void test02()
{Person p1("Tom", 10);Person p2("Tom", 10);//自定义数据类型,不会调用普通的函数模板//可以创建具体化的Person数据类型的模板,用于特殊处理这个类型bool ret = myCompare(p1, p2);if (ret){cout << "p1 == p2 " << endl;}else{cout << "p1 != p2 " << endl;}
}int main() {test01();test02();system("pause");return 0;
}/*a != b p1 == p2 
*/

总结:

  • 利用具体化的模板,可以解决自定义类型的通用化
  • 学习模板并不是为了写模板,而是在STL能够运用系统提供的模板
文章来源:https://blog.csdn.net/sgsgkxkx/article/details/128895689
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/news/22931.html

相关文章

简易版扫雷游戏实现

前言&#xff1a;小伙伴们大家好&#xff0c;上一次我们讲解了三子棋的游戏实现今天我们一起来学习扫雷游戏的实现。开始的设置过程和三子棋的一致&#xff0c;这里就不再过多赘述了。直接上代码设计游戏初始化数组我们需要在一个棋盘上布置雷&#xff0c;在另一个棋盘上存放雷…

ABB机器人安全板硬件功能介绍+接线方法示例

ABB机器人安全板硬件功能介绍+接线方法示例 ABB机器人有以下几种硬件停止功能,这些均属于EN 13849-1中描述的安全类别3,该安全类别是双通道发起的停止,如果发生单通道故障(例如接线不良),则会发生安全链报警。 ES1,ES2紧急停止;AS1,AS2自动模式停止(一般连接安全门、光…

Vue-VueRouter

前言 Vue Router 是 Vue.js (opens new window)官方的路由管理器。它和 Vue.js 的核心深度集成&#xff0c;让构建单页面应用变得易如反掌。包含的功能有&#xff1a; 嵌套的路由/视图表模块化的、基于组件的路由配置路由参数、查询、通配符基于 Vue.js 过渡系统的视图过渡效果…

Openharmony的用户态应用通过HDF框架驱动消息机制实现的通信实例

承接上文一个例子了解通过Openharmony的HDF框架实现简易驱动的流程&#xff0c;实现到了test_hdf_newdevice1设备的驱动。应用或服务如何与此设备通过HDF的框架的驱动消息机制&#xff0c;进行通信&#xff1f;依旧以Openharmony中的V3.1 版本为基座&#xff0c;编写测试代码来…

Ajax 原生请求方法

<html> <head> <script type"text/javascript" src"/jquery/jquery.js"></script> <script type"text/javascript"> //创建XMLHttpRequest 对象 //参数&#xff1a;无 //返回值&#xff1a;XMLHttpRequest 对象 f…

AC耦合电容位置对信号的影响

AC耦合电容位置对信号的影响 上期文章说到&#xff0c;电容焊盘对整个无缘通道的影响&#xff0c;仿真观察了焊盘大小&#xff0c;焊盘参考层掏空尺寸&#xff0c;以及具体参考哪一层。 单从焊盘这一点来看&#xff0c;可以看到阻抗一般会比较小&#xff0c;但是对信号未必造…

支付系统核心架构设计思路(万能通用)

文章目录1. 支付系统总览核心系统交互业务图谱2. 核心系统解析交易核心交易核心基础交易类型抽象多表聚合 & 订单关联支付核心支付核心总览支付行为编排异常处理渠道网关资金核算3. 服务治理平台统一上下文数据一致性治理CAS校验幂等 & 异常补偿对账准实时对账DB拆分异…

【C++提高编程】list 容器详解(附测试用例与结果图)

目录1. list容器1.1 list基本概念1.2 list构造函数&#xff08;初始化&#xff09;1.3 list 赋值和交换1.4 list 大小操作1.5 list 插入和删除1.6 list 数据存取1.7 list 反转&#xff08;reverse&#xff09;、排序&#xff08;sort&#xff09;和去重&#xff08;unique&…