[C++] C++11详解 (三)类的成员函数、完美转发

news2024/9/23 21:28:51

标题:[C++] C++11详解 (三)完美转发与lambda表达式

@水墨不写bug



目录

一、C++11新增两个类的默认成员函数

1.强制生成默认函数的关键字default:

2.禁止生成默认函数的关键字delete:

二、完美转发


正文开始:

一、C++11新增两个类的默认成员函数

        在之前的讲解中:《【Cpp】类和对象#拷贝构造 赋值重载_cpp类重载-CSDN博客》、

《【Cpp】类和对象#构造函数 析构函数_cpp类中析构函数-CSDN博客》,我们知道在C++11之前,类的成员函数有默认的6个,分别是:

        1.构造函数

        2.析构函数

        3.拷贝构造

        4.赋值拷贝

        5.取地址重载

        6.const取地址重载

        在C++11又新增了两个默认成员函数:移动构造和移动赋值 。

但是想要让编译器自己生成这两个默认成员函数,是有一定的规则的:

        如果没有手动实现移动构造,并且没有实现析构函数、拷贝构造、赋值拷贝这三个函数中的任意一个(这三个只要存在一个,就不满足条件),编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对内置类型逐字节拷贝,自定义类型则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,如果没有实现,就调用拷贝构造。

        完全类似的,如果没有手动实现移动赋值,并且没有实现析构函数、拷贝构造、赋值拷贝这三个函数中的任意一个(这三个只要存在一个,就不满足条件),编译器会自动生成一个默认移动赋值。默认生成的移动赋值函数,对内置类型逐字节拷贝,自定义类型则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,如果没有实现,就调用拷贝赋值。

        如果自己手动提供了移动构造或者移动赋值,编译器不会再自动提供。

        其实,仔细一想,上面的生成移动赋值的条件看似苛刻,但是确实是有逻辑支撑的:

        如果我们手动实现了一个类的析构函数,这表示这个类内部有资源需要清理,同时意味着在拷贝的时候需要深拷贝,也就必须手动实现拷贝赋值拷贝构造了。析构函数、拷贝赋值、拷贝构造是三位一体的。手动实现了这三个函数之后,移动构造与移动赋值自然也需要手动实现了。

        所以,如果不需要手动实现,则这个类就只有构造函数。其他的默认成员函数都是默认生成的。比如:

class Person
{
public:
    Person(const char* name = "", int age = 0)
        :_name(name)
        , _age(age)
    {}
private:
    bit::string _name;
    int _age;
};

        这个类虽然只手动实现了构造函数,符合生成移动构造和移动赋值的条件,编译器会默认生成拷贝构造,拷贝赋值,析构函数,移动构造,移动赋值;并且这些函数的默认生成都是正确的。

1.强制生成默认函数的关键字default:


        C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。(比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用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)
    {}
    
    //由于拷贝构造手动实现,无法生成默认移动构造
    //可通过关键字:default 强制编译器生成一份移动构造
    Person(Person&& p) = default;//这里仅仅是为了举例演示,实际项目中不会这样使用

private:
    bit::string _name;
    int _age;
};

 

2.禁止生成默认函数的关键字delete:


        如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补不定义,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数,阻止编译器默认生成。
 

二、完美转发

模板中的&& 万能引用

        什么是万能引用?当我们在实现函数前面加上模板参数,并把参数类型设为模板参数&&,这就表示t可以同时接受左值引用和右值引用,这就是万能引用或者引用折叠。

template<typename T>
void PerfectForward(T&& t)
{
    //t可以同时接受左值引用和右值引用
}

         注意:

        模板中的&&并不是表示右值引用,而是表示万能引用,其既能接受左值,又能接受右值。传入什么,就是t的类型就推导为什么的引用。

        我们知道,如果我们对一个右值引用,int&&pr = 10;虽然10是右值,但是10的引用pr缺退化为了左值。为了避免引用在传参的时候右值退化为左值,就需要完美转发:

        std::forward 完美转发在传参的过程中保留对象原生类型属性

        如果没有完美转发,t的类型可以是左值引用或者右值引用。由于右值引用本身的属性是左值,所以如果不用完美转发,则调用func(t),都只会匹配到左值版本。

void Fun(int &x){ cout << "左值引用" << endl; }
void Fun(const int &x){ cout << "const 左值引用" << endl; }
void Fun(int &&x){ cout << "右值引用" << endl; }
void Fun(const int &&x){ cout << "const 右值引用" << endl; }

