C++ 提高编程

news2024/11/23 20:12:28

C++ 提高编程
主要针对C++泛型编程和STL技术

一、 模板
1、 概念
模板就是建立通用的模具,大大提高代码的复用性

模板特点

模板不可以直接使用,它只是一个框架
​ 模板的通用并不是万能的
2、 函数模板
C++ 另一种编程思想为泛型编程,主要利用的技术就是模板
C++ 提供两种模板机制:函数模板 和 类模板
2.1 函数模板语法
函数模板的作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体确定,用一个虚拟的类型来代表

语法

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

参数

template:声明创建模板
typename:表明其后面的符号是一种数据类型,可以用class来代替
T:通用的数据类型,名称可以替换,通常为大写字母

// 两个整型交换函数
void swap(int& a, int& b)
{
	int temp = a;
	a = b; 
	b = temp;
}
// 交换浮点型的函数
void swap(double& a, double& b)
{
	double temp = a;
	a = b;
	b = temp;
}
// 函数模板
template <typename T>  // 声明模板,告诉编译器后面代码紧跟着T,不要报错,T是一个通用的数据类型
void m_swap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}
void test()
{
	int a = 1;
	int b = 3;
	double a1 = 4;
	double b1 = 5;
	/* swap(a, b);
	cout << a << b << endl;
	swap(a1, b1);
	cout << a1 << b1 << endl; */
	// 使用函数模板
	// 1、 自动推导
	m_swap(a, b);
	cout << a << b << endl;
	// 2、 显示指定类型
	m_swap<int>(a, b);
	cout << a << b << endl;
}

模板可以将数据类型参数化

模板的使用方法

自动推导
显示指定类型
2.2 注意事项
注意事项

自动推导数据类型,必须推导出一致的数据类型 T,才可以使用
模板必须要确定出 T 的数据类型,才可以使用
2.3 普通函数和函数模板的区别
普通函数调用时可以发生自动类型转换(隐式类型装换)
函数模板调用时,如果利用自动类型推导,不会发生隐式类型装换
如果利用显示指定类型的方法,可以发生隐式类型转换
2.4 普通函数和函数模板的调用规则
调用规则如下

如果函数模板和普通函数都可以实现,优先调用普通函数

可以通过空模板参数列表强制调用函数模板

void myPrint(int a, int b)
{
	cout << a << b << endl;
	cout << "普通函数" << endl;
}
template<typename T>
void myPrint(T a, T b)
{
	cout << a << b << endl;
	cout << "模板函数" << endl;
}

void test()
{
	int a = 10;
	int b = 20;
	myPrint<>(a, b);  // 空模板参数列表调用模板函数
}

函数模板也可以发生重载

如果函数模板可以产生更好的匹配模式,优先调用函数模板

void myPrint(int a, int b)
{
	cout << a << b << endl;
	cout << "普通函数" << endl;
}
template<typename T>
void myPrint(T a, T b)
{
	cout << a << b << endl;
	cout << "模板函数" << endl;
}

void test()
{
	char a = 'a';
	char b = 'b';
	myPrint(a, b);  // 函数模板可以产生更好的匹配 
}

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

2.5 模板的局限性
模板的通用性并不是万能的
如果传入的是一个元组以及自定义数据类型,就无法实现了

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

// 模板重载
// 对比两个数据是否相等
class Person
{
public:
	Person(string name, int age)
	{
		m_Age = age;
		m_Name = name;
	}
	string m_Name;
	int m_Age;
};
template<class T>
bool myCompare(T& a, T& b)  // 如果传入的是一个自定义数据类型呢
{
	if (a == b)
	{
		return true;
	}
	else
	{
		return false;
	}
}
// 利用具体化Person的版本实现代码,具体化优先调用
// 也可以使用运算符重载
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 test()
{
	Person p1("Tom", 10);
	Person p2("Tom", 10);
	cout << myCompare(p1, p2) << endl;
}

学习模板并不是为了写模板,而是在STL中能够运用系统提供的模板

3、 类模板
3.1 类模板语法
类模板作用

建立一个通用类,类中成员数据类型可以不具体制定,用一个虚拟的类型代表
语法

template<typename T>
参数

