c++ 类的特殊成员函数:拷贝构造函数(四)

news2024/9/28 1:24:55

1. 简介

拷贝构造是一种特殊的构造函数,用于创建一个对象,该对象是从同一类中的另一个对象复制而来的。拷贝构造函数通常采用引用参数来接收要复制的对象,并使用该对象的副本来创建一个新对象。

2. 结构

class MyClass {
public:
    MyClass(const MyClass& other) {
        // 在此处实现拷贝构造函数
    }
};

具体代码:

#include <iostream>
#include <string>

using namespace std;

//拷贝构造函数
class stu{
public:
    string name;
    int age;
    stu(){
        cout << "无参构造" <<endl;
    }
    stu(string name , int age ) : name(name) , age (age){
        cout << "有参构造" <<endl;
    }

    //-=========================
    //stu s2 = s1;
    stu(stu & s){
        cout << "运行拷贝构造函数" <<endl;
        //把拷贝源对象的数据,拷贝到现在创建的对象身上。
        name = s.name;
        age = s.age ;
    }

    //==========================
    ~stu(){
        cout << "析构函数" <<endl;
    }
};

int main() {

    stu s1("叶凡" ,24);
    cout << "s1: " <<s1.name << " " << s1.age <<endl;

    stu s2 = s1; //会执行拷贝构造函数
    cout << "s2: " <<s2.name << " " << s2.age <<endl;

    return 0;
}

运行结果:

有参构造
s1: 叶凡 24
运行拷贝构造函数
s2: 叶凡 24
析构函数
析构函数

可知 s1对象是有参构造,s2 对象利用 s1 拷贝构造的,两个是不同的对象,所以执行两次析构函数。

3.细节

拷贝构造函数:

  1. 由于是拷贝,所以函数的参数一定是拷贝源(源对象),如果是其他参数例如,则是有参构造
 stu(int age)
  1. 参数一定是当前类的类型,不能是其他类型。
  2. 为什么拷贝构造函数的参数一定是引用的类型呢?
    (1)避免无限递归调用:如果拷贝构造函数的参数不是引用,那么在执行拷贝构造函数时会一直调用自己,造成无限递归。这是因为拷贝构造函数的定义是使用一个同类对象来初始化新对象,如果参数不是引用,那么在创建参数对象时需要调用拷贝构造函数,如此就会形成无限递归,最终导致程序堆栈溢出。
