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的属性值赋给Rebecca
    cout << "瑞贝卡的私房钱:" << 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 };                 //动态分配空间建立数组,生成指针a
    Demo *d=new Demo(a);                        //传入指针,并动态生成对象d
    d->show();
    delete d;                                   //删除动态生成对象d
    cout << "现在数组中第1个数字是" << *a << endl;
    delete[] a;                                 //手动删除a,需要注释~Demo()否则报错
}

----说明:又回到浅复制了, 代码少了许多(如果解决静态变量问题需补上定义)

        2>不要传入指针,把数据放到一个类里,传入该类对象的引用.用对象引用去控制数据,内存占一点也没关系,省事多了.需要新对象的话再用普通构造函数生成一个

----说明:不要说深复制,浅复制都被省了,整个12章的内容几乎都被省去了.对作者和书的内容无可厚非,设计了这种机制,也讲清楚了.

 小结

        C++构造函数的理解和应用 

        

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

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

相关文章

电脑数据恢复篇:如何恢复误删除的文件

在清理电脑或优化存储设备时无意中删除重要文件是人类常见的错误。不可否认的是&#xff0c;在批量删除文件时&#xff0c;您经常会同时删​​除垃圾文件和重要文件。后来您发现一堆重要的文档或文件不见了。在这种情况下&#xff0c;您唯一的选择就是寻找恢复已删除文件的方法…

【机器学习300问】135、决策树算法ID3的局限性在哪儿?C4.5算法做出了怎样的改进?

ID3算法是一种用于创建决策树的机器学习算法&#xff0c;该算法基于信息论中的信息增益概念来选择最优属性进行划分。信息增益是原始数据集熵与划分后数据集熵的差值&#xff0c;熵越小表示数据集的纯度越高。有关ID3算法的详细步骤和算法公式在我之前的文章中谈到&#xff0c;…

单调队列优化DP——AcWing 135. 最大子序和

单调队列优化DP 定义 单调队列优化DP是一种在动态规划&#xff08;Dynamic Programming, DP&#xff09;中应用的数据结构优化方法。它利用单调队列&#xff08;Monotonic Queue&#xff09;这一数据结构来高效维护一个区间内的最值&#xff08;通常是最大值或最小值&#xf…

自定义一个背景图片的高度,随着容器高度的变化而变化,小于图片的高度时裁剪,大于时拉伸100%展示

1、通过js创建<image?>标签来获取背景图片的宽高比&#xff1b; 2、当元素的高度大于原有比例计算出来的高度时&#xff0c;背景图片的高度拉伸自适应100%&#xff0c;否则高度为auto&#xff0c;会自动被裁减 3、背景图片容器高度变化时&#xff0c;自动计算背景图片的…

RFID固定资产管理系统在企业中的应用与优势

随着企业资产规模的不断扩大和管理复杂性的增加&#xff0c;传统的资产管理方式已无法满足企业高效管理的需求。RFID固定资产管理系统凭借其高效、准确、实时的特点&#xff0c;成为企业固定资产管理的新宠。 一、什么是RFID固定资产管理系统 RFID&#xff08;无线射频识别&…

浪潮信息存储的灵魂:平台化+场景化 全面释放数据价值

在数字化浪潮的席卷下&#xff0c;浪潮信息存储平台凭借卓越的性能和稳定性&#xff0c;正日益成为企业释放数据价值的重要力量。近日&#xff0c;浪潮信息出席了“2024数据基础设施技术峰会”&#xff0c;相关代表聚焦当前数据价值的释放话题&#xff0c;围绕先进存储基础设施…

CSS|01 CSS简介CSS的3种书写方式注释

CSS简介 什么是CSS CSS&#xff08;Cascading Style Sheet&#xff09;&#xff0c;层叠样式表 或者 级联样式表&#xff0c;简称样式表。CSS的作用 主要用来给 HTML网页 设置外观或者样式。CSS的语法规则 h1 {属性:属性值}注意&#xff1a;1. CSS代码是由选择器和一对括号…

Ubuntu Server 和 Ubuntu Desktop 组合使用

1.常见的组合使用方式 Ubuntu Server 和 Ubuntu Desktop 确实可以组合使用&#xff0c;但具体要看你的需求和使用场景。以下是一些常见的组合使用方式&#xff1a; 单一设备上安装&#xff1a;你可以在一台设备上同时安装 Ubuntu Server 和 Ubuntu Desktop。这样&#xff0c;你…

【ONE·Linux || 高级IO(一)】

