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…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
