C++类与对象(拷贝与类的内存管理)

感谢大佬的光临各位,希望和大家一起进步,望得到你的三连,互三支持,一起进步

个人主页:LaNzikinh-CSDN博客

文章目录

  • 前言
  • 一.对象的动态建立和释放
  • 二.多个对象的构造和析构
  • 三.深拷贝与浅拷贝
  • 四.C++类的内存管理
  • 总结

前言 

我们前面讲起了一些关于C++中类与对象的一些语法,构造函数C构函数初始化成员列表等等,也讲了面对对象的程序设计方法和面对过程的程序设计方法有什么区别,我们这次就主要针对类与对象的拷贝和一些存储内存的角度继续了解


一.对象的动态建立和释放

我们在C语言中动态开辟内存和释放内存,用用到的就是malloc函数和free函数,当然在C++中也是可用的,但是来到了C++,我们就要用C++的语法,在这个地方我们主要是用new和delete来动态建立和释放。

new和delete都是运算符,不是库函数,不需要单独添加头文件,而我们malloc和free都需要头文件,而且是函数,有函数的调用就要开辟栈空间,所以而运算符是不需要的,所以说这也体现的C++的好处

格式:
new
1、类型指针 指针变量名 = new 类型
2、类型指针 指针变量名 = new 类型(初始值)
3、类型指针 指针变量名 = new 类型[元素个数]
delete
1、delete 指针变量名
2、delete[] 指针变量名

int main()
{
	//在堆上申请一个int类型大小的空间,并且将申请的空间初始化为10
	int* p1 = new int(10);
	delete p1;
	//在堆上申请4个int类型大小的空间,并没初始化
	int* p2 = new int[4];
	delete[4] p2;
	//在堆上申请一个Box类型大小的空间,会构造对象出来
	Box* p3 = new Box;
	delete p3;
	//在堆上申请4个Box类型大小的空间,会构造对象出来
	Box* p4 = new Box[4];
	delete[4] p4;
	return 0;
}

注意

new和delete是运算符,不是函数,因此执行效率高。虽然为了与C语言兼容,C++仍保留malloc和free函数,但建议用户不用malloc和free函数,而用new和delete运算符。new/delete 和 malloc/free有何取别呢?

1、malloc/free为C的标准库函数,new、delete则为C++的操作运算符
2、new能自动计算需要分配的内存空间,而malloc需要手工计算字节数
3、new与delete直接带具体类型的指针,malloc和free返回void类型的指针。
4、new类型是安全的,而malloc不是。例如int*p = new float[2];就会报错;
而int p = malloc(2sizeof(int))编译时编译器就无法指出错误来。
5、new调用构造函数,malloc不能;delete调用析构函数,而free不能
6.new/delete是操作符可以重载,malloc/free则不能

二.多个对象的构造和析构

我们之前学了析构函数和构造函数,但是有没有想过在多个对象中析构和构造的调用顺序是怎么样的呢?

注意:1.当类中的成员变量为另一个类的实例化对象时,我们称这个对象为成员对象。2.成员变量虽属的类中没有实现无参的构造函数是需要使用初始化成员列表。

#include<iostream>
using namespace std;
class ABC
{
public:
	ABC(int A, int B, int C)
	{
		cout << "ABC(int A, int B, int C)" << endl;
	}
	~ABC()
	{
		cout << "~ABC()" << endl;
	}
private:
	int a;
	int b;
	int c;
};
class myD
{
public:
	myD() :abc1(1, 2, 3), abc2(3, 5, 7)
	{
		cout << "myD()" << endl;
	}
	~myD()
	{
		cout << "~myD()" << endl;
	}


private:
	ABC abc1;
	ABC abc2;
};
int main()
{
	myD a;

	return 0;
}

调用顺序

最开始先是构造成员对象,所以先调用成员对象所对应的构造函数,然后就是构造函数本身,最后是析构函数,析构函数的调用顺序与构造相反,总之就是先构造成员对象,在构造本身,析构相反

三.深拷贝与浅拷贝

3.1拷贝构造函数

当使用已经构造好的对象t1,初始化一个新的对象就会调用拷贝构造函数

//拷贝构造函数
Test(const Test& t)
{
	cout << "Test(const Test& t)" << endl;
}

3.2对象的赋值

思考这样的赋值对吗?

