【C++】新的类功能和可变参数模板

目录

  • 一、新的类功能
    • 1.1 默认成员函数
      • 1.1.1 移动构造函数
      • 1.1.2 移动赋值运算符重载
    • 1.2 关键字default
    • 1.3 关键字delete
  • 二、可变参数模板
    • 2.1 可变参数的函数模板
    • 2.2 递归方式展开函数
    • 2.3 empalce

一、新的类功能

1.1 默认成员函数

在之前的学习过程中,我们已经知道了6个默认成员函数,分别是:

  1. 构造函数
  2. 析构函数
  3. 拷贝构造
  4. 拷贝赋值重载
  5. 取地址重载
  6. const 取地址重载

默认成员函数的特点:我们不写,编译器会生成出来一个默认的

C++11新增了两个:

  1. 移动构造函数
  2. 移动赋值运算符重载

1.1.1 移动构造函数

默认移动构造函数出现的条件:

  • 自己没有实现移动构造函数
  • 并且自己没有实现析构、拷贝构造和拷贝赋值重载函数中的任意一个
  • 默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造
class Person
{
public:Person(const char* name = "", int age = 0):_name(name), _age(age){}/*~Person(){}*/
private:yss::string _name;int _age;
};
int main()
{Person s1;Person s2 = std::move(s1);//右值return 0;
}

在这里插入图片描述

取消注释后运行:

	~Person(){}

在这里插入图片描述

1.1.2 移动赋值运算符重载

默认移动赋值运算符重载出现的条件:

  • 自己没有实现移动赋值运算符重载
  • 并且自己没有实现析构、拷贝构造和拷贝赋值重载函数中的任意一个
  • 默认生成的移动赋值运算符重载函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值重载,如果实现了就调用移动赋值重载函数,没有实现就调用拷贝赋值
class Person
{
public:Person(const char* name = "", int age = 0):_name(name), _age(age){}//~Person()//{}private:yss::string _name;int _age;
};
int main()
{Person s1;Person s2;s2 = std::move(s1);return 0;
}

在这里插入图片描述

取消注释后运行:

	~Person(){}

在这里插入图片描述

1.2 关键字default

作用:强制生成默认函数。 如果我们有写构造函数,就不会生成移动构造,可以使用default关键字显示指定移动构造生成。

class Person
{
public:Person(const char* name = "", int age = 0):_name(name), _age(age){}//拷贝构造Person(const Person& p):_name(p._name), _age(p._age){}//移动构造Person(Person&& p) = default;
private:yss::string _name;int _age;
};

在这里插入图片描述

1.3 关键字delete

作用:禁止生成默认函数。 只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

在这里插入图片描述

二、可变参数模板

2.1 可变参数的函数模板

以前学习的是类模板和函数模板,这两个的特点是只能含固定数量的模版参数。可变参数模板在此基础上有了很大的提升,可以接收0到N个模板参数

下面就是一个基本可变参数的函数模板:

template <class ...Args>
void ShowList(Args... args)
{}
  • Args是一个模板参数包,args是一个函数形参参数包
  • 声明一个参数包Args…args,这个参数包中可以包含0到任意个模板参数

2.2 递归方式展开函数

先看看显示函数参数包中的参数个数:

template <class ...Args>
void ShowList(Args... args)
{cout << sizeof...(args) << endl;
}int main()
{ShowList();//0ShowList(1);//1ShowList(1, 'A');//2ShowList(1, 'A', std::string("sort"));//3return 0;
}

如果想打印函数参数包中的每个参数呢,使用for循环?
在这里插入图片描述
很明显是不行的,因为模板是编译时解析,for循环是运行时解析参数。

方法:编译时递归解析

