C++11--类的新功能

目录

类的新功能

默认成员函数

类成员变量初始化

强制生成默认的关键子default

禁止生成默认成员函数关键字delete

继承和多态中final和override关键字


类的新功能

默认成员函数

八个默认成员函数 

在C++11之前,一个类中有如下六个默认成员函数:

  • 构造函数
  • 析构函数
  • 拷贝构造函数
  • 拷贝赋值函数
  • 取地址重载函数
  • const取地址重载函数 

其中前四个成员函数很重要,后面四个成员函数一般不会用到,这里"默认"的意思就是你不写编译器会自动生成.在C++11标准中又增加了两个默认成员函数,分别是移动构造和移动赋值重载函数.

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

C++11中新增的移动构造函数和移动赋值函数的生成条件如下:

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

也就是说,移动构造和移动赋值的生成条件于之前的六个默认成员函数不同,并不是单纯的没有自己实现移动构造和移动赋值编译器就会默认生成.

特别注意:如果我们自己实现了移动构造或者移动赋值,就算没有实现拷贝构造和拷贝赋值,编译器也不会默认生成拷贝构造和拷贝赋值.

默认生成的移动构造和移动赋值会做什么? 

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

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

要验证默认生成的移动构造和移动赋值确实做了上述工作,这里需要模拟实现一个简化的string类,类当中只编写了几个我们需要用到的成员函数.

代码如下:

namespace lzw
{class string{public://构造函数string(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}//叫换两个对象数据void swap(string & s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}//拷贝构造的现代写法string(const string& s):_str(nullptr),_size(0),_capacity(0){cout << "string(const string& s) -- 深拷贝" << endl;string temp(s._str);swap(temp);//叫换这两个对象}//移动构造string(string&& s):_str(nullptr),_size(0),_capacity(0){cout << "string(string&& s) -- 移动构造" << endl;swap(s);}//拷贝赋值函数(现代写法)string& operator=(const string& s){cout << "string& operator=(const string& s) -- 深拷贝" << endl;string temp(s);//用s拷贝构造出temp对象swap(temp);//交换这两个对象return *this;}//移动赋值string& operator=(string&& s){cout << "string& operator=(string&& s)--移动赋值" << endl;swap(s);return *this;}//析构函数~string(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}private:char* _str;size_t _size;size_t _capacity;};
}

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

代码如下:

	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& operator=(const Person& p){if (this != &p){_name = p._name;_age = p._age;}return *this;}//析构函数~Person(){}private:string _name;int _age;};

虽然Person类当中没有实现移动构造和移动赋值,但拷贝构造,拷贝赋值和析构函数Person类都实现了,因此Person类中不会默认生成移动构造和移动赋值,可以通过下面代码验证:

int main()
{lzw::Person s1("张三", 21);lzw::Person s2 =  std::move(s1);//想要调用Person默认生成的移动构造return 0;
}

上述代码中用一个右值去构造s2对象,但由于Person类中没有生成默认的移动构造,因此这里会调用Person的拷贝构造函数(拷贝构造既能接收做值也能接收右值).这时再Person的拷贝构造函数中会调用string的拷贝构造对name成员进行深拷贝.

如果想要让Person类生成默认的移动构造函数,就必须将Person类中的拷贝构造,拷贝赋值和析构函数全部注释调,这时用右值去构造s2对象时就会调用Person默认生成的移动构造函数.

  • Person默认生成的移动构造,对于内置类型成员age会进行值拷贝,而对于自定以类型成员name,因为我们的string类实现了移动构造函数,因此它会调用string的移动构造函数进行资源转移.
  • 而如果我们将string类当中的移动构造函数注释掉,那么Person默认生成的移动构造函数,就会调用string类中的拷贝构造对name成员进行深拷贝. 

要验证Person类中默认生成的移动赋值函数可以用一下代码,验证方式和上面验证移动构造的方式是一样的.

int main()
{lzw::Person s1("张三", 21);lzw::Person s2;s2 =  std::move(s1);//想要调用Person默认生成的移动赋值return 0;
}

 说明一下:

  • 我们再模拟实现string类的拷贝构造,拷贝赋值,移动赋值和移动赋值函数中都打印了一条提示语句,因此可以通过输出控制台输出来判断是否调用了对应的函数.
  • 由于VS2013没有完全支持c++11,因此上述代码无法再vs2013当中验证,需要使用叫新的编译器,入vs2022.

类成员变量初始化

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

	private:string _name = "张三";int _age = 20;static int _n;//静态成员变量不能给缺省值

 注意:这里不是初始化.而是给声明一个缺省值.

强制生成默认的关键子default

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

列如,下面的Person类中实现了拷贝构造函数:

		//拷贝构造函数Person(const Person& p):_name(p._name),_age(p._age){}

