【C++】—— c++11新的类功能

目录

(一)默认成员函数

1、 移动构造函数

 2、代码辅助理解

3、移动赋值运算符重载

(二)default关键字

(三)delete关键字

(四)委托构造函数

1、优势 

2、缺点

总结 


(一)默认成员函数

原来C++类中,有6个默认成员函数:

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

最后重要的是前4个,后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。
 

 💨 C++11 新增了两个:移动构造函数和移动赋值运算符重载

1、 移动构造函数

移动构造函数是C++中的特殊成员函数之一,用于以移动语义的方式构造新对象。它是在C++11中引入的,旨在提高对象的性能和效率。

移动构造函数通常用于在不进行资源拷贝的情况下将临时对象或者右值引用的对象的内容转移到新创建的对象中。通过移动构造函数,可以避免不必要的拷贝操作,提高代码的性能。


 2、代码辅助理解

接下来我们通过代码来尝试着学习相关的知识:

  • 首先,我先给出手动实现的string类,代码如下:
namespace zp
{class string{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}string(const char* str = ""):_size(strlen(str)), _capacity(_size){cout << "string(char* str)" << endl;_str = new char[_capacity + 1];strcpy(_str, str);}// s1.swap(s2)void swap(string& s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}// 拷贝构造string(const string& s):_str(nullptr){cout << "string(const string& s) -- 深拷贝" << endl;string tmp(s._str);swap(tmp);}// 移动构造string(string&& s):_str(nullptr){cout << "string(string&& s) -- 移动拷贝" << endl;swap(s);}// 赋值重载string& operator=(const string& s){cout << "string& operator=(string s) -- 深拷贝" << endl;string tmp(s);swap(tmp);return *this;}// s1 = 将亡值string& operator=(string&& s){cout << "string& operator=(string&& s) -- 移动赋值" << endl;swap(s);return *this;}~string(){//cout << "~string()" << endl;delete[] _str;_str = nullptr;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void push_back(char ch){if (_size >= _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}//string operator+=(char ch)string& operator+=(char ch){push_back(ch);return *this;}string operator+(char ch){string tmp(*this);tmp += ch;return tmp;}const char* c_str() const{return _str;}private:char* _str;size_t _size;size_t _capacity; // 不包含最后做标识的\0};//const zp::string& to_string(int value)zp::string to_string(int value){bool flag = true;if (value < 0){flag = false;value = 0 - value;}zp::string str;while (value > 0){int x = value % 10;value /= 10;str += ('0' + x);}if (flag == false){str += '-';}std::reverse(str.begin(), str.end());return str;}
}

接下来,有这样的一段代码,我们对它进行运行分析:

 接下来,我们给出相关示例,把代码运行起来看最终我们的样例是调用的什么:

 【解释说明】

  •  如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。

此时,我们把其中的析构函数进行相关的实现,在看最终的打印结果是什么:

  【解释说明】

  1. 使用 move 操作可以显式地将 s1转换为右值引用,并尝试将 s1 通过移动语义移动到 s3 中;
  2. 此时,我们可以发现,当我们手动的实现了一个析构函数之后,编译器就会对识别进行深拷贝操作;

【小结】

针对移动构造函数有一些需要注意的点如下:

  1. 如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造;
  2. 默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造
     

这里解释一下为什么生成默认移动构造条件这么苛刻的问题:

  1. 编译器之所以把这个条件设计这么苛刻,因为它认为说你是你自己要实现的拷构构造和拷贝赋值还是析构,按理来说你这个类呢,就是一个深拷贝的类,那你是一个深拷贝的类呢,那这个时候移动赋值,它不知道咋处理比较好;
  2. 就比如说这有个指针,那这个指针我要把你的资源转移,就是你可以认为它自己把控不住,它不知道该咋编译做资源移动。其次这个指针指向的资源就一定要移动吗?我们认为这是不一定的,要看我们实际当中的需求是什么,它自己把控不住,这个时候他就不再给你自动生成了;
  3. 那什么时候他觉得他可以把控住呢?就是像刚才这样的,你没有实现析构,你不是深拷贝的类,它就可以把控住。

