【C++】C++11之新的类功能与可变参数模板

news2025/1/22 9:07:29

目录

一、新的默认成员函数

二、新的关键字

2.1 default

2.2 detele

2.3 final和override

三、可变参数模板

3.1 定义

3.2 递归展开参数包

3.3 逗号表达式展开参数包

3.4 emplace_back

一、新的默认成员函数

在C++11之前,默认成员函数只有六个,而C++11新增了两个默认成员函数,即移动构造函数和移动赋值运算符重载函数

在前面对右值引用的学习中我们已经见过了这两个函数,关于它们的一些特性还有需要注意的地方

  • 如果用户没有显式实现一个移动构造函数,且没有显式实现析构函数、拷贝构造、赋值重载中的任意一个,那么编译器才会自动生成一个默认的移动构造函数
  • 移动赋值重载函数与移动构造同理,只要四个函数都没有被实现,编译器才会生成默认的
  • 移动构造函数会对内置类型成员进行逐字节的浅拷贝,对于自定义类型成员会调用该成员自己的移动构造,如果没有实现移动构造则调用其拷贝构造
  • 移动赋值重载函数与移动构造同理,对内置类型成员进行浅拷贝,对于自定义类型成员会调用该成员自己的移动赋值,如果没有实现移动赋值则调用其拷贝赋值
  • 如果用户已经实现了移动构造和移动赋值,编译器不会生成拷贝构造拷贝赋值

关于右值引用,如果还有不了解的可以移步

【C++】C++11之右值引用-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Eristic0618/article/details/140826229?spm=1001.2014.3001.5502


二、新的关键字

2.1 default

前面提到,如果四个默认成员函数被实现了其中一个,编译器就不会生成默认的移动构造函数

但是假如我们就想让编译器给我们生成某个默认的成员函数呢?

在C++11中新增了default关键字,用来显式的指定让某个默认成员函数被生成

例如:

class A
{
public:
	A(int x) //构造
		:_a(x)
	{}

	A(const A& a) //拷贝构造
		:_a(a._a)
	{}

	A(A&& a) = default; //强制生成默认移动构造

private:
	int _a;
};

2.2 detele

与用于释放动态分配的内存空间的delete运算符进行区分,C++11新增的delete关键字与default的功能相反,其功能是可以禁止生成指定的函数。这个功能看似很鸡肋,其实大有妙用

如果我们想让一个类无法被实例化,该如何实现呢?以前我们需要将构造函数定义为私有成员,现在则只需要直接将这个类的构造函数用delete修饰即可,例如:

还有更巧妙的用法,我们知道如果一个函数的参数类型为int,我们还是可以把double类型的参数传入,因为会发生隐式类型转换

但是如果我们不想这样的事情发生,只希望传入的参数就是我们想要的类型,该如何实现呢?

我们只需要再声明一个完全一样的函数,把参数改为double,然后再用delete修饰即可,例如:

2.3 final和override

这两个关键字在我以前的文章中有提到,有兴趣的可以移步【C++】多态-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Eristic0618/article/details/137755151?spm=1001.2014.3001.5502


三、可变参数模板

可变参数列表,即长度不定的参数列表,在过去我们实际上已经接触过可变参数列表了,例如C语言的scanf和printf,其函数参数的数量是不定的

但是在过去,模板参数的数量一直是固定的,直到C++11出现了可变参数模板,模板才能支持可变参数列表。可变参数模板能够支持传入任意个数、任意类型的参数

3.1 定义

首先来看看如何声明一个支持可变参数模板的函数模板:

template <class... Args>
void Print(Args... a)
{}

在class或typename后加上省略号即可声明一个模板参数包。

在函数的参数列表中,通过在模板参数包后加上省略号即可声明一个函数形参参数包,其中包含任意数量的模板参数

但是我们无法通过类似下标等方式来获取其中的参数,只能通过特定方式将参数包展开来获取参数

3.2 递归展开参数包

我们知道,在调用一个函数的时候,我们传入的参数和函数的参数列表是要一一对应的。

利用这个性质,我们让函数的第一个参数是单独的参数,让第二个参数是一个参数包,这样,我们就可以每次将参数包内的第一个参数提取出来,剩余的参数进入第二个参数成为新的参数包

例如:

template<class T>
void Print(const T& val)
{
	cout << val << endl;
}

template<class T, class... Args>
void Print(T val, Args... a)
{
	cout << val << " ";
	Print(a...);
}

int main()
{
	Print(1, 2, 3, 4);
	return 0;
}

像这样,当我们在主函数中传入4个参数,就会调用上面的第二个Print

数字1则进入函数的第一个参数,2、3、4进入第二个参数变为参数包

函数内部将1打印出来,剩余参数继续递归调用自己

等到最后只剩一个参数了,则会调用上面的只有一个参数的Print,结束递归