template:声明创建模板
typename:表明其后面的符号是一种数据类型,可以用class来代替
T:通用的数据类型,名称可以替换,通常为大写字母
template<typename NameT, typename AgeT>
class Person
{
public:
	Person(NameT name, AgeT age)
	{
		m_Age = age;
		m_Name = name;
	}
	NameT m_Name;
	AgeT m_Age;
};
void test()
{
	Person<string, int>("Tom", 30);  // 调用-只有一种调用方式
}

3.2 类模板和函数模板的区别
类模板与函数模板区别主要有两点

类模板没有自动类型推导的使用方式

类模板在模板参数列表中可以有默认参数

template<typename NameT, typename AgeT = int>  // 默认参数
class Person
{
public:
	Person(NameT name, AgeT age)
	{
		m_Age = age;
		m_Name = name;
	}
	NameT m_Name;
	AgeT m_Age;
};
void test()
{
	Person<string>("Tom", 30);
}

3.3 使用时机
类模板中成员函数和普通类中成员函数创建时机是有区别的

普通类中的成员函数一开始就可以创建
类模板中的成员函数在调用时才创建

class Person1
{
public:
	void show()
	{
		cout << "Person1" << endl;
	}

};

template<typename T>
class Person
{
public:
    // 没调用,其不会编译,因为无法确定T的数据类型
	T p1;
	void func1()
	{
		p1.show();
	}
	
};
void test()
{
	Person<Person1> p;
	p.func1();
}

3.4 类模板对象函数做参数
类模板实例出的对象,向函数传参

一共有三种传入方式

指定传入的数据类型:直接显示对象的数据类型

// 类模板做函数的参数
template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age)
	{
		m_Name = name;
		m_Age = age;
	}
	T1 m_Name;
	T2 m_Age;
	void showPerson()
	{
		cout << "name:" << m_Name << " age:" << m_Age << endl;
	}
};
// 指定传入类型
void printPerson1(Person<string, int> &p)  
{
	p.showPerson();
}
// 参数模板化
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{
	p.showPerson();
	cout << "T1的类型为:" << typeid(T1).name() << endl;
	cout << "T2的类型为:" << typeid(T2).name() << endl;
}
// 整个类模板化
template<class T>
void printPerson3(T &p)
{
	p.showPerson();
}
void test()
{
	Person<string, int> p("Tom", 12);
	printPerson1(p);
	printPerson2(p);
	printPerson3(p);
}

二、 STL 初识
1、 基本概念
STL 基本模板库
STL 从广义上分为容器、算法和迭代器
容器和算法事件通过迭代器无缝连接
STL 几乎所有的代码都采用了模板类或模板函数
2、 STL 六大组件
STL 大体分为六大组件:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

容器:各种数据结构:vector、list、deque、set、map等,用来存放数据
算法:各种常用的算法,如sort、find、copy、for_each等
迭代器:扮演了容器和算法之间的胶合剂
仿函数:行为类似的函数,可作为算法的某种策略
适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
空间配置器:负责空间的配置和管理
2.1 容器、算法、迭代器
容器:置物之所也

STL 容器就是将运用最广泛的一些数据结构实现出来

常用的数据结构:数组、列表、树、栈、队列、集合、映射表等

这些容器分为序列式容器和关联式容器两种

序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
算法:问题之解也

有限的步骤,解决逻辑或数学上的问题,这叫做算法

算法分为:质变算法和非质变算法

质变算法:是指运算过程中会更改区间内的元素的内容,例如拷贝、替换、删除等等
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等
迭代器:容器和算法之间粘合剂

提供一种方法,使之能够依序寻访某个容器所含有的各个元素,而又无需暴露该容器的内部表示方式

每个容器都有自己专属的迭代器

迭代器使用非常类似于指针

迭代器种类
在这里插入图片描述
常用的容器中迭代器种类为双向迭代器和随机访问迭代器

3、 迭代器初始
3.1 vector 存放内置数据类型
容器:vector

算法:for_each

迭代器:vector::iterator

#include <vector>  // vector 头文件
#include <algorithm>  // 标准算法头文件