// std::forward<T>(t)在传参的过程中保持了t的原生类型属性。
template<typename T>
void PerfectForward(T&& t)
{
    Fun(t);
}

如果在调用Fun(t)时,对t完美转发:(保持属性)

void Fun(int &x){ cout << "左值引用" << endl; }
void Fun(const int &x){ cout << "const 左值引用" << endl; }
void Fun(int &&x){ cout << "右值引用" << endl; }
void Fun(const int &&x){ cout << "const 右值引用" << endl; }

// std::forward<T>(t)在传参的过程中保持了t的原生类型属性。
template<typename T>
void PerfectForward(T&& t)
{
    Fun(std::forward<T>(t));
}

         这时,在调用Fun()时,就会正确匹配对应的函数了。


完~

未经作者同意禁止转载

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

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

相关文章

【YOLO5 项目实战】(8)PyQt5 图形界面—PCB缺陷检测系统

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans 【YOLO5 项目实战】&#xff08;8&#xff09;PyQt5 图形界面—PCB缺陷检测系统 1. PyQt5 图形界面开发工具1.1 PyQt5 的安装1.2 在 PyCharm 集成 QtDesigner 和 PyUIC1.3 使用 QtDesigner 开发 PyQt…

EPLAN在安装完成之后,输入文字时出现卡顿和死机的解决办法

EPLAN在安装完成之后,输入文字时出现卡顿和死机的解决办法 EPLAN在安装完成之后,插入文字时有时会卡顿,甚至出现软件卡死,无任何反映的情况,具体的解决办法可参考以下内容: 找到电脑右下角的输入法,右击进入设置, 如下图所示,点击进入常规设置, 如下图所示,向下找…

终于!我找到了开发的得力助手!阿里云天池云原生编程挑战赛参赛攻略

作者&#xff1a;ysevenk_7 参赛准备 我是机缘巧合在 6 月底了解到了天池云原生编程挑战赛&#xff0c;于是乎搜了一下&#xff0c;之前本人对于比赛并没有太多经验&#xff0c;看了大赛介绍之后莫名兴奋&#xff0c;果断拉了队友报名&#xff0c;完成认证、起队名、下载插件…

【STM32】RS485

RS485是常见的串口接口。 大部分图片来源&#xff1a;正点原子HAL库课程 专栏目录&#xff1a;记录自己的嵌入式学习之路-CSDN博客 目录 1 串口、UART、TTL、RS232、RS422、RS485的关系 1.1 串口 1.2 UART、TTL、RS232、RS422、RS485 1.3 常见串口标准的比较 …

Apache Arrow 的列式内存格式

Apache Arrow 的列式存储格式是一种内存数据组织标准&#xff0c;它通过物理布局、Array&#xff08;数组&#xff09;、Schema&#xff08;模式&#xff09;和 RecordBatch&#xff08;记录批次&#xff09;等&#xff0c;优化了大数据的存储与处理。这种格式以列而非行来存储…

更改网络ip地址时出现错误怎么办

在日常的网络使用中&#xff0c;‌有时我们需要更改IP地址以满足特定的网络需求&#xff0c;‌然而&#xff0c;‌在更改IP地址的过程中&#xff0c;‌可能会遇到各种错误&#xff0c;‌导致无法成功更改或网络连接出现问题。‌‌而更改网络IP地址时出现错误是由于多种原因导致…

二、基于Vue3的开发-环境搭建【Visual Studio Code】扩展组件

Visual Studio Code中的扩展组件 1、安装的扩展工具2、说明2.1 、代码规范性检查EsLint2.2 、代码语法高亮提示工具Vue - Official2.3 、阿里的AI代码开发提示工具 TONGYI Lingma 1、安装的扩展工具 2、说明 2.1 、代码规范性检查EsLint Visual Studio Code 中【设置】-setti…

基于元神操作系统编程写硬盘扇区

1. 背景 本文介绍了“调用元神操作系统API向硬盘扇区写数据”的程序实现及测试结果。 2. 方法 &#xff08;1&#xff09;调用元神操作系统API读硬盘扇区 本部分内容已在前面的文章中进行介绍&#xff0c;详细内容请参考“编写程序调用元神操作系统的API”。 &#xff08;…

二叉树 - 二叉树的所有路径

257. 二叉树的所有路径 方法一&#xff1a;递归法&#xff1a; /*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val (valundefined ? 0 : val)* this.left (leftundefined ? null : left)* this.right (rightundefi…

水下目标检测(低光照目标检测)方法-发表在Patter Recognition,代码已开源

