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类型大小的空间,并且将申请的空间初始化为10int* 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指针
相关文章:

C++类与对象(拷贝与类的内存管理)
感谢大佬的光临各位,希望和大家一起进步,望得到你的三连,互三支持,一起进步 个人主页:LaNzikinh-CSDN博客 文章目录 前言一.对象的动态建立和释放二.多个对象的构造和析构三.深拷贝与浅拷贝四.C类的内存管理总结 前言 …...

C语言----字符函数和字符串函数
在编程的过程中,我们要经常处理字符和字符串,为了方便操作字符和字符串,c语言标准库中提供的一系列库函数,接下来我们就开始学习与认识他们 1.字符分类函数 c语言中有一系列的函数是专门做字符分类的,也就是一个字符…...

神经网络 torch.nn---Convolution Layers
torch.nn — PyTorch 2.3 documentation torch.nn - PyTorch中文文档 (pytorch-cn.readthedocs.io) torch.nn和torch.nn.functional的区别 torch.nn是对torch.nn.functional的一个封装,让使用torch.nn.functional里面的包的时候更加方便 torch.nn包含了torch.nn.…...

Linux常用基本命令-操作
目录 一、shell 1、什么是shell 二、Linux基本的命令分类 1、内部命令和外部命令 2、查看内部命令 2.1、help命令 2.2、enable 命令 2.3、type命令 2.4、whereis命令 2.5、which 命令 2.6、hash缓存 编辑 三、Linux常用命令 1、Linux命令格式 2、编辑Linux命…...

从零开始使用 Elasticsearch(8.14.0)搭建全文搜索引擎
Elasticsearch 是目前最常用的全文搜索引擎。它可以快速地存储、搜索和分析海量数据,广泛应用于维基百科、Stack Overflow、Github 等网站。 Elasticsearch 的底层是开源库 Lucene。直接使用 Lucene 需要写大量代码,而 Elasticsearch 对其进行了封装&am…...

流程与IT双驱动:锐捷网络如何构建持续领先的服务竞争力?
AI大模型及相关应用进入“竞赛时代”,算力作为关键要素备受关注,由于算力行业对网络设备和性能有较大需求,其发展也在推动ICT解决方案提供商加速升级,提升服务响应速度和服务质量。 锐捷网络是行业领先的ICT基础设施及行业解决方…...

CopyOnWriteArrayList 详细讲解以及示范
CopyOnWriteArrayList是Java集合框架中的一种线程安全的列表实现,特别适用于读多写少的并发场景。 它是通过“写时复制”(Copy-On-Write)策略来保证线程安全的,这意味着当有线程尝试修改列表时,它会先复制原列表到一个…...

01-Java和Android环境配置
appium是做app自动化测试最火的一个框架,它的主要优势是支持android和ios,同时也支持Java和Python脚本语言。而学习appium最大的难处在于环境的安装配置,本文主要介绍Java和Android环境配置,在后续文章中将会介绍appium的安装和具…...