void printVector(int value)
{
	cout << value << endl;
}
// vector 存放内置数据类型
void test()
{
	// 创建一个 vector 容器——数组
	vector<int> v;

	// 向容器中插入数据
	v.push_back(10);  // 尾插数据
	v.push_back(11);
	v.push_back(12);

	// 通过迭代器访问容器中的数据
	vector<int>::iterator itBegin = v.begin(); // 起始迭代器,指向容器中第一个元素,当做指针使用
	vector<int>::iterator itEnd = v.end();  // 结束迭代器,指向容器最后一个元素的下一个位置

	// 第一种遍历方式
	while (itBegin != itEnd)
	{
		cout << *itBegin << endl;
		itBegin++;
	}
	// 第二种遍历方式
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << endl;
	}
	// 第三种遍历方式
	for_each(v.begin(), v.end(), printVector);  // 回调函数
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/795276.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT如何帮助学生学习

​ 一些教育工作者担心学生可能使用ChatGPT作弊。因为这个AI工具能写报告和计算机代码&#xff0c;画出复杂图表……甚至已经有许多学校把ChatGPT屏蔽。 研究发现&#xff0c;学生作弊的主要原因是想考得好。是否作弊与作业和考试的打分方式有关&#xff0c;所以这与技术的便…

浅谈前端跨平台框架

概述 前端跨端实践是指在开发过程中&#xff0c;使用统一的代码库或框架来实现在不同平台上运行的应用程序。 这种实践旨在减少重复开发和维护成本&#xff0c;并提高开发效率和用户体验。 以下是一些前端跨端实践的方法和技术&#xff1a; 响应式设计&#xff08;Responsiv…

0-虚拟机补充知识

虚拟机克隆 如果想要构建服务器集群&#xff0c;没有必要一台一台的去进行安装&#xff0c;只要通过克隆就可以。 快速获得多台服务器主要有两种方式&#xff0c;分别为&#xff1a;直接拷贝操作和vmware的克隆操作 直接拷贝 将之前安装虚拟机的所有文件进行拷贝&#xff0…

聊聊单片机编程测量电机的电流

要测量电机的电流&#xff0c;可以使用电流传感器来实现。常见的电流传感器有霍尔效应传感器和电阻式传感器。 在单片机编程中&#xff0c;可以通过 ADC&#xff08;模拟数字转换器&#xff09;模块来实现对电流传感器输出电压的采样和转换。下面是一个简单的步骤&#xff1a;…

笔记本充满电后,充电器可以长期不拔,会有安全隐患吗?

笔记本充满电后&#xff0c;一直插着不拔 1.建议人在身边可以暂时不拔&#xff0c;偶尔还是要使用电池当笔记本电池充满之后&#xff0c;电脑会自动使用电源供电&#xff0c;不会使用电池供电 2.笔记本电池都带有电池保护机制&#xff0c;在电池充满电后会自动停止充电 3.现在…

Ceph的应用

文章目录 一、创建 CephFS 文件系统 MDS 接口1&#xff09;在管理节点创建 mds 服务2&#xff09;查看各个节点的 mds 服务3&#xff09;创建存储池&#xff0c;启用 ceph 文件系统4&#xff09;查看mds状态&#xff0c;一个up&#xff0c;其余两个待命&#xff0c;目前的工作的…

Python - Opencv + pyzbar实时摄像头识别二维码

直接上代码&#xff1a; import cv2 from pyzbar.pyzbar import decodecap cv2.VideoCapture(0) # 打开摄像头while True: # 循环读取摄像头帧ret, frame cap.read()# 在循环中&#xff0c;将每一帧作为图像输入&#xff0c;使用pyzbar的decode()函数识别二维码barcodes …

gitignore文件使用方法(gitignore教程)(git status --ignored)(git check-ignore -v <file>)

文章目录 Gitignore文件使用描述Gitignore基本语法1. 基本语法★★★★★2. 配置方法 匹配示例示例1示例2示例3 其他命令git status --ignored&#xff08;用于显示被Git忽略的文件和文件夹的状态&#xff09;git check-ignore -v <file>&#xff08;用于检查指定文件是否…

springMVC--异常处理

文章目录 springMVC--异常处理基本介绍局部异常应用实例演示局部异常处理机制代码实现测试(页面方式) 全局异常应用实例应用实例需求代码实现完成测试(页面方式) 自定义异常应用实例应用实例需求应用实例-代码实现完成测试 全局异常处理---SimpleMappingExceptionResolver基本说…

Docker 阿里云容器镜像服务

