C++11 新的类功能

news2024/11/15 6:46:44

前言

上一期我们对右值引用和完美转发作了介绍,本期我们接着上期继续介绍C++11的新的类功能!

目录

前言

• 新的类功能

默认成员函数

类成员变量初始化

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

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

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


• 新的类功能

默认成员函数

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

1、构造函数

2、析构函数

3、拷贝构造函数

4、赋值拷贝重载

5、取地址重载

6、const 取地址重载

其中,前4个很重要,后面的那两个没有那么重要!默认成员函数是我们不写编译器会生成一个默认的。C++11又增加了两个:移动构造函数移动赋值运算符重载

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

• 移动构造:自己没实现移动构造,且有实现析构函数拷贝构造赋值拷贝重载任意一个

移动赋值:自己没实现移动赋值,且有实现析构函数拷贝构造赋值拷贝重载任意一个

注意:如果自己提供了移动构造或者移动赋值 ,即使没有提供赋值拷贝和拷贝构造,编译器也不会生成!

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

• 默认移动构造:对于内置类型成员按字节拷贝; 对于自定义类型的成员,则需要看这个成员类是否实现移动构造如果实现了移动构造就调用移动构造,否则,就调用拷贝构造!

• 默认移动赋值:对于内置类型成员按字节拷贝; 对于自定义类型的成员,则需要看这个成员类是否实现移动赋值如果实现了移动赋值就调用移动赋值,否则,就调用赋值拷贝!

ok, 我们来验证一下:

为了方便演示,我们还是把以前的string类给拷贝过来:

namespace cp
{
	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& operator=(const string& s)
		{
			cout << "string& operator=(string s) -- 赋值拷贝" << endl;
			string tmp(s);
			swap(tmp);
			return *this;
		}

		// 移动构造
		string(string&& s)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			cout << "string(string&& s) -- 移动构造" << endl;
			swap(s);
		}

		// 移动赋值
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移动赋值" << endl;
			swap(s);
			return *this;
		}

		~string()
		{
			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;
		}

		const char* c_str() const
		{
			return _str;
		}


	private:
		char* _str;
		size_t _size;
		size_t _capacity; // 不包含最后做标识的\0
	};

	cp::string to_string(int value)
	{
		cp::string str;

		bool flag = true;
		if (value < 0)
		{
			flag = false;
			value = 0 - value;
		}

		while (value > 0)
		{
			int x = value % 10;
			value /= 10;

			str += ('0' + x);
		}

		if (flag == false)
		{
			str += '-';
		}

		std::reverse(str.begin(), str.end());

		return str;
	}
}

我们自己写一个Person类: 

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

这个类中有两个成员,一个是我们自己的cp::string、一个是int _age,我们当前的Person是没有:析构、拷贝构造、赋值拷贝的!此时,Person中就会有一个默认生成的移动构造,此时,我们的cp::string上期是实现了移动构造的,所以,他就会调用它的移动构造,而_age就直接按字节拷贝了!

Person s1;
Person s2 = s1;
cout << "---------------------------" << endl;
Person s3 = std::move(s1);

如果我们,把cp::string中的移动构造给注释掉,此时他就会去调用,拷贝构造:

再来看看移动赋值:

我们还是来把,cp::string中的移动赋值给注释掉,他就会调用赋值拷贝:

类成员变量初始化

C++11允许在类定义时给成员变量给一个缺省值,这个在以前就介绍过,主要是为了解决,不写构造调用默认构造时,自定义类型去调它的构造,内置类型不处理!这里的初始值,其实是给初始化列表,解决内置类型是随机值的缺陷的!

class Person
{
public:
	Person(const char* name = "", int age = 0)
		:_name(name)
		, _age(age)
	{}
private:
		cp::string _name = "张三";
		int _age = 10;//主要是解决这里的
};

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

C++11可以让你更好的控制要使用的默认函数,假设你要使用某个默认的函数,但是由于一些原因这个函数没有默认的生成。比如,你写了析构,就不会生成移动构造了,那么我们可以使用default关键字来显示的强制生成移动构造:

class Person
{
public:
	Person(const char* name, int age)
		:_name(name)
		, _age(age)
	{}

	// 我们写了构造,编译器就不会生成默认的构造了,我们可以使用default强制的生成
	Person() = default;
private:
		cp::string _name;
		int _age;
};