#include<iostream>
using namespace std;
class Test
{
public:
	int x;
	int y;
	int* sum;
	Test(int a, int b):x(a),y(b)
	{
		sum = new int[4];
	}
	//拷贝构造函数
	Test(const Test& t)
	{
		cout << "Test(const Test& t)" << endl;
		x = t.x;
		y = t.y;
		sum = t.sum;
	}
	~Test()
	{
		delete[4] sum;
	}
};
int main()
{
	Test t1(10,20);
	t1.sum[0] = 10; t1.sum[1] = 11; t1.sum[2] = 12; t1.sum[3] = 13;
	Test t2 = t1;
}

答案是不对的,不可以直接这样赋值会出现问题,为什么呢?因为他们的sum的地址都指向同一个地方。这个赋值并没有开辟两个空间,而是让这两个成员变量都指向了同一个区域。调用析构函数的时候会释放两次,因此就会造成问题

这个就是拷贝错误,拷贝分为浅拷贝和深拷贝,同一类对象之间的负值一般是没有副作用的,但是类中有指针,并且指针指向的动态分配的内存空间时会导致两个对象的指针指向同一块内存空间,遇到这种情况时浅拷贝,他就不能解决问题,我们就要用深拷贝去解决

class Test
{
public:
	int x;
	int y;
	int* sum;
	Test(int a, int b):x(a),y(b)
	{
		sum = new int[4];
	}
	//拷贝构造函数
	Test(const Test& t)
	{
		cout << "Test(const Test& t)" << endl;
		x = t.x;
		y = t.y;
		//浅拷贝
	    //sum = t.sum;
		//深拷贝
		sum = new int[4];
	for (int i = 0; i < 4; i++)
	{
		sum[i] = t.sum[i];
	}
	}
	~Test()
	{
		delete[4] sum;
	}
};

3.3浅拷贝

1、同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况被称为浅拷贝
2、一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,将导致两个对象的指针变量向同一块内存空间,当两个对象被销毁时调用析构函数,因为在析构函数中会释放指针所指向的堆空间,造成同一块堆空间被释放两次从而导致程序运行出错。
3、如果我们没有实现拷贝构造函数,C++编译器会自动实现一个拷贝构造函数,我们称之为默认拷贝构造函数,但是在默认拷贝构造函数中实现的时浅拷贝

3.4深拷贝

实现拷贝构造函数,在拷贝构造函数中需要对对象中的指针变量进行单独的内存申请。两个对象中的指针变量不会指向同一块内存空间,然后再将右值对象指针所指向的空间中的内容拷贝到新的对象指针所指向的堆空间中。

四.C++类的内存管理

C++类和对象中成员变量和成员函数是分开存储的,成员变量:静态成员变量存储于全局数据区中普通成员变量存储于函数中与结构体变量有相同的字节对其方式。成员函数:存放于代码段

证明:

#include<iostream>
using namespace std;
class C1
{
public:
	int i;
	int j;
	int k;
};
class C2
{
public:
	int i;
	int j;
	int k;
	int getK()
	{
		return k;
	}
	void setK(int val)
	{
		k = val;
	}
};

int main()
{
	C1 c1;
	C2 c2;
	cout << sizeof(c1) << endl;
	cout << sizeof(c2) << endl;
}

4.2this指针

this指针的本质--指针常量,当形参和成员变量同名时,可用this指针来区分

using namespace std;
class ABC
{
public:
	int x, y, z;
	ABC(int x, int y, int z)
	{
		x = x;
		y = y;
		z = z;
	}
};
int main()
{
	ABC a(1, 2, 3);
	return 0;
}

经过编译

this指针指向调用该成员函数的对象

class ABC
{
public:
	int x, y, z;
	ABC(ABC*const this,int x, int y, int z)
	{
		this->x = x;
		this->y = y;
		this->z = z;
	}
};
int main()
{
	//&a就是this指针
	ABC a(&a,1, 2, 3);
	return 0;
}

4.3类的静态成员变量

如果我要记录一个农场里面羊的数量,我该如何写呢?如果用C语言来写的话,就是面对过程的编程只有有样出生我就++,有羊死去我就减减,但是麻烦的是每个羊他可能会有年龄名字就会非常的繁琐,但是如果你是用c++面对对象的编程的话,我就可以直接构造一个样的类利用构造函数和析构函数来完成这个事情,而静态成员变量可以让这个事情完成的更完美,他是什么意思呢?可以用关键字static用于声明一个类的成员,静态的成员提供了一个同类对象的共享机制