阿里云-容器镜像服务ACR 将本地/服务器docker image&#xff08;镜像&#xff09;推送到 阿里云容器镜像服务仓库 1. 在容器镜像服务ACR中创建个人实例 2. 进入个人实例 > 命名空间 创建命名空间 3. 进入个人实例 > 镜像仓库 创建镜像仓库 4. 进入镜像仓库 > 基本信…

商品分类新建,修改,删除。手机扫码开单打印进销存,商贸批发生产企业仓库条码管理软件系统

商品分类新建&#xff0c;手机扫码开单打印进销存&#xff0c;商贸批发生产企业仓库条码管理软件系统&#xff0c;超市便利店五金茶叶烟酒鞋帽门店零售手机收银管理软件APP_哔哩哔哩_bilibili本期视频讲解&#xff1a;商品分类新建, 视频播放量 1、弹幕量 0、点赞数 0、投硬币枚…

小程序picker 在苹果手机不兼容 bug,按month时在iPhone 显示不正确及自动定位时间问题

如下图&#xff1a;点击弹出时间列表&#xff1a;日历控件点击选择显示1年1月 解决: 加上起始时间字段 <picker mode"date" value"{{date}}" start"1970-09-01" end"2030-09-01"></picker> 问题二&#xff1a; 还是&a…

vant-ui,DatetimePicker时间选择器选择到秒

vant-ui的DatetimePicker 组件只能选择年月日时分&#xff0c;可能是组件维护者认为秒的选择用途不多&#xff0c;但是今天的需求中就是需要选择年月日时分秒所以就对DatetimePicker的组件封装成了可以选择年月日时分秒&#xff0c;直接上代码&#xff1a; 封装成组件&#xf…

【电源芯片】电量计(Gauge)介绍

对于电池供电的产品,比如手机、笔记本电脑、电动车等,我们都希望知道其电池还剩多少电、还能用多久,以便我们能放心使用,避免使用过程中电量用光而宕机。并且客户已经受到智能手机影响,需要其他更低端的设备也能有1%的电量显示,不再像以前的小灵通或是诺基亚手机那样只会…

2 Linux基础篇-Linux入门

2Linux基础篇-Linux入门 文章目录 2Linux基础篇-Linux入门2.1 Linux介绍2.2 Linux和Unix的关系 学习视频来自于B站 【小白入门 通俗易懂】2021韩顺平 一周学会Linux。 2.1 Linux介绍 常见的操作系统有 Windows、MacOS、Android、ios、Linux、Unix等。而其中&#xff0c;Linux是…

【C语言】动态内存管理详解

目录 为什么存在动态内存分配 动态内存函数的介绍 malloc 和 free calloc realloc 常见的动态内存错误 对NULL指针的解引用操作 对动态开辟空间的越界访问 对非动态开辟内存使用free释放 使用free释放一块动态开辟内存的一部分 对同一块动态内存多次释放 动态开辟内存忘记释放&…

视频标注是什么?和图像数据标注的区别?

视频数据标注是对视频剪辑进行标注的过程。进行标注后的视频数据将作为训练数据集用于训练深度学习和机器学习模型。这些预先训练的神经网络之后会被用于计算机视觉领域。 自动化视频标注对训练AI模型有哪些优势 与图像数据标注类似&#xff0c;视频标注是教计算机识别对象…

DHCP部署与安全详解

文章目录 一、DHCP是什么&#xff1f;二、DHCP相关概念三、DHCP优点四、DHCP原理1. 客户机发送DHCP Discovery广播包&#xff08;发现谁是DHCP服务器&#xff09;2. 服务器响应DHCP Offer广播包3. 客户机发送DHCP Request广播包4. 服务器发送DHCP ACK广播包 五、DHCP续约六、部…

020 - like

LIKE&#xff1a;操作符用于在 WHERE 子句中搜索列中的指定模式。 语法&#xff1a; SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern; -- 查询columnm字段名中以C开头的内容&#xff0c;%表示字母C后面可以是任意内容 select * from table名 where c…

IPv4 over IPv6简介

在IPv4 Internet向IPv6 Internet过渡的后期&#xff0c;IPv6网络已被大量部署&#xff0c;此时可能出现IPv4孤岛。利用隧道技术可在IPv6网络上创建隧道&#xff0c;从而实现IPv4孤岛的互连。这类似于在IP网络上利用隧道技术部署VPN。在IPv6网络上用于连接IPv4孤岛的隧道&#x…