stu(const stu & s){// stu s = s1; --->?  stu s = s1;  ---> stu s = s1;

(2)保证对象的数据正确性:拷贝构造函数的目的是创建一个与原对象完全相同的新对象。如果参数是值传递,那么在创建参数时就需要调用拷贝构造函数,这就会使得新对象与原对象不同。而使用引用传递,可以确保新对象与原对象完全一致。

  1. 拷贝构造函数,一般会给参数加上 const , 为什么?
    为了确保在拷贝构造函数中不会对传递进来的对象进行修改,避免无意中修改原始对象。

4. 浅拷贝的问题

对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。如果数据中有属于动态成员( 在堆内存存放 ) ,那么浅拷贝只是做指向而已,不会开辟新的空间。默认情况下,编译器提供的拷贝操作即是浅拷贝。

#include <iostream>
#include <string>

using namespace std;

class stu{
public:
    string * name = nullptr;
    int age;
    
    stu(){
        cout << "无参构造" <<endl;
    }
    
    stu(string name , int age ) : name(new string(name)) , age (age){
        cout << "有参构造" <<endl;
    }
    
    stu(stu & s){
        cout << "拷贝构造" <<endl;
        name = s.name;
        age = s.age ;
    }
    
    ~stu(){
        cout << "析构函数" <<endl;
    }
};


int main() {

    stu s1("叶凡" ,24);
    cout << "s1: " <<*s1.name << " " << s1.age <<endl;

    stu s2 = s1;

    *s2.name = "叶黑";
    cout << "s1: " <<*s1.name << " " << s1.age <<endl;
    cout << "s2: " <<*s2.name << " " << s2.age <<endl;

    return 0;
}

运行结果:

有参构造
s1: 叶凡 24
拷贝构造
s1: 叶黑 24
s2: 叶黑 24
析构函数
析构函数

画图显示其中的关系:
在这里插入图片描述浅拷贝的问题:
如果一个类有一个指向动态分配内存的指针成员变量

  1. 在拷贝对象和原始对象中,成员变量所指向的内存区域是相同的,如果在拷贝对象中修改了这些成员变量,那么原始对象中对应的成员变量也会被修改,这可能会导致意想不到的行为。
  2. 如果拷贝构造函数使用浅拷贝,那么拷贝对象和原始对象将共享同一块内存,如果在拷贝对象中释放了这块内存,那么原始对象会成为一个悬空指针,可能导致程序崩溃或者出现未定义的行为。

5. 深拷贝

#include <iostream>
#include <string>

using namespace std;

class stu{
public:
    string * name = nullptr;
    int age;

    stu(){
        cout << "无参构造" <<endl;
    }

    stu(string name , int age ) : name(new string(name)) , age (age){
        cout << "有参构造" <<endl;
    }

    stu(stu & s){
        cout << "拷贝构造" <<endl;
        //name = s.name;
        name = new string (*s.name);
        age = s.age ;
    }

    ~stu(){
        cout << "析构函数" <<endl;
    }
};


int main() {

    stu s1("叶凡" ,24);
    cout << "s1: " <<s1.name  << " " << *s1.name << " " << s1.age <<endl;

    stu s2 = s1;
    cout << "s2: " <<s2.name << " " << *s1.name<< " " << s2.age <<endl;

    *s2.name = "叶黑";

    cout << "s1: " <<s1.name << " " << *s1.name<< " " << s1.age <<endl;
    cout << "s2: " <<s2.name << " " << *s2.name<< " " << s2.age <<endl;

    return 0;
}

运行结果:

有参构造
s1: 000001F37461E410 叶凡 24
拷贝构造
s2: 000001F3746235C0 叶凡 24
s1: 000001F37461E410 叶凡 24
s2: 000001F3746235C0 叶黑 24
析构函数
析构函数

图标说明如下:
在这里插入图片描述

深拷贝也是执行拷贝,只是在面对对象含有动态成员时,会执行新内存的开辟,仅仅是拷贝数据,而两个对象的指针成员有各自的空间。

6. 拷贝出现的场景

6.1 对象的创建依赖于其他对象

当使用一个对象初始化另一个对象时,拷贝构造函数将被调用来创建新对象的副本。

MyClass obj1;
MyClass obj2 = obj1; // 拷贝构造函数被调用来创建 obj2

6.2 函数参数(传递对象)

如果一个对象作为参数传递给一个函数,那么拷贝构造函数将被调用来创建一个新的对象,该对象是原始对象的副本。例如:

void func(MyClass obj) {
  // ...
}

MyClass obj1;
func(obj1); // 拷贝构造函数被调用来创建 obj2

6.3 函数返回值 (返回对象)

如果一个函数返回一个对象,那么拷贝构造函数将被调用来创建返回值的副本。例如:

MyClass func() {
  MyClass obj;
  // ...
  return obj; // 拷贝构造函数被调用来创建返回值的副本
}

只要存在了类型 对象 = 已有对象 ----> 就一定会执行拷贝构造函数。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一种新的基于区域的在线活动轮廓模型研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

SpringBoot热部署的开启与关闭

1、 开启热部署 &#xff08;1&#xff09;导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId> </dependency>&#xff08;2&#xff09;设置 此时就搞定了。。。 2、…

TCP网络通信编程之网络上传文件

【图片】 【思路解析】 【客户端代码】 import java.io.*; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException;/*** ProjectName: Study* FileName: TCPFileUploadClient* author:HWJ* Data: 2023/7/29 18:44*/ public class TCPFil…

解决在云服务器开放端口号以后telnet还是无法连接的问题

这里用阿里云服务器举例&#xff0c;在安全组开放了对应的TCP端口以后。使用windows的cmd下的telnet命令&#xff0c;还是无法正常连接。 telnet IP地址 端口号解决方法1&#xff1a; 在轻量服务器控制台的防火墙规则中添加放行端口。 阿里云-管理防火墙 如图&#xff0c;开放…

Windows 11 下 OpenFace 2.2.0 的安装

写在前面 最近需要做关于面部的东西&#xff0c;所以需要使用到OpenFace这个工具&#xff0c;本文仅用来记录本人安装过程以供后续复现&#xff0c;如果可以帮助到读者也是非常荣幸。 安装过程 不编译直接使用 这种方法可以直接从官方下载下来编译好的exe以及gui进行使用&a…

1000Wqps生产级IM,怎么架构?

前言 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;很多小伙伴拿高薪&#xff0c;完成架构的升级&#xff0c;进入架构师赛道&#xff0c;打开薪酬天花板。 然后&#xff0c;在架构师的面试过程中&#xff0c;常常会遇到IM架构的问题&#xff1a; 如果要你从0到1做IM架构…

python与深度学习(十):CNN和cifar10二

目录 1. 说明2. cifar10的CNN模型测试2.1 导入相关库2.2 加载数据和模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章训练的模型进行测试。首…

Flutter 使用texture_rgba_renderer实现桌面端渲染视频

Flutter视频渲染系列 第一章 Android使用Texture渲染视频 第二章 Windows使用Texture渲染视频 第三章 Linux使用Texture渲染视频 第四章 全平台FFICustomPainter渲染视频 第五章 Windows使用Native窗口渲染视频 第六章 桌面端使用texture_rgba_renderer渲染视频&#xff08;本…

MySQL高级篇第3章(用户与权限管理)

文章目录 1、用户管理1.1 登录MySQL服务器1.2 创建用户1.3 修改用户1.4 删除用户1.5 设置当前用户密码1.6 修改其他用户密码1.7 MySQL8密码管理 2、权限管理2.1 全新列表2.2 授予权限的原则2.3 授予权限2.4 查看权限2.5 收回权限 3、权限表3.1 user表3.2 db表3.3 tables_priv表…

ssti总结转载

一、初识SSTI 1、什么是SSTI&#xff1f; SSTI就是服务器端模板注入(Server-Side Template Injection)&#xff0c;实际上也是一种注入漏洞。 可能SSTI对大家而言不是很熟悉&#xff0c;但是相信大家很熟悉SQL注入。实际上这两者的思路都是相同的&#xff0c;因此可以类比来分…

【嵌入式Linux系统开发】——系统移植概述

目录 &#x1f349;&#x1f349;一、什么是嵌入式系统 &#x1f349;&#x1f349;二、嵌入式系统操作 &#x1f349;&#x1f349;三、嵌入式Linux的特点 &#x1f349;&#x1f349;四、嵌入式系统的组成 1、硬件和软件 2、硬件层 3、中间层 4、软件层 5、 功能层与执…

手动创建一张“资产负债表”和“利润表”

1. 前言 了解了“复式记账法”&#xff0c;以及“增值税”等概念后&#xff0c;让我们通过一个简化的例子&#xff0c;来手动创建一张资产负债表和利润表&#xff0c;进而加深对于记账和这两种报表的理解。 2. 手动创建财务报表 2.1 期初余额 假设某公司的2022年度期初余额…

找不到vcruntime140.dll无法继续执行代码怎么办?(详解)

1.vcruntime140.dll是什么&#xff1f;有什么作用&#xff1f; vcruntime140.dll是Windows操作系统中的一个动态链接库文件&#xff0c;它属于Microsoft Visual C Redistributable的一部分。DLL是Dynamic Link Library的缩写&#xff0c;它包含了一系列函数和资源&#xff0c;…

C计数问题---2023河南萌新联赛第(三)场:郑州大学

解析&#xff1a; n 可以分成两个数&#xff0c;记录每个数的因子对数&#xff0c;乘起来即可。 注意当因子相同时&#xff0c;只1 #include<bits/stdc.h> using namespace std; int n,res; int main(){cin>>n;for(int i1;i<n;i){int xi,yn-i;int cnt10,cnt20;…

【周末闲谈】剑指offer,了解面试,学会面试

我们在找工作时&#xff0c;需要结合自己的现状&#xff0c;针对意向企业做好充分准备。作为程序员&#xff0c;你有哪些面试IT技术岗的技巧&#xff1f; 你可以从一下几个方向谈谈你的想法和观点。 个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️…

DHCP中继代理原理(第二十八课)

当客户机和DHCP服务器不在一个广播域时,DHCP服务器无法接收到客户机的DHCP discover广播数据包,客户机就无法获得IP地址 第一步配置DHCP服务器的信息 <Huawei>u t m //清除日志 Info: Current terminal monitor is off. <Huawei>sys [Huawei]sysname DHCP-R…

RBAC三级菜单实现(从前端到后端)未完待续

1、菜单设计 2、前端路由 根据不同的用户id显示不同的菜单 一个是找 一个是路由 3、多级菜单 展示所有权限&#xff0c;并且根据当前用户id展示它所属的角色的所有菜单。 前端树状展示 太牛逼了&#xff01; 思路&#xff1a; 后端&#xff1a;传给前端map&#xff0…

Android AIDL 使用

工程目录图 请点击下面工程名称&#xff0c;跳转到代码的仓库页面&#xff0c;将工程 下载下来 Demo Code 里有详细的注释 代码&#xff1a;LearnAIDL代码&#xff1a;AIDLClient. 参考文献 安卓开发学习之AIDL的使用android进阶-AIDL的基本使用Android AIDL 使用使用 AIDL …

Matlab Image Processing toolbox 下载安装方法

当安装好Matlab之后&#xff0c;发现没有Image Processing toolbox这个图像处理工具箱 从新安装一遍&#xff0c; 选上 Image Processing toolbox 但是不用选matlab即可 1.找到之前安装时的Setup安装程序包&#xff0c;按照之前安装Matlab步骤&#xff0c;到选择需要安装的Ma…

基于FasterRCNN深度学习网络的车辆检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022A 3.部分核心程序 ....................................................................... % 训练Faster R-…