//递归终止条件
void _ShowList()
{cout << endl;
}
//子函数中递归
template <class T, class ...Args>
void _ShowList(const T& val, Args... args)
{cout << val << " ";_ShowList(args...);
}
//传入函数参数包
template <class ...Args>
void ShowList(Args... args)
{_ShowList(args...);
}int main()
{ShowList(1);ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

在这里插入图片描述

分析:以参数为3个为例
在这里插入图片描述

2.3 empalce

empalce系列中的emplace_back函数与push_back函数的功能是相同的,都是尾插数据。但是C++11新增empalce函数系列支持模板的可变参数和万能引用。下面的是emplace_back函数:
在这里插入图片描述

通过以下代码的对比,区分出empalce函数的优势在哪:
1️⃣深拷贝类对象

int main()
{list<yss::string> lt1;yss::string s1("xxxx");lt1.push_back(s1);//左值lt1.push_back(move(s1));//右值cout << endl;yss::string s2("xxxx");lt1.emplace_back(s2);//左值lt1.emplace_back(move(s2));//右值cout << endl;lt1.push_back("1111");//右值lt1.emplace_back("1111");//右值return 0;
}

在这里插入图片描述
对于深拷贝类对象,如果插入的是类对象时,两个没有区别;如果插入的是对象的参数,那么emplace系列函数会减少一次移动构造

2️⃣浅拷贝类对象

int main()
{list<Date> lt1;Date d1(1, 1, 1);lt1.push_back(d1);//左值lt1.push_back(move(d1));//右值cout << endl;Date d2(2, 2, 2);lt1.emplace_back(d2);//左值lt1.emplace_back(move(d2));//右值cout << endl;lt1.push_back({ 3, 3, 3 });//构造+拷贝构造lt1.emplace_back(3, 3, 3);//构造return 0;
}

注意:emplace_back不支持使用列表初始化

在这里插入图片描述

对于浅拷贝类对象,如果插入的是类对象时,两个没有区别;如果插入的是对象的参数,那么emplace系列函数会减少一次拷贝构造

总结一下(以emplace_back为代表):

  • emplace_back和push_back都可以实现尾插,但是emplace_back的参数不仅可以接收左值和右值,还可以接收参数包
  • 直接插入对象参数的情况下,如果是浅拷贝类对象,减少了一次拷贝构造;如果是深拷贝类对象,减少了一次移动构造
  • 综合前面两点,emplace系列函数在性能上更加优越

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度剖析:计算机集群在大数据体系中的关键角色和技术要点

什么是计算机集群&#xff1f; 计算机集群是一组相互连接的计算机&#xff08;服务器&#xff09;&#xff0c;它们协同工作以完成共同的任务。集群中的每个计算机节点都可以独立运行&#xff0c;但它们通过网络连接在一起&#xff0c;以实现更高的可靠性、性能和可扩展性。 典…

父子页面调用和传值的问题(window.open,iframe)

解决的场景&#xff1a; 当前系统点击列表&#xff0c;打开了新窗口详情页&#xff08;window.open&#xff09;,然后在新窗口详情页进行状态更改操作成功之后&#xff0c;点击原标签页&#xff0c;希望原标签页自动刷新列表更新状态 当然了&#xff0c;父标签页调用子标签页的…

想要成为一名合格的软件测试工程师,你得会些啥?

对于很多新入行或者打算入行&#xff0c;成为软件测试工程师的小伙伴来说&#xff0c;刚开始接触这行&#xff0c;不知道自己究竟该学些什么&#xff0c;或者不知道必须掌握哪些知识&#xff0c;才能成为一名合格的测试工程师。 根据笔者观点&#xff0c;如果你能在学习过程中…

SSM框架学习——MyBatis关联映射

MyBatis关联映射 为什么要关联映射 实际开发中&#xff0c;对数据库操作常常会涉及多张表&#xff0c;所以在OOP中就涉及对象与对象的关联关系。针对多表操作&#xff0c;MyBatis提供关联映射。 关联关系概述 一对一&#xff1a;A类中定义B类的属性b&#xff0c;B类中定义A…

嵌入式硬件中常见的面试问题与实现

1 01 请列举您知道的电阻、电容、电感品牌(最好包括国内、国外品牌) ▶电阻 美国:AVX、VISHAY威世 日本:KOA兴亚、Kyocera京瓷、muRata村田、Panasonic松下、ROHM罗姆、susumu、TDK 台湾:LIZ丽智、PHYCOM飞元、RALEC旺诠、ROYALOHM厚生、SUPEROHM美隆、TA-I大毅、TMT…

【讲解下Gitea】

&#x1f308;个人主页:程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

vulhub打靶记录——driftingbox

文章目录 主机发现端口扫描目录扫描爆破子域名提权总结 主机发现 使用nmap扫描局域网内存活的主机&#xff0c;命令如下&#xff1a; nmap -sP 192.168.56.0/24192.168.56.1&#xff1a;主机IP&#xff1b;192.168.56.100&#xff1a;DHCP服务器IP&#xff1b;192.168.56.101…

c++的学习之路:7、类和对象(3)

一、初始化列表 初始化列表&#xff1a;以一个冒号开始&#xff0c;接着是一个以逗号分隔的数据成员列表&#xff0c;每个"成员变量"后面跟一个放在括号中的初始值或表达式&#xff0c;如下方代码就是初始化列表的方式。从图片可以看出这种方式也可以利用缺省初始化…

《数据结构学习笔记---第九篇》---循环队列的实现

文章目录 1.循环队列的定义 2.循环队列的判空判满 3.创建队列并初始化 4.入队和出队 5. 返回队尾队首元素 6.释放循环队列 1.循环队列的定义 定义&#xff1a;存储队列元素的表从逻辑上被视为一个环。 我们此次实现的循环队列&#xff0c;采用顺序表 typedef struct {int…

Python异常处理:基础到进阶的实用指南

前言 大家好&#xff0c;我是海鸽。异常处理在工程文件中必不可少&#xff0c;今天就带大家彻底搞定python的异常处理。 什么是异常 在Python中&#xff0c;异常是指在程序执行过程中出现的错误或异常情况。 当Python解释器无法执行代码时&#xff0c;它会引发异常&#xff0…

2024年鸿蒙迎来大爆发,有必要转行鸿蒙开发吗?

学鸿蒙开发有前途吗&#xff1f;学鸿蒙为时尚早&#xff1f; 一年前看到这个问题“现在学鸿蒙开发有前途吗&#xff1f;或者说找得到工作吗&#xff1f;” 得到的回答是这样子的&#xff1a; 这话只对了一半。 随着华为925秋季全场景新品发布会上余承东突然宣布&#xff1a;…

scratch买蛋糕 2024年3月中国电子学会图形化编程 少儿编程 scratch编程等级考试一级真题和答案解析

目录 scratch买蛋糕 一、题目要求 1、准备工作 2、功能实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、 推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、py…