这种通过递归展开参数包的方式,就需要一个递归终止函数,也就是上面的第一个Print

除此之外,还有一种展开参数包的方式

3.3 逗号表达式展开参数包

这种方式则更为抽象一点,先来看看是如何用逗号表达式来展开一个参数包的

template<class T>
void Print(T& val)
{
	cout << val << " ";
}

template<class... Args>
void Get(Args... a)
{
	int arr[] = { (Print(a), 0)... };
	cout << endl;
	for (auto i : arr) //打印看看数组内的值
	{
		cout << i << " ";
	}
}

int main()
{
	Get(1, 2, 3, 4);
	return 0;
}

首先,逗号表达式会从头到尾执行所有的表达式,其结果是最后一个表达式的值,所以 (Print(a), 0) 会执行一次Print函数并返回0。除此之外还用到了C++11的另一个特性即初始化列表,通过初始化列表来初始化一个变长数组,整个初始化列表{ (Print(a), 0)... }将会展开成sizeof(参数包)个逗号表达式,通过这种方式就可以在构造数组时展开参数包

如果你对上面的过程有疑惑,我们可以将逗号表达式中的Print函数和0换个位置,看看数组的内容会不会改变,前提是Print函数得返回一个值

可以看到,此时逗号表达式的结果就变为了Print函数的返回值,数组的内容也变为了1、2、3、4

3.4 emplace_back

C++11中一些容器多了名为emplace_back的接口,用于在尾部进行元素插入

有人会说,尾插直接用push_back不就好了?emplace_back的优势在哪呢?

首先我们可以看到emplace_back支持了可变参数模板和万能引用,而push_back的参数数量是固定的,这就导致如果容器元素的类型是pair的话,就必须提前用make_pair等构造好再传参

例如:

int main()
{
	list<pair<int, int>> lt2;
	lt2.push_back(make_pair(1, 1));
	return 0;
}

如果换成emplace_back的话,我们就不需要提前构造,直接把参数传入即可,因为emplace_back使用了可变参数列表,不需像push_back一样一次只能传一个参数

完. 

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

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

相关文章

2024华数杯选题建议-建模思路-代码论文助攻

你是否在寻找数学建模比赛的突破点&#xff1f;数学建模进阶思路&#xff01; 作为经验丰富的数学建模团队&#xff0c;我们将为你带来2024 华数杯的全面解析。这个解决方案包不仅包括完整的代码实现&#xff0c;还有详尽的建模过程和解析&#xff0c;帮助你全面理解并掌握如何…

C:关于static 和 extern 关键字的介绍-学习笔记

目录 1、作用域与生命周期 1.1 作用域 1.2 生命周期 1.3 变量的作用域和生命周期之间的关系 2、static 和 extern 2.1 static 修饰局部变量&#xff1a; 2.2 static 修饰全局变量&#xff08;包含extern的作用&#xff09;&#xff1a; 2.3 static修饰函数&#xff1a…

海思RTSP推流第二篇——海思平台和H264编码Demo

前言&#xff1a; 记得行内一个老师说过&#xff0c;基础不牢&#xff0c;地动山摇&#xff0c;对于海思的编码过程还是不是很熟悉所以回头把这个分析一遍。 海思平台&#xff1a; 官方手册&#xff1a;HiMPP IPC V2.0 媒体处理软件开发参考&#xff0c;里面有介绍海思IPC平台的…

polyfit曲线拟合

一、简介 polyfit函数是matlab中用于进行曲线拟合的一个函数。其数学基础是最小二乘法曲线拟合原理。曲线拟合&#xff1a;已知离散点上的数据集&#xff0c;即已知在点集上的函数值&#xff0c;构造一个解析函数&#xff08;其图形为一曲线&#xff09;使在原离散点上尽可能接…

深度学习 —— 个人学习笔记10(池化层、LeNet)

声明 本文章为个人学习使用&#xff0c;版面观感若有不适请谅解&#xff0c;文中知识仅代表个人观点&#xff0c;若出现错误&#xff0c;欢迎各位批评指正。 二十一、池化层 1、 最大池化层和平均池化层 与互相关运算符一样&#xff0c;汇聚窗口从输入张量的左上角开始&#…

打靶记录6——靶机EvilBox---One

靶机下载地址 https://www.vulnhub.com/entry/evilbox-one,736/学习记录 在进行目录爆破和文件爆破的过程当中&#xff0c;如果有发现新的路径&#xff0c;一定要对新的路径再次进行更深层次的爆破虚拟机出现问题就删除掉&#xff0c;重新导入虚拟机 目标: 获取两个flag&am…

如何准备专利申请书的摘要部分?

如何准备专利申请书的摘要部分&#xff1f;

基于概率神经网络的异方差不确定性估计