【qt】视口和窗口坐标
视口和窗口坐标 一.视口和窗口坐标的原理二.视口和窗口坐标的好处三.演示好处四.总结 一.视口和窗口坐标的原理 在绘图事件中进行绘图 void Widget::paintEvent(QPaintEvent *event) {QPainter painter(this);QRect rect(200,0,200,200);painter.drawRect(rect);//设置视口的…...

优化SQL查询的策略和技巧 - AI提供
优化SQL查询以提高处理大型数据集的数据库性能是一个重要课题。 以下是一些关键策略和技巧,可以帮助您提升查询效率: 1、创建合适索引: 针对频繁出现在WHERE、JOIN、ORDER BY和GROUP BY子句中的列创建索引。索引能够显著加速数据检索过程。…...

平安科技智能运维案例
平安科技智能运维案例 在信息技术迅速发展的背景下,平安科技面临着运维规模庞大、内容复杂和交付要求高等挑战。通过探索智能运维,平安科技建立了集中配置管理、完善的运营管理体系和全生命周期运维平台,实施了全链路监控,显著提…...

基于深度学习的向量图预测
基于深度学习的向量图预测 向量图预测(Vector Graphics Prediction)是计算机视觉和图形学中的一个新兴任务,旨在从像素图像(栅格图像)生成相应的向量图像。向量图像由几何图形(如线条、曲线、多边形等&…...

鸿蒙HarmonyOS $r(““)与$rawfile(““)的区别
在鸿蒙(HarmonyOS)开发中,$r(“”) 和 $rawfile(“”) 是两种不同的资源引用方式,它们分别用于引用不同的资源类型。 1、$r(“”) $r 函数通常用于引用字符串、颜色、尺寸、样式等定义在资源文件(如 strings.json, c…...

简单了解java中的Collection集合
集合 1、Collection-了解 1.1、集合概述 集合就是一种能够存储多个数据的容器,常见的容器有集合和数组 那么集合和数组有什么区别嘞? 1、集合长度可变,数组的长度不可变 2、集合只能存储引用数据类型(如果要存储基本数据类型…...

java 实现导出word 自定义word 使用aspose教程包含图片 for 循环 自定义参数等功能
java 实现导出word 主要有一下几个知识点 1,aspose导入 jar包 和 java编写基础代码下载使用 aspose-words jar包导入 aspose jar 包 使用 maven导入java代码编写 2,if判断 是否显示2,显示指定值3,循环显示List 集合列表 使用 fore…...

CSS动画(炫酷表单)
1.整体效果 https://mmbiz.qpic.cn/sz_mmbiz_gif/EGZdlrTDJa6yORMSqiaEKgpwibBgfcTQZNV0pI3M8t8HQm5XliaicSO42eBiboEUC3jxQOL1bRe0xlsd8bv04xXoKwg/640?wx_fmtgif&fromappmsg&wxfrom13 表单,也需要具有吸引力和实用性。HTML源码酷炫表单不仅能够提供给用户…...

Stream
Stream 也叫Stream流,是Jdk8开始新增的一套API (java.util.stream.*),可以用于操作集合或者数组的数据。 优势: Stream流大量的结合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作集合或者数组中的…...

鸿蒙轻内核A核源码分析系列五 虚实映射(5)虚实映射解除
虚实映射解除函数LOS_ArchMmuUnmap解除进程空间虚拟地址区间与物理地址区间的映射关系,其中参数包含MMU结构体、解除映射的虚拟地址和解除映射的数量count,数量的单位是内存页数。 ⑴处函数OsGetPte1用于获取指定虚拟地址对应的L1页表项数据。⑵处计算需要解除的无效…...

编程初学者用什么软件电脑:全方位指南及深度解析
编程初学者用什么软件电脑:全方位指南及深度解析 在数字化浪潮席卷而来的今天,编程技能逐渐成为了一项必备的基本素养。对于初学者来说,选择一款合适的编程软件电脑至关重要。本文将从四个方面、五个方面、六个方面和七个方面,深…...

代理IP池功能组件
1.IP池管理器:用于管理IP池,包括IP地址的添加、删除、查询和更新等操作。 2.代理IP获取器:用于从外部资源中获取代理IP,例如从公开代理IP网站上爬取代理IP、从代理服务商订购代理IP等。 3.IP质量检测器:用于检测代理…...

Sqlite3入门和c/c++下使用
1. SQLite3基本介绍 1.1 数据库的数据类型 1.2 基本语法 1. 创建数据表格 create table 表名(字段名 数据类型, 字段名 数据类型); create table student(id int, name varchar(256), address text, QQ char(32)); 2. 插入数据 insert into 表名 valu…...

pyinstaller打包exe多种失败原因解决方法
pyinstaller打包exe多种失败原因解决方法 目录 pyinstaller打包exe多种失败原因解决方法1、pyinstaller安装有问题1.1 安装pyinstaller1.2 采用anconda的环境启动 2、pyqt5与pyside6冲突2.1 打包生成.spec文件2.2 编辑spec文件 3、打包成功后打不开exe,exe闪退3.1 s…...

x64-linux下在vscode使用vcpkg
1.使用vscode远程连接上对应的linux ,或者直接在图形化界面上使用。 2.安装vcpkg 插件,然后打开插件设置。 注意:defalut和host的主机一定和你自己的主机一致,且必须符合vcpkg三元组格式,其中你可以选择工作台的设置&a…...

运营商二要素核验-手机号机主姓名核验接口-运营商二要素核验接口
通过电信运营商验证手机号码与姓名是否一致。广泛用于实名注册、风控审核等场景,如电商、游戏、直播、金融等需要用户实名认证的场景。支持携号转网核验。 更新周期:联通T1 电信T3 移动T3~5 均为工作日 接口地址: https://www.wapi.cn/api_de…...

C++设计模式-生产者消费者模式
运行在VS2022,x86,Debug下。 32. 生产者消费者模式 解耦生产者和消费者之间的关系,即生产者和消费者只依赖缓冲区,而不相互依赖。应用:多线程并发编程,可以解决生产者和消费者之间的同步问题。实现 生产者…...

VSTO Word.net 如何在另外的工程内添加CustomTaskPane
其他工程肯定是不能直接添加CustomTaskPane面板的,但我们可以在ThisAddIn 中先把对应的panel给新建出来再进行隐藏。步骤如下: 1.在另外工程中定义public static CustomTaskPane currMainForm;把需要隐藏的界面赋值给currMainForm; 2.在另外…...

ROS——自定义话题消息和使用方法
定义Person话题 定义Person发布者 /*** 该例程将发布/person_info话题,自定义消息类型: test_topic::Person*/#include <ros/ros.h> #include <test_topic/Person.h> //包含的头文件,ros相关的头文件,及自定义头文件…...

包装对象类型又是啥啊。。。
包装对象类型 目录 包装对象类型 目录包装对象的概念包装对象类型和字面量类型Objectobject 包装对象的概念 JavaScript 的8种类型之中,undefined和null其实是两个特殊值,object属于复合类型,剩下的五种属于原始类型(primiti…...

服务编排如何选?这几款可视化服务编排引擎,开发团队赶紧收藏
最近看到几款不错的服务编排的产品,先给大家上图看看 扣子: jvs-logic: node-red: jvs-rules: 上述几个产品是最近看到的 几个比较有特点的服务编排的系统。 接下来我对API详细分解下,说明下优点与挑战 服…...

web前端语言框架:探索现代前端开发的核心架构
web前端语言框架:探索现代前端开发的核心架构 在快速发展的web开发领域,前端语言框架的选择对于项目的成功至关重要。它们不仅影响着开发效率,更直接关系到用户体验与网站性能。本文将从四个方面、五个方面、六个方面和七个方面,…...