C++基础语法:复制构造函数,赋值构造函数及浅复制,深复制
前言
"打牢基础,万事不愁" .C++的基础语法的学习
引入
前一篇帖子C++基础语法:类构造函数之普通构造函数-CSDN博客讲了普通构造函数,还有 复制构造函数,赋值运算符以及延伸出来的浅复制和深复制问题,做个补充.
内容主要参考自<<C++ Prime Plus>> 6th Edition 第12章 类和动态内存分配
题外话
先说说个人心得,这部分内容是C++学习首次接触时,开始觉得杂乱的地方,也可以说是第一个难点(当然后面还有多种继承方式,多重继承啊,模板啊,算法啊,也不容易).所以需要好好梳理他的来龙去脉. 类可以包络一切数据和逻辑,类写完了,程序差不多就完成了.所以构造类对象比较重要.
再谈谈学习方法,纯记忆学习,很牢靠也很让人踏实.但有两个问题,一是记不记得了那么多,有的人记忆力没那么好.二是容易造成一个不爱思考的"舒适区",编程本身就是在表达逻辑,比使用逻辑要深一层.所以学习最好能建立逻辑链,以"现有知识"推导"未知",同时把"未知"变为"已知"
复制构造函数
对象的生成方法,不止使用普通构造函数,还可以使用复制构造函数.他们在形式上有差别.普通构造函数,使用了非对象做参数;复制构造函数,使用已生成的对象做参数,生成新的对象.例如:
#include<iostream>
using namespace std;
class Person { //类声明string description;double money;
public:Person(const string& des, double mo) :description(des), money(mo) {}double getMoney() {return money;}string getDescription() {return description;}
};int main(void) {Person Annie = Person("beautiful", 5000); //普通构造函数生成对象安妮Person Julie(Annie); //复制构造函数生成对象朱丽,属性值和安妮相同cout << "安妮的私房钱:" << Annie.getMoney() << endl;cout << "朱莉的私房钱:" << Julie.getMoney() << endl;
}
----对象Annie的生成调用了普通构造函数,对象Julie的生成调用了复制构造函数.
复制构造函数还有另外几种形式: 不用可以去记忆,他们的共同特征是以已有对象做参数.
Person Julie=Annie;
Person Julie=Person(Annie);
Person *pJulie=new Person(Annie);
赋值运算符
和复制构造函数几乎相同:
Person Rebecca; //声明对象瑞贝卡Rebecca = Julie; //将Julie的属性值赋给Rebeccacout << "瑞贝卡的私房钱:" << Rebecca.getMoney() << endl;
=============================================================Person(){} //类声明中加上默认构造函数,否则报错
函数原型及浅复制
每个类存在默认复制构造函数和默认赋值运算符,本例中的原型是:
Person (const Person&); //默认复制构造函数原型
Person& Person::operator=(const Person&); //赋值运算符重载
他表达的逻辑: 传入已有对象时,将对象的属性值赋给新对象,
===========================内容分割线:小思考=============================
疑问:原型内部逻辑怎样实现属性值复制?
java里有反射机制,可以获得每个类的属性和方法,C++没有明确说明是怎样实现"反射"的.但可以肯定的是:一定存在类似反射的机制,可以获得每个类的属性.他有可能被封装进源码里,没有将接口开放给程序员.
===========================内容分割线:小思考=============================
浅复制的问题
篇幅所限,代码参考<<C++ Prime Plus>> 6th Edition 第12章 类和动态内存分配 中的String类
1>无法处理类静态变量
这里必须说明,因为静态变量num_strings是表示生成对象的数量,在普通构造函数中有所表示---每生成一个对象,num_strings++;而在默认的复制构造函数和赋值符"="的定义中,没有表示,所以会造成调用后两种方法生成对象时,不会记录到静态变量中.----这不是语法造成的,而是逻辑上的错误.自定义默认构造函数和赋值符解决
2>当传入指针,并在析构函数中调用delete删除指针指向对象,又把对象浅复制,并且两次调用析构函数.
第2个问题的条件比较长,分两步来理解.
首先是类设计时,有指针传入; 在析构函数中调用delete删除指针指向的对象.
然后在生成对象object后,浅复制生成了新对象newObject(可能有多个).两次或多次调用析构函数释放内存,使删除出错. -----原因:C++两次释放同一块空间会出现错误.
浅复制问题的解决:深复制
深复制可以解决浅复制带来的问题,操作也比较简单,不管是普通构造函数,复制构造函数,赋值运算符重载,都用new开辟一块内存空间,复制传入指针指向的数据,在析构函数里定义delete.那么不管怎样复制对象,每生成一个对象,调用delete一次,不会出错.
深复制的问题
以下内容书上没有,属于自己总结,有版权:)
===========================内容分割线:小思考============================
为什么要给类传入指针?
C++是追求性能的语言,试想这种场景:尽可能的占用少的内存.内存分为三块:静态内存,局部变量使用内存,动态内存;那么可以推导出程序运行占用的内存只有类定义,函数定义(这些空间无法节省),所有的数据都用new动态生成,用完即删除.所以传入的指针都是new生成的.
===========================内容分割线:小思考============================
深复制有以下两个问题:
1>和以上内容存在悖论,为了正确的删除,占用了更多的内存空间.
2>给指针分配多少内存合适?书上的例子是char *指针,可以求出其占用空间,若指针指向数组,可以用sizeof()求出,如果指针指向链表或者其他数据集合又该怎么办呢?
深复制问题的解决
1>所有构造函数定义和赋值运算符重载都不用new分配空间(比书上还省一点),什么时候删除指针指向的数据,全由程序员自己掌握.举例:
class Demo { //演示类,属性有指针int* demo;
public:Demo(int * de):demo(de){}void show() {cout << "数组中的第1个数字是:" << *demo << endl;}
// ~Demo() { delete[] demo; }; //若启用则删除传入指针指向数据,和"delete[] a"互斥
};
================================================================
int main(void) {int *a=new int[] { 10,20 }; //动态分配空间建立数组,生成指针aDemo *d=new Demo(a); //传入指针,并动态生成对象dd->show();delete d; //删除动态生成对象dcout << "现在数组中第1个数字是" << *a << endl;delete[] a; //手动删除a,需要注释~Demo()否则报错
}
----说明:又回到浅复制了, 代码少了许多(如果解决静态变量问题需补上定义)
2>不要传入指针,把数据放到一个类里,传入该类对象的引用.用对象引用去控制数据,内存占一点也没关系,省事多了.需要新对象的话再用普通构造函数生成一个
----说明:不要说深复制,浅复制都被省了,整个12章的内容几乎都被省去了.对作者和书的内容无可厚非,设计了这种机制,也讲清楚了.
小结
C++构造函数的理解和应用
相关文章:
C++基础语法:复制构造函数,赋值构造函数及浅复制,深复制
前言 "打牢基础,万事不愁" .C的基础语法的学习 引入 前一篇帖子C基础语法:类构造函数之普通构造函数-CSDN博客讲了普通构造函数,还有 复制构造函数,赋值运算符以及延伸出来的浅复制和深复制问题,做个补充. 内容主要参考自<<C Prime Plus>> 6th Edition …...
架构是怎样练成的-楼宇监控系统案例
目录 概要 项目背景 原系统设计方案 改进后的设计方案 小结 概要 绝大多数人掌握的架构都是直接学习,慢慢地才能体会到一个架构的好处。架构是一种抽象,是为了复用目的而对代码做的抽象。通过一个项目的改造,理解架构是如何产生的&…...
valgrind使用浅谈
1、Valgrind 简介 Valgrind是一款用于内存调试、内存泄漏检测以及性能分析的软件开发工具,它可在以下平台上运行: X86/Linux、AMD64/Linux、ARM/Linux、ARM64/Linux、PPC32/Linux、PPC64/Linux、PPC64LE/Linu x、S390X/Linux、MIPS32/Linux、MIPS64/Li…...
强化学习专题:强化学习知识梳理(一)
2024/6/23: 前段时间有幸完成了大学期间的第一篇论文。在面试之前复盘一下关于自己论文中DQN的一些相关点。 浅谈主要区别(在线 or 离线) 首先,一切的开始是强化学习中时序差分方程,这体现了强化学习方法的优化策略。在…...
深入JVM:详解JIT即时编译器
文章目录 深入JVM:详解JIT即时编译器一、序言二、基础概念1、何为JIT即时编译2、热点代码 三、HotSpot内置的即时编译器1、C1编译器2、C2编译器3、分层编译3.1 协作流程 四、常见JIT优化技术1、方法内联2、逃逸分析(1)同步锁消除(…...
ORBSLAM3_ROS_Ubuntu18_04环境搭建安装
orbslam3安装 ORB-SLAM3配置及安装教程(2023.3)_orbslam3安装-CSDN博客 换源,换成国内的 搜索software 安装工具 sudo apt install git sudo apt update sudo apt install gcc g cmake安装 cmake安装新版本 ubuntu20.04安装cmake详细…...
【opencv - C++ - Ubuntu】putText 显示中文最快方法
话不多说,直接上代码 #include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/freetype.hpp>using namespace std; using namespace cv;int main(void) {Mat image(1000, 1800, CV_8UC3, Scalar(200,162,33));Ptr<freetype::F…...
百度网盘下载速度慢的解决办法
目录 一、背景 二、解决办法 1、点击三个竖点,再点设置 2、点击传输,再点击去开启该功能 3、点击同意,开启优化速率 三、结果 四、备注 一、背景 当你不是百度网盘会员时,你在使用百度网盘下载时,是否下载速度太…...
Python api接口 异步
Python API接口异步编程简介 在现代的软件开发中,大多数应用都需要通过API接口与其他系统进行交互。Python是一种非常流行的编程语言,因此许多开发者选择使用Python来构建他们的API接口。在一些情况下,API接口需要进行异步编程,以…...
Java 和 Kotlin 单例模式写法对比
目录 1、饿汉模式 Java 写法: Kotlin 写法: Kotlin 这段代码反编译&简化后如下: 2、懒汉模式,静态同步方法 Java 写法: Kotlin 写法: Kotlin 这段代码反编译&简化后如下: 3、懒…...
解析connectionReset异常的原因与解决方案
解析connectionReset异常的原因与解决方案 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨Java中connectionReset异常的原因及其解决方案。这…...
mindspore打卡第9天 transformer的encoder和decoder部分
mindspore打卡第9天 transformer的encoder和decoder部分 import mindspore from mindspore import nn from mindspore import ops from mindspore import Tensor from mindspore import dtype as mstypeclass ScaledDotProductAttention(nn.Cell):def __init__(self, dropout_…...
Python实现IPv4地址和16进制互相转换
Python实现IPv4地址和16进制互相转换 import socketdef ip_to_hex16(ipaddr):# 使用 socket 库中的方法将IP地址转换为网络字节序的二进制表示hex_bytes socket.inet_aton(ipaddr)# 将二进制数据转换为整数, 其中byteorderbig 表示使用大端字节序(从高位到低位&…...
计算机视觉 | 基于图像处理和边缘检测算法的黄豆计数实验
目录 一、实验原理二、实验步骤1. 图像读取与预处理2. 边缘检测3. 轮廓检测4. 标记轮廓序号 三、实验结果四、完整代码 Hi,大家好,我是半亩花海。 本实验旨在利用 Python 和 OpenCV 库,通过图像处理和边缘检测算法实现黄豆图像的自动识别和计…...
深入分析 Android BroadcastReceiver (七)
文章目录 深入分析 Android BroadcastReceiver (七)1. 高级应用场景1.1 示例:动态权限请求1.2 示例:应用内通知更新 2. 安全性与性能优化2.1 示例:设置权限防止广播攻击2.2 示例:使用 LocalBroadcastManager2.3 示例:在…...
C++中的数据结构
一.STL标准库 结构:STL中有六大组件,分别是:容器,算法,迭代器,仿函数,配接器,配置器;以下分别介绍这六大组件中的最主要的三个。 1.容器 容器来配置存储空间,算法通过…...
武汉星起航:一站式服务,助力亚马逊卖家高效运营,实现收益飞跃
在跨境电商的浪潮中,武汉星起航电子商务有限公司以其独特的一站式跨境电商服务,为众多亚马逊卖家提供了强有力的支持,助力他们在不断发展的市场中脱颖而出,实现收益的大幅提升。 武汉星起航的一站式跨境电商服务,以其…...
从灵感到实践:Kimi辅助完成学术论文选题的文艺之旅
学境思源,一键生成论文初稿: AcademicIdeas - 学境思源AI论文写作 昨天我们为大家介绍了ChatGPT辅助完成实现设计(AI与学术的交响:ChatGPT辅助下的实验设计新篇章)。今天我们再来看看Kimi对于论文选题都能提供哪些帮助…...
华为od-C卷200分题目4 -电脑病毒感染
华为od-C卷200分题目4 -电脑病毒感染 一个局域网内有很多台电脑,分别标注为0 - N-1的数字。相连接的电脑距离不一样,所以感染时间不一样,感染时间用t表示。其中网络内一个电脑被病毒感染,其感染网络内所有的电脑需要最少需要多长…...
show-overflow-tooltip 解决elementui el-table标签自动换行的问题
elementui中 el-table中某一行的高度不想因为宽度不够而撑开换行展示的解决方法。可通过show-overflow-tooltip属性解决,如下 代码是这样的 <el-table-column width"80" prop"id" label"ID"></el-table-column> <el…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...
软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...