3、移动赋值运算符重载

移动赋值运算符重载的原理跟上述移动构造函数一样的。大家只需记住一个,另一个类似的就可以记住!!!


(二)default关键字

在C++11之前,如果在类的定义中没有显式声明默认构造函数、复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符时,编译器会自动生成这些函数的默认版本。然而,在C++11及以后的标准中,如果我们显式地定义了一个带有参数的构造函数、复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符,编译器将不再自动生成默认版本。

为了强制生成默认版本的函数,我们可以使用关键字 default。在类的定义内部,用 = default形式指定函数。这将告诉编译器生成该函数的默认版本。

  • 代码展示:


(三)delete关键字

当我们在类中手动定义了自定义构造函数、复制构造函数、移动构造函数、赋值运算符或移动赋值运算符时,编译器就不会再自动生成默认版本的这些函数。然而,在某些情况下,我们可能希望保留编译器自动生成的默认版本。

使用 delete 关键字可以告诉编译器生成该函数的默认版本,即恢复被手动定义函数覆盖的默认行为。

  • 代码展示:


(四)委托构造函数

委托构造函数是C++11引入的特性之一,它允许一个构造函数调用同一类的其他构造函数来完成对象的初始化。通过委托构造函数,可以减少代码的冗余、提高可维护性,并且确保初始化逻辑的一致性。

以下是委托构造函数的简要说明和示例:

1、优势 

  • 委托构造函数的语法:

委托构造函数使用特殊的语法来调用同一类的其他构造函数。它在成员初始化列表中使用冒号(:)后面的成员初始化器列表来调用其他构造函数。

class Test 
{
public:Test(int x, int y) :  // 构造函数1,委托给构造函数2Test(x, y, 0) {   // 委托构造函数}Test(int x, int y, int z) :// 构造函数2,实际完成对象初始化的构造函数{// 具体的初始化逻辑}
};

【解释说明】 

  • 这样,当我们使用委托构造函数创建对象时,只需调用适合的构造函数,并由该构造函数负责完成所有初始化工作;
  • 这样做可以避免在多个构造函数中复制相同的初始化代码,提高了代码的可维护性。

  • 委托构造函数的特点:

    • 委托构造函数的声明和定义位于同一类中,并且在其他构造函数的前面。
    • 委托构造函数不能有初始值列表,因为它的作用是将初始化任务委托给其他构造函数。
    • 委托构造函数可以有自己的成员初始化列表,用于初始化委托所使用的其他构造函数中未初始化的成员变量。

2、缺点

委托构造函数在使用时存在一种潜在的问题,称为"委托环"(delegation cycle)。委托环是指构造函数之间形成了循环的委托调用关系,导致无限递归或编译错误的情况。

下面是一个示例,展示了如何在不小心的情况下创建委托环的代码:

class Test 
{
public:Test(int x) {// 执行一些初始化操作}Test() : Test(0) { // 委托构造函数,调用了另一个构造函数// 其他逻辑}
};

【解释说明】

  1. 在上面的代码中,Test 类有一个带有参数的构造函数和一个不带参数的构造函数,而不带参数的构造函数使用委托构造函数调用了带有参数的构造函数。这看起来没有问题,但实际上却形成了委托环;
  2. 当创建一个不带参数的 Test 对象时,会调用不带参数的构造函数。然后,由于委托构造函数的存在,它又会调用带有参数的构造函数。然后,带有参数的构造函数又会调用不带参数的构造函数。这样就形成了循环,导致无限递归。

委托构造函数自身不应该包含其他的初始化语句,否则会导致重复初始化的问题

class Test 
{
public:Test(int value) : Test(value, 0.0) {// 错误!委托构造函数体中存在其他初始化语句tmp_ = 42;}Test(int value, double rate): value_(value), rate_(rate){// 构造函数体...}private:int value_;double rate_;int tmp_;
};

【解释说明】