目录 摘要1 介绍2 预热3 分析3.1对称性和特征非线性3.2逆方差加权有效欠样本 4 方法5 实验5.1合成数据集5.2真实数据集6 结论 摘要 捕获任意不确定性是许多机器学习系统的关键部分。在深度学习中&#xff0c;达到这一目的的一种常用方法是训练神经网络&#xff0c;通过最大化观…

力扣SQL50 组合两个表 入门基础连表查询

Problem: 175. 组合两个表 select FirstName, LastName, City, State from Person left join Address on Person.PersonId Address.PersonId ;

AI说 | 如何入门AI行业,成为人工智能产品经理?(上)

这周在上海出差&#xff0c;划个水&#xff0c;发一篇之前写的文章&#xff0c;谈谈如何入门AI行业 另外&#xff0c;有朋友说我的文章读起来很累&#xff0c;自我反思&#xff0c;确实写的太长&#xff0c;后面我会在保证有趣或有干货的情况下&#xff0c;将文章内容尽量减短…

《深入浅出WPF》学习笔记四.提高效率,code snippets的使用

《深入浅出WPF》学习笔记四.提高效率,code snippets的使用 背景 再跟着视频教程学习Wpf的过程中,发现这个小技巧。很惭愧好几年开发经验&#xff0c;没用过这个东西。 这个信息差还是很让人头疼的&#xff0c;特别在此分享。 code snippets是什么 Code Snippets是插入代码…

Elasticsearch 未授权访问漏洞

Elasticsearch 未授权访问漏洞 ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口。Elasticsearch是用Java开发的&#xff0c;并作为Apache许可条款下的开放源码发布&#xff0c;是当前流行的企业级搜索…

zabbix监控中文乱码解决方案

zabbix切换中文后&#xff0c;会出现乱码情况&#xff0c;如下图&#xff1a; 解决方案如下&#xff1a; 1、找到字体 WinR打开运行&#xff0c;输入fonts&#xff0c;回车进入Windows字体目录&#xff0c;找到微软雅黑-常规字体&#xff0c;复制出来将文件名修改为msyh.ttf…

Substance Painter工具栏及快捷键

3 菜单栏_哔哩哔哩_bilibili ctrl右键左右滑动调整笔刷大小/左键流量 上下滑动有其他作用 线框显示工具 制作随机效果 Fill要配合遮罩使用 白色遮罩显示底色&#xff0c;黑色遮罩不显示底色 核心工具 图层关系 必须添加在蒙版的效果下 选择中蒙版 滤镜仅能添加在图层下 id图…

k8s中yaml文件的编写

目录 1.编写pod.yaml 2.编写deploment.yaml 3.编写service.yaml关联创建的pod 4.总结获取K8S资源配置清单文件模板方法 方法1&#xff1a;根据现有资源导出yaml文件修改配置&#xff0c;重新创建 方法2&#xff1a;根据现有资源&#xff0c;进入其配置中&#xff0c;复制…

Go语言实现多协程文件下载器

文章目录 前言流程图主函数下载文件初始化分片下载worker分发下载任务获取下载文件的大小下载文件分片错误重试项目演示最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;最近在开发文件传输相关的项目&#xff0c;然后顺手写了一个多协程文件下载器&#xff0c;代码非常精…

Cxx primer-chap12-Dynamic Memory

目前我们使用的对象都是语言本身代替我们管理其生命周期和作用域&#xff0c;例如global object、局部的自动变量和局部的static变量&#xff0c;除此之外&#xff0c;语言也允许我们创建动态分配的对象&#xff08;即运行时创建的对象&#xff09;&#xff1a;不同类型的对象&…

SpringCloud概述和基本工程搭建

目录 1.认识微服务 1.1单体架构 1.2集群和分布式架构 1.3微服务架构 1.4微服务的优势 2.微服务解决方案-Spring Cloud 2.1什么是Spring Cloud 2.2Spring Cloud Alibaba 2.3SpringCloud实现对比 3.服务拆分原则 3.1单一职责原则 3.2服务自治原则 3.3单向依赖原则 …

前端:Vue

一、引入 Vue是一套前端框架&#xff0c;免除javaScript中的DOM操作&#xff0c;简化书写。基于MVVM思想&#xff0c;实现数据的双向绑定&#xff0c;将编程的关注点放在数据上。 框架&#xff1a;是一个半成品软件&#xff0c;是一套可重用的、通用的、软件基础代码模型。基于…

C#初级——字典Dictionary

字典 字典是C#中的一种集合&#xff0c;它存储键值对&#xff0c;并且每个键与一个值相关联。 创建字典 Dictionary<键的类型, 值的类型> 字典名字 new Dictionary<键的类型, 值的类型>(); Dictionary<int, string> dicStudent new Dictionary<int, str…