#include<iostream>
using namespace std;
class sheep
{
public:
	int age;
	char name[32];
	sheep()
	{
		cnt++;
	}
	~sheep()
	{
		cnt--;
	}
	static int cnt;
};

int sheep::cnt = 0;
int main()
{

	return 0;
}

static int cnt;只是声明了一个静态成员变量,不是内或者对象的成员变量,但是他的作用与在内和这些类的所有实例化对象中

int sheep::cnt = 0;定义了sheep这个类中的静态成员变量cnt,并初始化为零,如果不初始化默认为4

4.4类的静态成员函数

定义:使用static修饰的成员函数叫做静态成员函数

在静态成员函数内,不能访问除静态成员函数以外的其他成员变量

什么时候可以将函数设计成静态成员函数?

函数的行为跟类的实例无关,只跟类有关

静态成员函数的用处:

1.访问被private/protected修饰静态成员变量
2.可以实现某些特殊的设计模式:如Singleton(单例模式)
3.可以封装某些算法,比如数学函数,如In,sin,tan等等,这些函数本就没必要属于任何一个对象,所以从类上调用感觉更好,比如定义一个数学函数类Math。


总结

这次我们主要讲解了对象的动态开辟和释放对比C语言的不同,和前面所讲到的析构和构造的一个升华,是多对象的析构和构造,还讲了C++独特的浅拷贝和深拷贝以及C++类的一些内存管理如类的静态成员变量静态成员函数和this指针

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

⌈ 传知代码 ⌋ 以思维链为线索推理隐含情感

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

基于改进YOLOv5的小目标检测 | 添加CBAM注意机制 + 更换Neck网络之BiFPN + 增加高分辨率检测头

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。本文针对图像中小目标难以检测的问题&#xff0c;提出了一种基于YOLOv5的改进模型。在主干网络中&#xff0c;加入CBAM注意力模块增强网络特征提取能力&#xff1b;在颈部网络部分&#xff0c;使用BiFPN结构替换PANet结构&…

Linux驱动应用编程(三)UART串口

本文目录 前述一、手册查看二、命令行调试串口1. 查看设备节点2. 使用stty命令设置串口3. 查看串口配置信息4. 调试串口 三、代码编写1. 常用API2. 例程●线程优化●poll优化●select优化&#xff08;功能和poll一样&#xff09; 前述 在开始实验前&#xff0c;请一定要检查测试…

【RabbitMQ】RabbitMQ配置与交换机学习

【RabbitMQ】RabbitMQ配置与交换机学习 文章目录 【RabbitMQ】RabbitMQ配置与交换机学习简介安装和部署1. 安装RabbitMQ2.创建virtual-host3. 添加依赖4.修改配置文件 WorkQueues模型1.编写消息发送测试类2.编写消息接收&#xff08;监听&#xff09;类3. 实现能者多劳 交换机F…

【深度学习】—— 神经网络介绍

神经网络介绍 本系列主要是吴恩达深度学习系列视频的笔记&#xff0c;传送门&#xff1a;https://www.coursera.org/deeplearning-ai 目录 神经网络介绍神经网络的应用深度学习兴起的原因 神经网络&#xff0c;全称人工神经网络&#xff08;Artificial Neural Network&#xf…

25.逢七必过

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/363 题目描述 逢七必过的游戏规则如下:对一…

Linux安装Docker | 使用国内镜像

环境 CentOS7 先确认能够上网 curl www.baidu.com返回该输出说明网络OK 步骤一&#xff1a;安装gcc 和 gcc-c yum -y install gccyum -y install gcc-c步骤二&#xff1a;安装Docker仓库 yum install -y yum-utils接下来配置yum的国内镜像 yum-config-manager --add-re…

激活乡村振兴新动能:推动农村产业融合发展,打造具有地方特色的美丽乡村,实现乡村全面振兴

目录 一、推动农村产业融合发展 1、农业产业链条的延伸 2、农业与旅游业的结合 二、挖掘地方特色&#xff0c;打造美丽乡村 1、保护和传承乡村文化 2、发展特色农业 三、加强基础设施建设&#xff0c;提升乡村品质 1、改善农村交通条件 2、提升农村水利设施 四、促进…

大数据湖一体化运营管理建设方案(49页PPT)

方案介绍&#xff1a; 本大数据湖一体化运营管理建设方案通过构建统一存储、高效处理、智能分析和安全管控的大数据湖平台&#xff0c;实现了企业数据的集中管理、快速处理和智能分析。该方案具有可扩展性、高性能、智能化、安全性和易用性等特点&#xff0c;能够为企业数字化…