这里写自定义目录标题 前言动机贡献Overview一些实验结果数据集主要实验结果实验结果展示 总结 前言 Hi,各位读者&#xff0c;好久不见&#xff01;现在我已经从北大博士毕业&#xff0c;成为一名小青椒啦&#xff01;工作还是需要宣传的。今天想分享我在水下目标检测的工作&a…

低代码技术:快速构建应用的未来

在当今快速发展的数字化时代&#xff0c;企业和个人对软件应用的需求不断增长。然而&#xff0c;传统的软件开发过程通常复杂且耗时。这使得低代码技术&#xff08;Low-Code Technology&#xff09;成为了越来越多人关注的焦点。本文将探讨低代码技术的基本概念、优势以及如何在…

贾湖刻符——汉字起源的重要线索

关注我们 - 数字罗塞塔计划 - 汉字是世界上唯一沿用至今的古老文字系统&#xff0c;其演变历程承载着中华文明的发展和赓续。那么汉字究竟源自何时&#xff1f;是古代神话传说的“昔者仓颉作书&#xff0c;而天雨粟&#xff0c;鬼夜哭”&#xff1b;还是由华夏先民创制的刻划符…

请你学习:前端布局3 - flex

Flexbox布局也叫Flex布局&#xff0c;弹性盒子布局。它的目标是提供一个更有效地布局、对齐方式&#xff0c;并且能够使父元素在子元素的大小未知或动态变化情况下仍然能够分配好子元素之间的间隙。主要思想是使父元素能够调整子元素的宽度、高度、排列方式&#xff0c;从而更好…

AI变现之Midjourney头像定制

前言 Midjourney | 头像定制 1.项目介绍 个性化头像在如今的社交媒体时代变得越来越重要。传统头像照片有时显得普通&#xff0c;而AI绘画头像则能为自己的社交账号增加独特性和吸引力。 通过AI绘画工具制作头像&#xff0c;可以获得一个充满创意和个性的头像&#xff0c;让…

湖南的智榜样网络安全公司开的培训学校参加学习成为网络安全工程师

学习网络安全可以通过以下步骤进行&#xff1a; 获取基础知识&#xff1a;开始学习网络安全之前&#xff0c;建议先获取一些计算机基础知识&#xff0c;包括计算机网络、操作系统、编程语言等方面的知识。这些基础知识将为你理解和学习网络安全提供必要的背景。 学习网络安全基…

数据中台即将消亡,数智基建取而代之?

数据中台即将消亡&#xff0c;数智基建取而代之&#xff1f; 前言数智基建 前言 在当今数字化浪潮汹涌澎湃的时代&#xff0c;企业的发展如同在浩瀚海洋中航行的巨轮&#xff0c;而数据则是推动这艘巨轮前行的强大动力。然而&#xff0c;如何有效地管理和利用数据&#xff0c;…

2024年第十四届APMCM亚太地区大学生数学建模竞赛思路

2024年第十四届亚太地区大学生数学建模竞赛(以下简称“竞赛”)是由中国国际科技促进会物联网工作委员会和北京图象图形学学会联合主办的亚太地区大学生学科类竞赛&#xff0c;竞赛由亚太地区大学生数学建模竞赛组委会负责组织&#xff0c;欢迎各高等院校按照竞赛章程及有关规定…

MySQL:SQL调优的简单实践

记一次简单的SQL优化实践。 一、初始化数据 1.1 初始化数据-课程表 #课程表 create table Course(c_id int primary key,name varchar(10) );#存储过程&#xff1a;增加课程表100条数据DROP PROCEDURE IF EXISTS insert_Course;DELIMITER $CREATE PROCEDURE insert_Course()…

[线程]***多线程带来的风险-线程安全问题

文章目录 一. 什么是线程安全二. 线程不安全一个经典的例子三. 对上述例子的理解四. 出现线程不安全的原因1. 线程在操作系统中是随机调度, 抢占式执行的2. 当前代码中, 多个线程同时修改同一变量3. 线程针对变量的修改操作, 不是"原子"的4. 内存可见性问题, 引起线程…

使用gradle 移除敏感权限

前言 最近要上架Google Play 但是因为有个敏感权限很容易被拒。 想着把权限依赖的库去掉就行了&#xff0c;但是遇到一个恶心的问题。就是这个权限在Android Studio的Merged Manifest 视图中没有&#xff0c;但是在生成的apk中却包含。这样的就不能通过Android Studio来定位权…