  1. 在上述示例中,委托构造函数的体内存在对 tmp_ 的初始化,这将导致该变量在构造过程中被初始化两次,可能会产生不可预料的结果。
  2. 正确的做法是,在委托构造函数内部只进行调用,不要插入其他的初始化语句。

总结 

以上便是关于本期 c++11新的类功能全部知识。感谢大家的观看与支持!!!

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

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

相关文章

ubuntu学习(四)----文件写入操作编程

1、write函数的详解 ssize_t write(int fd,const void*buf,size_t count); 参数说明&#xff1a; fd:是文件描述符&#xff08;write所对应的是写&#xff0c;即就是1&#xff09; buf:通常是一个字符串&#xff0c;需要写入的字符串 count&#xff1a;是每次写入的字节数…

vue中实现echarts三维散点图

需要安装 echarts 同时引入 echarts-gl 我安装的版本&#xff1a; "echarts": "^5.3.2", "echarts-gl": "^2.0.9", import Vue from "vue"; import * as echarts from "echarts"; Vue.prototype.$echarts echa…

温故知新之:代理模式,静态代理和动态代理(JDK动态代理)

0、前言 代理模式可以在不修改被代理对象的基础上&#xff0c;通过扩展代理类&#xff0c;进行一些功能的附加与增强。 1、静态代理 静态代理是一种代理模式的实现方式&#xff0c;它在编译期间就已经确定了代理对象&#xff0c;需要为每一个被代理对象创建一个代理类。静态代…

36、springboot --- 对 tomcat服务器 和 undertow服务器 配置访客日志

springboot 配置访客日志 ★ 配置访客日志&#xff1a; 访客日志&#xff1a; Web服务器可以将所有访问用户的记录都以日志的形式记录下来&#xff0c;主要就是记录来自哪个IP的用户、在哪个时间点、访问了哪个资源。 Web服务器可将所有访问记录以日志形式记录下来&#xff…

VMware 修改ip地址 虚拟机静态ip设置 centos动态ip修改为静态ip地址 centos静态ip地址 vmware修改ip地址

虚拟机的centos服务器经常变换ip&#xff0c;测试起来有些麻烦&#xff0c;故将动态ip修改为静态ip 1. 查看vmware 虚拟机网络配置&#xff1a; 点击编辑&#xff0c;打开虚拟网络配置 2. 选中nat模式&#xff0c;点击nat设置&#xff0c;最终获取网关ip: 192.168.164.2 3. 进…

CleanMyMac2024永久版Mac清理工具

Mac电脑作为相对封闭的一个系统&#xff0c;它会中毒吗&#xff1f;如果有一天Mac电脑产生了疑似中毒或者遭到恶意不知名攻击的现象&#xff0c;那又应该如何从容应对呢&#xff1f;这些问题都是小编使用Mac系统一段时间后产生的疑惑&#xff0c;通过一番搜索研究&#xff0c;小…

CK-GW06-E03与汇川PLC的EtherNet/IP通信

准备阶段&#xff1a; CK-GWO6-E03网关POE交换机网线汇川PLC编程软件汇川AC801-0221-U0R0型号PLC 1.打开汇川PLC编程软件lnoProShop(V1.6.2)SP2 新建工程&#xff0c;选择对应的PLC型号&#xff0c;编程语言选择为“结构化文本&#xff08;ST&#xff09;语言”&#xff0c;然…

线性代数(五) 线性空间

前言 《线性代数(三) 线性方程组&向量空间》我通过解线性方程组的方式去理解线性空间。此章从另一个角度去理解 空间是什么 大家较熟悉的&#xff1a;平面直角坐标系是最常见的二维空间 空间由无穷多个坐标点组成 每个坐标点就是一个向量 反过来&#xff0c;也可说&…

kafka--技术文档--架构体系

架构体系 Kafka的架构体系包括以下几个部分&#xff1a; Producer. 消息生产者&#xff0c;就是向Kafka broker发送消息的客户端。Broker. 一台Kafka服务器就是一个Broker。一个集群由多个Broker组成。一个Broker可以容纳多个Topic。Topic. 可以理解为一个队列&#xff0c;一…

Oracle 如何给大表添加带有默认值的字段

一、讲故事 你是否遇到过开发人员添加字段&#xff0c;导致数据库锁表问题&#xff1f; 但是令开发疑惑的事&#xff0c;他们添加字段&#xff0c;有的时候很快&#xff0c;有的时候很慢&#xff1f; 为什么呢&#xff1f; 询问得知&#xff0c;**加的慢时候是带上了default默…

【洛谷】P2440 木材加工

原题链接&#xff1a;https://www.luogu.com.cn/problem/P2440 1. 题目描述 2. 思路分析 整体思路&#xff1a;二分答案 设置一个变量longest来记录最长木头的长度&#xff0c;sum记录切成的小段数量之和。 令左边界l0&#xff0c;右边界llongest。 写一个bool类型的check…

【云原生】Docker的数据管理(数据卷、容器互联)

目录 一、数据卷&#xff08;容器与宿主机之间数据共享&#xff09; 二、数据卷容器&#xff08;容器与容器之间数据共享&#xff09; 三、 容器互联&#xff08;使用centos镜像&#xff09; 总结 用户在使用Docker的过程中&#xff0c;往往需要能查看容器内应用产生的数据…

联合注入步骤

使用场景&#xff1a; 有回显&#xff0c;可以看到某些字段的回显信息 像下面的有具体的回显信息 一、判断注入位点 在原始的id&#xff08;参数&#xff09;的输入后面添加额外的条件 如果and 11 有结果&#xff0c;and10没有结果输出&#xff0c; 就说明我们添加的额外条件…

2023最新AI创作系统ChatGPT网站源码V2.6.0+详细图文搭建安装教程/GPT联网/支持ai绘画+Dall-E2绘画/支持MJ以图生图

一、AI系统 如何搭建部署AI创作ChatGPT系统呢&#xff1f;小编这里写一个详细图文教程吧&#xff01; SparkAi使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到AIGC系统&#xff01; 程序核心功能 程序已支持ChatGPT3.5/4.0提问、AI绘画、Midjourney绘画&#xff08;…

solidity0.8.0的应用案例12:通用可升级合约UUPS

代理合约中选择器冲突(Selector Clash)的另一个解决办法:通用可升级代理(UUPS,universal upgradeable proxy standard)。代码由OpenZeppelin的UUPSUpgradeable简化而成,不应用于生产。 UUPS 作为透明代理的替代方案,UUPS也能解决"选择器冲突"(Selector Cl…

论文阅读_模型结构_LoRA

name_en: LoRA: Low-Rank Adaptation of Large Language Models name_ch: LORA&#xff1a;大语言模型的低阶自适应 paper_addr: http://arxiv.org/abs/2106.09685 date_read: 2023-08-17 date_publish: 2021-10-16 tags: [‘深度学习’,‘大模型’] author: Edward J. Hu cita…

2023谷歌开发者大会直播大纲「初稿」

听人劝、吃饱饭,奉劝各位小伙伴,不要订阅该文所属专栏。 作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 跨域学习者,从事过全栈研发、产品经理等工作,现任研发部门 CTO 。荣誉:2022年度博客之星Top4、博客专家认证、全栈领域优质创作者、新星计划导师,“星荐官共赢计…

【C++】开源:Box2D动力学库配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Box2D动力学库配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c…

EasyExcel自定义字段对象转换器支持转换实体和集合实体

文章目录 1. 实现ObjectConverter2. 使用3. 测试3.2 导出excel3.1 导入excel 1. 实现ObjectConverter package com.tophant.cloud.common.excel.converters;import cn.hutool.json.JSONUtil; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.…

远程连接虚拟机中ubuntu报错:Network error:Connection refused

ping检测一下虚拟机 可以ping通&#xff0c;说明主机是没问题 #检查ssh是否安装&#xff1a; ps -e |grep ssh发现ssh没有安装 #安装openssh-server sudo apt-get install openssh-server#启动ssh service ssh startps -e |grep ssh检查一下防火墙 #防火墙状态查看 sudo ufw…