这里一定要注意,默认构造的含义:1、默认生成的 2、无参的 3、支持第一个参数是缺省的

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:
		cp::string _name;
		int _age;
};

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

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

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

	Person(Person& p) = delete;// 默认删除/禁用掉 拷贝构造

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

OK,我们假设现在有一个需求,需要设置一个类,该类的对象只能在堆上!我们分别用C++98和C++11的方式实现一下:

class A
{
public:
	static A* Heap_Obj()
	{
		return new A;
	}

private:
	A() {}// 将默认的构造给禁用掉
	A(const A& a);// C++98的写法,不实现,只声明
	std::string _name;
	int _age;
};

再来看看C++11的:

class A
{
public:
	static A* Heap_Obj()
	{
		return new A;
	}

	A(const A& a) = delete;// C++11直接禁用掉
private:
	A() {}// 将默认的构造给禁用掉
	//A(const A& a);// C++98的写法,不实现,只声明
	std::string _name;
	int _age;
};

当然这个我们后面单独一期介绍,一些特殊类的设计!

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

final修饰类

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

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

final修饰虚函数

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

//父类
class Person
{
public:
	virtual void Print() final //被final修饰,该虚函数不能再被重写
	{
		cout << "hello Person" << endl;
	}
};
//子类
class Student : public Person
{
public:
	virtual void Print() //重写,编译报错
	{
		cout << "hello Student" << endl;
	}
};

override修饰虚函数

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

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

OK,好兄弟本期分享就到这里,我是cp我们下期再见!

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

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

相关文章

流动网红打卡车!苏州金龙海格双层巴士带你体验别样津门津韵

近日&#xff0c;由文化和旅游部主办&#xff0c;天津市文化和旅游局等单位承办的2024中国文化旅游产业博览会在天津拉开帷幕&#xff0c;展会期间&#xff0c;来自全国各地的文旅产品精彩亮相。而在天津交通集团展台&#xff0c;来自苏州金龙海格客车制造的网红双层观光“音乐…

redis安装(以6.0.13为例)

redis-6.0.13安装 1.创建安装目录2. 上传安装包3. 替换repo文件4.依赖安装5. redis安装5.1 解压5.2 编译5.3 安装5.4 配置 6. 常用命令 1.创建安装目录 mkdir -p /apps/scripts/ cd /apps/scripts/2. 上传安装包 将redis-6.0.13.tar.gz 上传至/apps/scripts/目录下 下载链接…

一站式语音识别服务:中文、方言、多语言全覆盖

在当今全球化与多元化的社会背景下&#xff0c;语音识别技术的需求日益增长。智匠MindCraft凭借其先进的语音识别功能&#xff0c;不仅覆盖了标准的中文识别&#xff0c;还扩展到了多种方言和多国语言的识别&#xff0c;为用户提供了一站式的语音转文本解决方案。 技术亮点 1…

c# 视觉识别图片文字 二维码

1.二维码识别 插件 ZXing.Net using System; using System.Drawing; // 如果你使用的是System.Drawing.Common using ZXing;class Program {static void Main(){string imagePath "path_to_your_qr_code_image.png";var barcodeBitmap (Bitmap)Image.FromFile(im…

9.20哈好

函数体 #include"SeqList.h"void SeqList::init(int n) {this->ptrnew data[n];this->len0;this->sizen; }bool SeqList::empty() {return this->len0; }bool SeqList::full() {return this->sizethis->len; }void SeqList::push_back(data e) {i…

Zookeeper安装使用教程

# 安装 官网下载安装包 #配置文件 端口默认8080&#xff0c;可能需要更改一下 #启动 cd /Users/lisongsong/software/apache-zookeeper-3.7.2-bin/bin ./zkServer.sh start #查看运行状态 ./zkServer.sh status #停止 ./zkServer.sh stop #启动客户端 ./zkCli.sh ls /

Linux:Bash中的文件描述符

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 Linux中的所有进程&#xff0c;都拥有自己的文件描述符(File Descriptor, FD)&#xff0c;它是操作系统在管理进程和文件时的一种抽象概念。每个文件描述符由一个非负整…

在渗入测试和峰谷测试中选Flat还是Ramp-up?

前面的一篇文章中我们为大家介绍了在基准测试和规划测试中选Flat还是Ramp-up&#xff0c;具体应该怎么配置&#xff0c;在这篇文章里&#xff0c;我们继续为大家介绍在渗入测试和峰谷测试中选Flat还是Ramp-up&#xff1f; 渗入测试&#xff08;疲劳强度测试&#xff09; 使用固…

vue-ts-demo