水滴型锤片粉碎机:多功能粉碎利器

在现代工业生产中&#xff0c;粉碎机作为一种重要的机械设备&#xff0c;广泛应用于饲料、化工、木材等多个领域。其中&#xff0c;水滴型锤片粉碎机凭借其设计和粉碎能力&#xff0c;成为市场上的热门产品。 水滴型锤片粉碎机其设计灵感来源于水滴的形态。这种设计使得机器在…

vmware-17虚拟机安装教程,安装linux centos系统

下载VMware 1.进入VMware官网&#xff1a;https://www.vmware.com/sg/products/workstation-pro.html 2.向下翻找到&#xff0c;如下界面并点击“现在安装” 因官网更新页面出现误差&#xff0c;现提供vmware17安装包网盘链接如下&#xff1a; 链接&#xff1a;https://pan.b…

【SpringBoot + Vue 尚庭公寓实战】基本属性接口实现(七)

【SpringBoot Vue 尚庭公寓实战】基本属性接口实现&#xff08;七&#xff09; 文章目录 【SpringBoot Vue 尚庭公寓实战】基本属性接口实现&#xff08;七&#xff09;1、保存或更新属性名称2、保存或更新属性值3、查询全部属性名称和属性值列表4、根据ID删除属性名称5、根据…

freertos内核拓展DAY2(消息队列)

这节内容是信号量的基础&#xff0c;因为创建以及发送/等待信号量所调用的底层函数&#xff0c;就是创建/发送/接受消息队列时所用到的通用创建函数&#xff0c;这里先补充一下数据结构中关于队列的知识。 目录 1. 队列原理 1.1 顺序队列操作 1.2 循环队列操作 2.消息队列原…

N32G45XVL-STB之移植LVGL(lvgl-8.2.0)

目录 概述 1 软硬件介绍 1.1 软件版本信息 1.2 ST7796-LCD 1.3 MCU IO与LCD PIN对应关系 2 认识LVGL 2.1 LVGL官网 2.2 LVGL库文件下载 3 移植LVGL 3.1 准备移植文件 3.2 添加lvgl库文件到项目 3.2.1 src下的文件 3.2.2 examples下的文件 3.2.3 配置文件路径 3.2…

python-数字黑洞

[题目描述] 给定一个三位数&#xff0c;要求各位不能相同。例如&#xff0c;352是符合要求的&#xff0c;112是不符合要求的。将这个三位数的三个数字重新排列&#xff0c;得到的最大的数&#xff0c;减去得到的最小的数&#xff0c;形成一个新的三位数。对这个新的三位数可以重…

【Web世界探险家】3. CSS美学(二)文本样式

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更…

Web学习_SQL注入_布尔盲注

盲注就是在SQL注入过程中&#xff0c;SQL语句执行后&#xff0c;查询到的数据不能 回显到前端页面。此时&#xff0c;我们需要利用一些方法进行判断或者尝 试&#xff0c;这个过程称之为盲注。而布尔盲注就是SQL语句执行后&#xff0c;页面 不返回具体数据&#xff0c;数据库只…

32、matlab:基于模板匹配的车牌识别

1、准备工作 1&#xff09;准备材料 车牌字符模板和测试的实验车牌 2&#xff09;车牌字符模板 数字、字母和省份缩写 3&#xff09;测试车牌 四张测试车牌 2、车牌识别实现(已将其嵌入matlab) 1&#xff09;打开APP 找到APP 找到我的APP双击点开 2)界面介绍 包括&am…

神经网络 torch.nn---Non-Linear Activations (ReLU)

ReLU — PyTorch 2.3 documentation torch.nn - PyTorch中文文档 (pytorch-cn.readthedocs.io) 非线性变换的目的 非线性变换的目的是为神经网络引入一些非线性特征&#xff0c;使其训练出一些符合各种曲线或各种特征的模型。 换句话来说&#xff0c;如果模型都是直线特征的…

【数据结构】排序(上)

个人主页~ 堆排序看这篇~ 还有这篇~ 排序 一、排序的概念及应用1、概念2、常见的排序算法 二、常见排序的实现1、直接插入排序&#xff08;1&#xff09;基本思想&#xff08;2&#xff09;代码实现&#xff08;3&#xff09;时间复杂度&#xff08;4&#xff09;空间复杂度 2…