【C++】C++11 -- 新功能

文章目录

  • C++11 -- 新功能
    • 默认成员函数
    • 类成员变量初始化
    • 强制生成默认函数关键字default
    • 禁用生成默认函数的关键字delete
    • final and override 关键字

C++11 – 新功能

默认成员函数

在C++11之前一个类有6个默认成员函数,在C++11标准中又新增了两个默认成员函数,分别是移动构造函数和移动赋值函数

默认移动构造和移动赋值生成的条件

  • 移动构造函数的生成条件:没有自己实现移动构造函数,并且没有自己实现析构函数,拷贝构造函数和拷贝赋值函数
  • 移动赋值重载函数的生成条件:没有自己实现移动赋值重载函数,并且没有自己实现析构函数,拷贝构造函数,拷贝赋值函数

也就是说移动构造和移动赋值的生成条件和之前六个默认成员函数不同,并不是不写就会生成默认的。

特别注意,如果我们自己实现了移动构造和移动赋值,就算没有实现拷贝构造和拷贝赋值,先一起也不会生成默认的拷贝构造和拷贝赋值

默认移动构造函数会做什么

  • 默认生成的移动构造函数:对于内置类型的成员可以完成值拷贝(浅拷贝),对于自定义类型的成员,如果该成员实现了移动构造就调用它的移动构造,否则就调用它的拷贝构造
  • 默认生成生成的移动赋值函数:对于内置类型的成员会完成值拷贝(浅拷贝),对于自定义类型成员,如果该成员实现了移动赋值就调用它的移动赋值,否则就调用它的拷贝赋值

验证默认生成的移动构造函数和移动赋值函数所做的工作

要验证默认生成的移动构造和移动赋值所做的工作,这里使用了类一个简化版的string类,其中只编写了几个我们需要的成员函数