 这是如下代码就无法编译成功了,因为Person类中编写了拷贝构造函数,导致无法生成默认的构造函数,因为默认构造函数的生成条件是没有编写任意类型的构造函数,包括拷贝构造函数.

int main()
{Person s;//没有合适的默认构造函数
}

这时我们就可以使用default关键字强制生成默认的构造函数,如下:

class Person
{
public:Person() = default;//强制生成默认的构造函数Person(const Person& p):_name(p._name),_age(p._age){}
private:string _name;int _age;
};int main()
{Person s;return 0;
}

 说明一下:默认成员函数都可以用default关键字强制生成,包括移动构造和移动赋值.

禁止生成默认成员函数关键字delete

当我们想要限制某些默认成员函数生成时,可以通过如下两种方式:

  • 在C++98中,可以将该函数设置成私有,并且只有声明不要定义,这样当外部调用该成员函数就会报错.
  • 在C++11中,可以在还函数声明后面加上=delete,表示让编译器不生成该函数的默认版本,我们将=delete修饰的函数称为删除函数. 

列如,要让一个类不能被拷贝,可以使用=delete修饰该类的拷贝构造和拷贝赋值.

class CopyBan
{
public:CopyBan(){}
private:CopyBan(const CopyBan&) = delete;CopyBan& operator=(const CopyBan&) = delete;
};

 说明一下:被=delete修饰的函数可以设置为公有,也可以设置为私有,效果都一样.

继承和多态中final和override关键字

final修饰类 

被final修饰的类叫最终类无法被继承.比如:

class NonInherit final//被final修饰,该类不能在被继承
{};