npm i -g vue/cli PS D:\kwai\vue3\project> vue create vue3-te-demo element-plus 一个 Vue 3 UI 框架 | Element Plus https://element-plus.org/zh-CN/guide/installation.html 安装&#xff1a; npm install element-plus --save 完整引入使用&#xff1a; 使用&…

AI大模型微调实战训练营,文旅对话 知识库 大模型实战(模型参数微调)

一、引言 随着人工智能技术的飞速发展&#xff0c;AI大模型在各个领域的应用日益广泛。其中&#xff0c;大模型微调作为一种强大的工具&#xff0c;能根据特定任务定制化模型性能&#xff0c;尤其在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;文旅对话和知识库构建…

eclipse使用 笔记02

创建一个项目&#xff1a; 【File-->New-->Dynamic Web Project】 进入页面&#xff1a; Project name为项目命名 Target runtime&#xff1a;选择自己所对应的版本 finish创建成功&#xff1a; 创建成功后的删除操作&#xff1a; 创建前端界面&#xff1a; 【注意&a…

二叉树的层序遍历 II

题目链接 二叉树的层序遍历 II 题目描述 注意点 树中节点数目在范围 [0, 2000] 内-1000 < Node.val < 1000 解答思路 根据队列先进先出的特点层序遍历所有的节点&#xff08;从左到右&#xff09;&#xff0c;又因为需要自底向上的输出层序遍历的结果&#xff0c;所…

2-100 基于matlab的水果识别

基于matlab的水果识别。从面积特征、似圆形特征&#xff0c;颜色(rgb值和hsv值)特征对图像中的梨子、苹果、桃子、香蕉和菠萝进行特征提取&#xff0c;边缘检测识别&#xff0c;最后按照筛选出来的特征对水果进行识别。程序已调通&#xff0c;可直接运行。 下载源程序请点链接…

机器学习算法与实践_03概率论与贝叶斯算法笔记

1、概率论基础知识介绍 人工智能项目本质上是一个统计学项目&#xff0c;是通过对 样本 的分析&#xff0c;来评估/估计 总体 的情况&#xff0c;与数学知识相关联 高等数学 ——> 模型优化 概率论与数理统计 ——> 建模思想 线性代数 ——> 高性能计算 在机器学…

EI-BISYNCH协议,欧陆2000系列设备读取数据

EI-Bisynch是一种基于ANSI X3.28-2.5 A4标准的专有协议&#xff0c;用于消息框架。尽管其名称中包含“Bisynch”&#xff0c;但它实际上是一种基于ASCII的异步协议。数据通过7位数据位、偶校验和1个停止位进行传输。 4.1 术语解释 4.1.1 地址 每个仪器都有一个可配置的地址&…

Leetcode面试经典150题-172.阶乘后的零

给定一个整数 n &#xff0c;返回 n! 结果中尾随零的数量。 提示 n! n * (n - 1) * (n - 2) * ... * 3 * 2 * 1 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;0 解释&#xff1a;3! 6 &#xff0c;不含尾随 0示例 2&#xff1a; 输入&#xff1a;n 5 输出&a…

linux之mysql安装

1:mysql安装包下载 下载地址 可私信我直接获取安装包 2:linux下wget命令下载 下载地址 wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz3:手动安装 将自己的安装包上传到对应的位置 解压 压缩包 使用命令 tar -zxvf mysql-5.7…

chorme浏览器 您的连接不是私密连接

‌当浏览器显示“您的连接不是私密连接&#xff0c;攻击者可能会试图从 localhost 窃取您的信息&#xff08;例如&#xff1a;密码、消息或信用卡信息&#xff09;”的警告时&#xff0c;这通常意味着您正在尝试访问的网站的安全证书存在问题&#xff0c;可能是因为它使用的是自…

Windows安装启动:stable-diffusion-webui,AIGC大模型文生图、文生视频,Python

Windows安装启动:stable-diffusion-webui&#xff0c;AIGC大模型文生图、文生视频&#xff0c;Python stable-diffusion-webui是github上的AIGC开源项目&#xff0c;地址&#xff1a; https://github.com/AUTOMATIC1111/stable-diffusion-webuihttps://github.com/AUTOMATIC1…

移动技术开发:简单文本编辑器

1 实验名称 简单文本编辑器 2 实验目的 掌握基本布局管理器的使用方法和基本控件的使用方法&#xff0c;以及事件监听处理的使用方法 3 实验源代码 布局文件代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:an…