总言 主要内容&#xff1a;介绍五种IO模型的基本概念、学习IO多路转接&#xff08;select、poll编程模型&#xff09;。       文章目录 总言1、问题引入1.1、网络通信与IO1.2、五种IO模型1.2.1、举例引入1.2.2、IO模型具体含义介绍1.2.2.1、阻塞式IO1.2.2.2、非阻塞轮询检…

mathcup大数据竞赛论文中集成学习(或模型融合)的运用分析

ps: (模型融合和集成学习是两个紧密相关但又有所区别的概念。集成学习是一种更广泛的范式&#xff0c;而模型融合可以被视为集成学习的一种特殊形式或策略。) 1.集成学习原理 图1 如图1所示&#xff0c;集成学习是一种通过结合多个机器学习模型的预测来提高整体性能的策略。其…

数据结构-循环链表和双向链表

目录 前言一、循环链表1.1 循环链表的介绍1.2 循环链表的实现 二、双向链表总结 前言 本篇文章介绍数据结构中的循环链表和双向链表 一、循环链表 1.1 循环链表的介绍 将单链表的形式稍作改变&#xff0c;单链表的最后一个结点指向第一个结点 对第一个结点概念的说明&#…

Echarts地图实现:山东省报考人数

Echarts地图实现&#xff1a;山东省报考人数 效果预览 设计思路 数据可视化&#xff1a;选择地图作为数据展示的方式&#xff0c;可以直观地展示山东省不同城市的报考人数分布。交互性&#xff1a;通过ECharts的交互功能&#xff0c;如提示框&#xff08;tooltip&#xff09;…

致远互联FE协作办公平台 codeMoreWidget SQL注入致RCE漏洞复现

0x01 产品简介 致远互联FE协作办公平台是一款为企业提供全方位协同办公解决方案的产品。它集成了多个功能模块&#xff0c;旨在帮助企业实现高效的团队协作、信息共享和文档管理。 0x02 漏洞概述 致远互联FE协作办公平台 codeMoreWidget.jsp接口处存在SQL注入漏洞,未经授权攻…

有哪些防爬虫的方法

防爬虫的方法有robots.txt文、user-agent过滤、ip限制、验证码、动态页面生成、频率限制、动态url参数和反爬虫技术等。详细介绍&#xff1a;1、robots.txt文件&#xff0c;用于告诉搜索引擎爬虫哪些页面可以访问&#xff0c;哪些页面禁止访问&#xff1b;2、ip限制&#xff0c…

机器学习入门指南:理解基本概念与常见算法

目录 什么是机器学习&#xff1f; 机器学习的基本概念 1. 训练数据 2. 特征工程 3. 模型评估 监督学习与非监督学习的区别 监督学习 非监督学习 常见的机器学习算法 1. 线性回归与逻辑回归 2. 决策树与随机森林 3. 支持向量机&#xff08;SVM&#xff09; 4. K近邻…

2小时动手学习扩散模型(pytorch版)【入门版】【代码讲解】

2小时动手学习扩散模型&#xff08;pytorch版&#xff09; 课程地址 2小时动手学习扩散模型&#xff08;pytorch版&#xff09; 课程目标 给零基础同学快速了解扩散模型的核心模块&#xff0c;有个整体框架的理解。知道扩散模型的改进和设计的核心模块。 课程特色&#xf…

学生宿舍管理系统

摘 要 随着高校规模的不断扩大和学生人数的增加&#xff0c;学生宿舍管理成为高校日常管理工作中的重要组成部分。传统的学生宿舍管理方式往往依赖于纸质记录和人工管理&#xff0c;这种方式不仅效率低下&#xff0c;而且容易出错&#xff0c;无法满足现代高校管理的需求。因此…

不同node版本的切换及其指定版本vue-cli脚手架下载

目录 一.清空本地已安装node.js版本 二.装nvm管理工具 三.安装指定node版本 四.使用nvm命令切换或删除指定node版本 五.在指定node版本下下载指定vue-cli脚手架 一.清空本地已安装node.js版本 1.按健winR弹出窗口&#xff0c;键盘输入cmd&#xff0c;然后敲回车。 2.输入…

这是我见过的大模型 RAG 优化方案与实践最全总结了

暑期实习基本结束了&#xff0c;校招即将开启。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。提前准备才是完全之策。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c…

QT基本对话框(基本对话框、工具盒类、进度条、调色板与电子钟、可扩展对话框、程序启动画面)

此篇文章通过实例介绍基本对话框的用法。首先介绍标准文件对话框&#xff08;QFileDialog&#xff09;、标准颜色对话框&#xff08;QColorDialog&#xff09;、标准字体对话框&#xff08;QFontDialog&#xff09;、标准输入对话框&#xff08;QInputDialog&#xff09;以及标…