 final修饰虚函数,表示该虚函数不能再被重写,如果子类继承后重写了该虚函数则编译器报错.比如:

class Person
{
public:virtual void Print()final{cout << "hello " << endl;}
};
class Student :public Person
{
public:virtual void Print()//编译器报错{cout << "hello world" << endl;}
};

override修饰虚函数 

override修饰子类的虚函数,检查子类是否重写了父类的某个虚函数,如果没有重写则编译器报错.比如:

class Person
{
public:virtual void Print(){cout << "hello " << endl;}
};
class Student :public Person
{
public:virtual void Print() override //检查子类是重写了父类的某个虚函数{cout << "hello world" << endl;}
};

 

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

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

相关文章

2023-12-03 C语言最小二乘法备忘

点击 <C 语言编程核心突破> 快速C语言入门 C语言最小二乘法备忘 前言一、数学公式二、代码总结 前言 要解决问题: 最小二乘法实现线性回归的C语言实现, 这个数学公式转为C语言. 一、数学公式 设有 n n n 组数据 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ⋯ , ( x n , y n ) …

KDE环境文件夹user-dirs为英文

KDE环境文件夹user-dirs 修改KDE主页文件夹为英文 该文件路径 ~/.config/user-dirs.dirs打开后会发现里面的内容如下 # This file is written by xdg-user-dirs-update # If you want to change or add directories, just edit the line youre # interested in. All local …

openGauss学习笔记-140 openGauss 数据库运维-例行维护-例行维护表

文章目录 openGauss学习笔记-140 openGauss 数据库运维-例行维护-例行维护表140.1 相关概念140.2 操作步骤140.3 维护建议 openGauss学习笔记-140 openGauss 数据库运维-例行维护-例行维护表 为了保证数据库的有效运行&#xff0c;数据库必须在插入/删除操作后&#xff0c;基于…

Ant Design Pro 框架设置API Token拦截器的功能

分享记录一个解决方法&#xff0c;希望对大家有帮助。 找到文件&#xff0c;然后定义一个方法。最后调用一下即可。 代码我也给你贴上了。 // 获取token 拦截方法 const setTokenRequest (config: any) > {const token 30|eh5GNXWRe5rO4XLjbbnqy132RABfiKqI338EoIhqc790a…

思维模型 反馈效应

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。反馈促进改进。 1 反馈效应的应用 1.1 反馈效应在营销中的应用 1 “可口可乐与百事可乐之战” 在 20 世纪 80 年代&#xff0c;可口可乐公司是全球最大的饮料公司之一&#xff0c;其市场…

利用reddit的api进行爬虫

1 介绍 Reddit是一个社交新闻聚合网站&#xff0c;用户可以发布、评价和讨论各种话题。Reddit的内容涵盖了广泛的主题&#xff0c;可以从中获取大量的文本数据进行情绪分析。 2 注册 2.1 注册reddit 你需要先注册一个reddit的账号。 2.2 注册api https://www.reddit.com/…

文科专业和编程基础薄弱的女孩子做软件的神器——aardio学习资源入门

相关资源 aardio 开发桌面应用&#xff0c;这几点必须要掌握&#xff01; - 星安果的文章 - 知乎 https://zhuanlan.zhihu.com/p/430970376 从使用者角度来为aardio编程软件说句话 - popdes的文章 - 知乎 https://zhuanlan.zhihu.com/p/461290014 故事和情怀 优点 1 快捷 2 …

HarmonyOS开发(九):数据管理

1、概述 1.1、功能简介 数据管理为开发者提供数据存储、数据管理能力。 它分为两个部分&#xff1a; 数据存储&#xff1a;提供通用数据持久化能力&#xff0c;根据数据特点&#xff0c;分为用户首选项、键值型数据库和关系型数据库。数据管理&#xff1a;提供高效的数据管…

Bean的加载控制

Bean的加载控制 文章目录 Bean的加载控制编程式注解式ConditionalOn*** 编程式 public class MyImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {try {Class<?> clazz Class.forName("…

UCore-OS实验Lab0

实验内容&#xff1a;搭建ucore-os的实验环境 实验准备内容&#xff1a;vmware虚拟机&#xff0c;ubuntu22.04镜像&#xff0c;qemu7.0.0源码 ucore代码地址 GitHub - chyyuu/os_kernel_lab at x86-32 实验步骤&#xff1a; 在vmware中安装ubuntu&#xff0c;因为我个人喜欢…

★448. 找到所有数组中消失的数字

★448. 找到所有数组中消失的数字 使用数组本身当作哈希表 考虑让nums数组本身当作哈希表。 遍历nums&#xff0c;每遇到一个数x&#xff0c;就让在x-1位置处的数n。 再次遍历nums&#xff0c;如果遇到i位置上数nums[i]不大于n&#xff0c;则i1并没有出现。 eg&#xff1a; …

【智能家居】四、网络服务器线程控制功能点

网络控制 网络线程控制功能点代码 inputCommand.h&#xff08;输入控制指令&#xff09;socketControl.c&#xff08;socket网络控制指令&#xff09;main.c&#xff08;主函数&#xff09;编译运行结果 网络控制 Linux网络编程 “网络控制”&#xff08;Network Control&a…

openEuler学习04-ssl升级到openssl-1.1.1w

当前环境ssl的版本是 1.1.1f &#xff0c;计划升级到openssl-1.1.1w [roottest ~]# more /etc/os-release NAME"openEuler" VERSION"20.03 (LTS-SP3)" ID"openEuler" VERSION_ID"20.03" PRETTY_NAME"openEuler 20.03 (LTS-SP3)&q…

ES6 Promise的用法,async/await异步处理同步化

文章目录 一、什么是promise &#xff1f;二、await / async ES7的新规范&#xff0c;异步处理同步化 一、什么是promise &#xff1f; promise是解决异步的方法&#xff0c;本质上是一个构造函数&#xff0c;可以用它实例化一个对象。对象身上有resolve、reject、all&#xff…

java学习part33Date

1.Jdk8之前 1.1当前系统时间 1.2.Date类 1.2.1util.date 两个构造器两个方法 1.2.2sql.date 1.3SimpleDateFormat日期格式 1.4Calendar日历 147-常用类与基础API-JDK8之前日期时间API的使用&#xff1a;Date、SimpleDateFormat、Calendar_哔哩哔哩_bilibili 2.Jdk8 2.1本地时…

【C语言学习疑难杂症】第6期:C语言中如何打印一些特殊字符,比如打印扩展ascii码字符

首先我们来看下ascii表和ascii拓展表: ascii表中的字符只有128个,是从0-127,而拓展ascii表的内容是128-255。拓展表中它们都是一些特殊的字符,如果我们想答应ascii拓展码中的一些字符应该要怎么操作呢? 比如下面的代码: unsigned char a = 176, b = 219;printf("%…

Nginx反向代理和负载均衡详细教程

1、Nginx反向代理概述 关于正向代理和反向代理&#xff0c;我们在前面的章节已经通过一张图给大家详细的介绍过了&#xff0c;简而言之就是正向代理代理的对象是客户端&#xff0c;反向代理代理的是服务端&#xff0c;这是两者之间最大的区别。 Nginx即可以实现正向代理&#x…

游戏被流量攻击会有什么样的影响,该用什么样的防护方式去处理

德迅云安全-领先云安全服务与解决方案提供商德迅云游戏盾专门针对游戏进行防护&#xff0c;可免费提供防护方案~ 如果游戏被流量攻击会产生以下影响&#xff1a; 服务器过载&#xff1a;流量攻击会导致游戏服务器接收到的请求数量急剧增加&#xff0c;超出服务器的处理能力。这…

ESP32-Web-Server编程综合项目1-结合 Web Server 实现 WiFi 配网和网页 OTA 更新

ESP32-Web-Server编程综合项目1-结合 Web Server 实现 WiFi 配网和网页 OTA 更新 概述 前述的内容多是一个个小功能的演示&#xff0c;本章节讲述一些实际项目中使用到的综合项目。 首先要讲述的案例是通过ESP32 上的 Web Server 实现对 ESP32 的 WiFi 配网和网页 OTA 更新功…

探究两个互联网时代的差异,Web 2.0 与 Web 3.0 区别

Web 2.0 的特征 首先我们来了解一下 Web 2.0 的特征都有哪些。 用户生成内容&#xff1a;Web 2.0 时代以用户生成内容为特征&#xff0c;用户可以轻松地在网络上分享、创建和编辑信息。社交媒体平台、博客等网站的兴起使得用户成为信息的创造者&#xff0c;网络逐渐从被动浏览…