//
// Created by 陈李鑫 on 2023/7/16.
//
#ifndef SIMULATION_REALIZATION_STL_CLX_STRING_HPP
#define SIMULATION_REALIZATION_STL_CLX_STRING_HPP#endif //SIMULATION_REALIZATION_STL_CLX_STRING_HPP#include <iostream>
#include <algorithm>
#include <utility>
#include <cassert>class clx_string{
public:typedef char* iterator;iterator begin() { return _str;}iterator end() { return _str + _size; }const char* c_str() const { return const_cast<const char*>(_str); };void swap(clx_string& s);clx_string(const char* str = "");clx_string(const clx_string& s);clx_string(clx_string&& s);~clx_string();clx_string& operator=(const clx_string& s);clx_string& operator=(clx_string&& s);char& operator[](size_t i);void reserve(size_t n);void push_back(char ch);clx_string& operator+=(char ch);static clx_string to_string(int value);
private:char* _str;size_t _size;size_t _capacity;
};void clx_string::swap(clx_string& s) {std::swap(_size, s._size);std::swap(_capacity, s._capacity);std::swap(_str, s._str);
}clx_string::clx_string(const char* str) {std::cout << "clx_string(const char* str) -- 直接构造" << std::endl;_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);
}clx_string::clx_string(clx_string&& s):_size(0), _capacity(0), _str(nullptr)
{std::cout << "clx_string::clx_string(clx_string&& s) -- 移动构造" << std::endl;swap(s);
}// 拷贝构造函数 以前的写法
//clx_string::clx_string(const clx_string& s) {
//    _size = strlen(s.c_str());
//    _capacity = _size;
//    _str = new char[_capacity + 1];
//    strcpy(_str, s.c_str());
//}// 拷贝构造函数 现代写法
clx_string::clx_string(const clx_string& s): _str(nullptr), _size(0), _capacity(0)
{std::cout << "clx_string(const clx_string& s) -- 拷贝构造"  << std::endl;clx_string tmp(s.c_str());swap(tmp);std::cout << std::endl;std::cout << std::endl;
}clx_string::~clx_string() {_size = 0;_capacity = 0;delete[] _str;_str = nullptr;
}
clx_string& clx_string:: operator=(const clx_string& s) {std::cout << "clx_string& clx_string:: operator=(const clx_string& s) -- 赋值函数重载" << std::endl;clx_string tmp(s.c_str());clx_string::swap(tmp);std::cout << std::endl;std::cout << std::endl;return *this;
}clx_string& clx_string::operator=(clx_string&& s) {std::cout << "clx_string& clx_string::operator=(clx_string&& s) -- 移动赋值重载" << std::endl;swap(s);return *this;
}char& clx_string::operator[](size_t i) {assert(0 <= i && i < _size);return _str[i];
}void clx_string::reserve(size_t n) {if (n > _capacity) {char* tmp = new char[n + 1];strncpy(tmp, _str, _size + 1);if (_str) {delete[] _str;}_str = tmp;_capacity = n;}
}
void clx_string::push_back(char ch) {while (_size >= _capacity) {reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_str[_size + 1] = 0;_size++;
}
clx_string& clx_string::operator+=(char ch) {push_back(ch);return *this;
}clx_string clx_string::to_string(int value) {clx_string res;bool flag = false;if (value < 0) {flag = true;value = -1 * value;}while (value > 0) {char ch = static_cast<char>(value % 10);res += ch + '0';value /= 10;}if(flag) res += '-';std::reverse(res.begin(), res.end());return res;
}

然后再编译一个简单的Person类,Person类中的成员name的类型就是我们模拟实现的string类

class Person{
public:explicit Person(const char* name = "", int age = 0):_name(name), _age(age){}Person(const Person& p) :_name(p._name),_age(p._age){}Person& operator=(const Person& p) {if (this != &p) {_name = p._name;_age = p._age;}return *this;}private:clx_string _name;   // 姓名int _age;           // 年龄
};

虽然Person类当中没有实现移动构造和移动赋值,但是拷贝构造,拷贝赋值,析构函数都实现了,因此Person类不会生成默认的移动构造和移动赋值

void clx_person_test1() {Person s1("clx", 21);Person s2 = std::move(s1);
}
// 输出
clx_string(const char* str) -- 直接构造
clx_string(const clx_string& s) -- 拷贝构造
clx_string(const char* str) -- 直接构造

可以看到我们已经使用右值取构造s2但是Person类并没有调用默认生成的移动构造函数,因为_name作为自定义类型并没有调用其的移动构造以及移动赋值。这里调用的是Person的拷贝构造函数,其又调用了clx_string类的拷贝构造函数

生成默认移动构造和移动赋值

为了让Person调用默认生成的移动构造函数和移动赋值函数,我们需要将Person类的拷贝构造,拷贝赋值,析构函数都注释掉,再次运行上述代码

clx_string(const char* str) -- 直接构造
clx_string::clx_string(clx_string&& s) -- 移动构造

可以看到Person类默认生成了移动构造函数,其对自己的自定义成员_name调用了自定义成员的移动构造函数_,我们还可以改一下代码看一下默认移动赋值的效果

void clx_person_test1() {Person s1("clx", 21);Person s2;s2 = s1;
}
clx_string(const char* str) -- 直接构造
clx_string(const char* str) -- 直接构造
clx_string& clx_string:: operator=(const clx_string& s) -- 赋值函数重载
clx_string(const char* str) -- 直接构造

类成员变量初始化

默认生成的构造函数,对于其自定义类型的成员会调用其构造函数进行初始化,但并不会对内置类型的成员进行处理。于是对于C++11支持非静态成员变量在声明时初始化赋值,默认生成的构造函数会使用这些缺省值对成员进行初始化

struct student{string s = "clx";int age = 18;
};void clx_student_test1() {student s;cout << s.s << endl;			// clxcout << s.age << endl;    // 18
}

注意这里只是声明,是给声明的成员变量一个缺省值。不是定义!不是定义!

强制生成默认函数关键字default

C++11可以让我们更好的控制要使用的默认成员函数,假设某些情况我们需要使用某个默认成员函数,但是因为某些原因导致无法生成这个默认成员函数,就可以使用default这个关键字强制其生成

struct student{student(const student& stu): s(stu.s), age(stu.age){}string s = "clx";int age = 18;
};
void clx_student_test2() {student s;
}

这样就不行,编译就会报错。因为Person类中编写了拷贝构造函数,导致无法生成默认的构造函数。默认的构造函数生成条件是没有编写任何类型的构造函数,包括拷贝构造函数

struct student{student() = default;          // 默认生成构造函数student(const student& stu): s(stu.s), age(stu.age){}string s = "clx";int age = 18;
};

这样我们可以使用default关键字强制生成默认构造函数。

default不仅能生成默认构造,所有默认成员函数都可以用default关键字强制生成,包括移动构造和移动赋值.

class Person{
public:explicit Person(const char* name = "", int age = 0):_name(name), _age(age){}Person(const Person& p):_name(p._name),_age(p._age){}Person& operator=(const Person& p) {if (this != &p) {_name = p._name;_age = p._age;}return *this;}~Person(){}Person(Person&&) = default;								// 生成默认的移动赋值和拷贝函数Person& operator=(Person&&) = default;
private:clx_string _name;   // 姓名int _age;           // 年龄
};void clx_person_test1() {Person s1("clx", 21);Person s2 = move(s1);
}
clx_string(const char* str) -- 直接构造
clx_string::clx_string(clx_string&& s) -- 移动构造

可以看到默认的移动赋值函数是生成了的

禁用生成默认函数的关键字delete

如果我们想要限制某些默认函数生成时,可以通过一下几种方式

  • C++98: 将函数设置成私有,并只声明不实现,这样外部调用该函数就会报错
  • C++11:在该函数的声明后面加上=delete,表示不让编译器生成该函数的默认版本

final and override 关键字

final 修饰的类

final修饰的类被称为最终类,最终类无法被继承

class UnInheritable final {}

Final 修饰虚函数

final修饰的虚函数,表示该虚函数不能再被重写,如果字类继承后重写了该虚函数编译就会报错

Override 修饰虚函数

override修饰的字类虚函数,检查该类是否是由父类继承下来的并且必须重写,如果没有重写就会报错

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

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

相关文章

23款奔驰S450 4MATIC更换原厂流星雨智能数字大灯,让智能照亮您前行的路

“流星雨”数字大灯&#xff0c;极具辨识度&#xff0c;通过260万像素的数字微镜技术&#xff0c;实现“流星雨”仪式感与高度精确的光束分布&#xff1b;在远光灯模式下&#xff0c;光束精准度更达之前84颗LED照明的100倍&#xff0c;更新增坡道照明功能&#xff0c;可根据导航…

【PCB专题】如何在Allegro中定义字体及批量修改丝印

在PCB板上丝印往往包含了很多信息,比如元件边界、元件参数、元件编号、极性、静电标识、板号等,这些信息在生产、测试及后期维护等都需要使用。一个好的设计往往都能从丝印的布局、丝印的完整性上体现出来。如下所示PCB在电解电容旁有极性丝印、电阻旁有电阻的位号信息等。 …

利用 jenkins 关联 Job 方式完善 RobotFramework 测试 Setup 以及 Teardown 后操作

目录 1.前言 2.Jekins 关联 Job 方式 1.前言 Jenkins是一个流行的持续集成和交付工具&#xff0c;它可以帮助自动化构建、测试和部署软件。与Robot Framework结合使用&#xff0c;可以实现更高效的测试工作流程。 在Robot Framework中&#xff0c;Setup和Teardown是测试用例…

SQL语句GROUP BY、HAVING、EXISTS、SQL函数(Null判断、日期相关、计算数值和字符串操作 )

目录 GROUP BY HAVING EXISTS SQL函数 Null判断函数 日期数据类型及函数 计算数值和字符串操作函数 AVG(平均值) COUNT(数据条数) FIRST/LAST(第一条数据) MAX/MIN(最大值) SUM(列总和) UCASE/ LCASE (转换大小写) MID(截取字符串) LEN(字符值的长度) ROUND(数…

什么是70v转12v芯片?

问&#xff1a;什么是70v转12v芯片&#xff1f; 答&#xff1a;70v转12v芯片是一种电子器件&#xff0c;其功能是将输入电压范围在9v至100v之间的电源转换为稳定的12v输出电压。这种芯片通常被用于充电器、车载电池充电器和电源适配器等设备中。 问&#xff1a;这种芯片的最大…

如何在Microsoft Excel中使用SORT函数

虽然 Microsoft Excel 提供了一个内置的数据排序工具,但你可能更喜欢函数和公式的灵活性。 使用 SORT 函数的好处是,你可以在不同的位置对数据进行排序。如果你想在不干扰原始数据集的情况下操作项目,你会喜欢 Excel 中的 SORT 函数。但是,如果你喜欢对项目进行原位排序,…

ES(4)核心概念

文章目录 索引文档字段映射分片副本分配 索引 一个索引就是一个拥有积分相似特征的文档的集合。我们可以有客户数据的索引、产品目录的索引、订单数据的索引。 对我而言这个索引可能更像是表的概念 文档 一个文档是一个可被检索的最基本的单元&#xff0c;也就是一条数据&…

Spring AOP的介绍与实现

文章目录 Spring AOP1. Spring AOP概念2. Spring AOP的作用3.AOP的组成4. Spring AOP的实现4.1 添加Spring AOP依赖4.2 定义切面&#xff08;创建切面类&#xff09;4.3 定义切点&#xff08;配置拦截规则&#xff09;4.3.1 切点表达式语法 4.4 定义通知的实现 5. Spring AOP实…

STM32 Proteus仿真全自动洗衣机洗涤脱水-0074

STM32 Proteus仿真全自动洗衣机洗涤脱水-0074 Proteus仿真小实验&#xff1a; STM32 Proteus仿真全自动洗衣机洗涤脱水-0074 功能&#xff1a; 硬件组成&#xff1a;STM32F103R6单片机LCD1602显示器 L298N驱动电机正反转蜂鸣器LED指示灯多个按键(标准洗&#xff0c;快速洗&a…

STM32学习笔记(十二)丨RTC实时时钟

本篇文章包含的内容 一、计算机底层计时系统——时间戳1.1 时间戳简介1.2 GMT/UTC1.3 C语言和time.h库 二、STM32的BKP和RTC时钟2.1 BKP&#xff08;Backup Registers&#xff09;备份寄存器2.2 RTC&#xff08;Real Time Clock&#xff09;实时时钟2.2.1 RTC简介2.2.2 RTC的内…

javascript 导出表格的excel

一个php网站的表格,需要增加导出excel的功能, 因对web开发不甚了解,开始想着用php导出, 搜索一番发现比较复杂,而且我的表格里已经有数据了, 如果导出又要去库中获取一次,不是负担加倍, 可否把现有表格数据,直接导出来? 答案是肯定的,用js在前端导出 开源js组件…

opencv-07-感兴趣区域(ROI)

在图像处理过程中&#xff0c;我们可能会对图像的某一个特定区域感兴趣&#xff0c;该区域被称为感兴趣区 域&#xff08;Region of Interest&#xff0c;ROI&#xff09;。在设定感兴趣区域 ROI 后&#xff0c;就可以对该区域进行整体操作。 以下是一些 OpenCV ROI应用场景 …

Blender操作快捷键

视角操作 按住鼠标中键旋转视角 滚动滚轮视角推拉 shift中键 视角平移 其它操作 X 删除物体 I 插入关键帧 N 隐藏属性工具栏 小键盘0 进入摄像机视角 ~ 切换视角 ctrlAltQ 四视图 移动旋转缩放 • G 移动 • S 缩放 (AltS 沿法线方向缩放) • R 旋转 • G(XY…

centos环境搭建nsq单点

简言 下载 启动nsq(单节点) 1. 启动nsqd 2. 启动nsqlookupd 3. 启动nsqadmin 查看状态 简言 1. nsq是go语言实现的分布式消息处理平台&#xff0c;类似我们常用的kafka&#xff0c;rocket mq等&#xff0c;目的是用来大规模地处理每天数以十亿计级别的消息。它具有分布式和…

Java集合工具:列表查找之position和find

操作集合时&#xff0c;查找列表中的元素是常见操作&#xff0c;本文记录两个平常使用的List查找工具方法。 使用示例 Testpublic void testPositionAndFind() {List<Integer> list Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);//查找list中2的下标&#xff0c;不存…

如何用Jmeter做性能测试

目录 性能测试的概念 性能测试类型 性能测试应用场景&#xff08;领域&#xff09; 性能测试常用的指标 性能测试流程 需求分析 搭建测试环境 测试场景设计 测试用例设计和脚本开发 测试数据准备 性能测试执行和管理 性能测试结果分析与调优 测试报告和跟踪 性能测…

AtcoderABC244场

A - Last LetterA - Last Letter 题目大意 给定一个长度为N的字符串S&#xff0c;由小写英文字母组成&#xff0c;打印出S的最后一个字符。 思路分析 题目要求打印出字符串S的最后一个字符&#xff0c;可以直接通过访问S的最后一个元素来获取该字符。可以使用字符串的back()…

用Arthas快速定位线上JVM问题!

Arthas分析FullGC问题定位 对于FullGC那一定不会陌生,一般来说会采用横切FullGC前置拦截(-XX:+HeapDumpBeforeFullGC)和后置拦截(-XX:+HeapDumpAfterFullGC),导出FullGC发生前后的heap dump文件,以便于我们进行FullGC原因的分析和定位。 推测分析问题之FullGC的频率过高…

unity背景缓动动效

这算是一个很常见的小功能&#xff0c;比如我们在玩横版游戏的时候&#xff0c;背景动画会以一定的频率运动&#xff0c;其实现方式也有很多种。 比如&#xff0c;使用UGUI的imageanimtion动画的方式&#xff0c;自己k桢实现。 还可以使用材质球本身的功能来实现&#xff0c;关…

WPF 自定义控件完成库容表盘显示效果

先看一下显示效果&#xff1a; 需要注意的地方有以下几点&#xff1a; 表盘的刻度分部&#xff0c;长刻度和短刻度显示。在数值80W时&#xff0c;需要更改刻度盘的颜色渐变。在数值80W时&#xff0c;更改库容总数背景的显示&#xff0c;也是颜色渐变。刻度盘控件属性定义&…