0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C++之拷贝构造函数的浅copy及深copy

电子设计 来源:电子设计 作者:电子设计 2020-12-24 15:31 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、深拷贝和浅拷贝构造函数总结:

1、两个特殊的构造函数:

(1)无参构造函数:

没有参数的构造函数

Class Test

public:
Test()

//这是一个无参构造函数

};

当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空;换句话来说,就是我们在类中,不用我们程序猿自己写,编译就自动提供了无参构造函数(只是我们肉眼看不到!)

#include <iostream>
#include <string>
class Test{
//编译器默认给我们提供了一个无参构造函数,只是我们肉眼看不到
};
int main()

Test t;
return 0;

结果输出(编译时能够通过的):

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp#

(2)拷贝构造函数:

参数为const class_name&的构造函数

class Test{
public:
Test(const Test& p)




当类中没有定义拷贝构造函数时,编译器默认提供了一个拷贝构造函数,简单的进行成员变量的值赋值

#include <iostream>
#include <string>
class Test{
private:
int i;
int j;
public:
Test(const Test& p)编译器默认提供这样操作的

i = p.i;
j = p.j;

};
int main()

Test t;
return 0;

输出结果(编译可以通过):

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp#

(3)注意:

在写程序的时候,定义的类对象初始化时看属于哪种类型的:

Test t;//对应无参构造函数
Test t(1);//对应有参构造函数
Test t1;
Test t2=t1;//对应拷贝构造函数

比如下面我定义的类对象属于无参构造函数(当然前提是你手写了其他构造函数,虽然说编译器会默认提供,但是既然要手写,那么三种构造函数就在定义类对象的时候按需求来写),如果只写了有参数构造函数,那么编译器就会报错:

#include <iostream>
#include <string>
class Test{
private:
int i;
int j;
public:
Test(int a)

i = 9;
j=8;

Test(const Test& p)

i = p.i;
j = p.j;

};
int main()

Test t;
return 0;

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:25:9: error: no matching function for call to ‘Test::Test()’
Test t;

test.cpp:25:9: note: candidates are:
test.cpp:15:3: note: Test::Test(const Test&)
Test(const Test& p)

test.cpp:15:3: note: candidate expects 1 argument, 0 provided
test.cpp:10:3: note: Test::Test(int)
Test(int a)

test.cpp:10:3: note: candidate expects 1 argument, 0 provided

4、拷贝构造函数的意义:

(1)浅拷贝

拷贝后对象的物理状态相同

(2)深拷贝

拷贝后对象的逻辑状态相同

(3)编译器提供的拷贝构造函数只进行浅拷贝

代码版本一:

#include <stdio.h>
#include <string>
class Test{
private:
int i;
int j;
int *p;
public:
int getI()

return i;

int getJ()

return j;

int *getP()

return p;

Test(int a)

i = 2;
j = 3;
p = new int;
*p = a;

void free()

delete p;

};
int main()

Test t1(3);//Test t1 3;
Test t2 = t1;
printf("t1.i = %d, t1.j = %d, t1.p = %p", t1.getI(), t1.getJ(), t1.getP());
printf("t2.i = %d, t2.j = %d, t2.p = %p", t2.getI(), t2.getJ(), t2.getP());
t1.free();
t2.free();

return 0;

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp# ./a.out
t1.i = 2, t1.j = 3, t1.p = 0x1528010
t2.i = 2, t2.j = 3, t2.p = 0x1528010
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001528010 ***
Aborted (core dumped)

注解:出现了段错误,仔细分析,我们发现这里释放了堆空间两次(因为我们这里没有调用拷贝构造函数,也就是自己去写拷贝构造函数;所以这种情况是浅拷贝,不能释放两次堆空间):

代码版本二(加上拷贝构造函数):

#include <stdio.h>
#include <string>
class Test{
private:
int i;
int j;
int *p;
public:
int getI()

return i;

int getJ()

return j;

int *getP()

return p;

Test(int a)

i = 2;
j = 3;
p = new int;
*p = a;

Test(const Test& t)

i = t.i;
j = t.j;
p = new int;
*p = *t.p;

void free()

delete p;

};
int main()

Test t1(4);
Test t2 = t1;
printf("t1.i = %d, t1.j = %d, t1.p = %p", t1.getI(), t1.getJ(), t1.getP());
printf("t2.i = %d, t2.j = %d, t2.p = %p", t2.getI(), t2.getJ(), t2.getP());
t1.free();
t2.free();
return 0;

输出结果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp# ./a.out
t1.i = 2, t1.j = 3, t1.p = 0xb0a010
t2.i = 2, t2.j = 3, t2.p = 0xb0a030

注解:从打印的p地址空间来看,就知释放的两个对象的堆空间不同,不再是指向同一堆空间了;同时我们发现浅拷贝只是简单数值上的进行赋值而已;深拷贝不只是简单的值赋值,而是从内存的角度来看,是操作不同的内存。

5、什么时候需要进行深拷贝?

(1)对象中有成员指代了系统中的资源

成员指向了动态内存空间

成员打开了外存中的文件

成员使用了系统中的网络端口

注意:一般来说,自定义拷贝构造函数(也就是我们自己手写的),必然需要实现深拷贝!

二、总结:

C++编译器会默认提供构造函数

无参构造函数用于定义对象的默认初始化状态

拷贝构造函数在创建对象时拷贝对象的状态

对象的拷贝有浅拷贝和深拷贝两种方式。

好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。我是txp,下期见!

审核编辑:符乾江
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 可编程逻辑
    +关注

    关注

    7

    文章

    528

    浏览量

    45459
  • C++
    C++
    +关注

    关注

    22

    文章

    2124

    浏览量

    77353
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    C++与lua联合编程

    的出现,在经济上相当于建立了一个高度标准化的“自由贸易区”或“中转仓库”。无论 C++ 想传给 Lua 一个复杂的嵌套表,还是 Lua 想回调 C++ 的一个函数,都不需要直接面对对方混乱的内存布局,而是
    发表于 04-19 16:27

    C++:const 的空间,常量也能占内存?

    ] != BLACK)): return True return False c++语言5g.FsW.dgdfgsg.cnJIWWQc++语言 c++语言5g.I5y.dgdfgsg.cnJIWWQc++
    发表于 04-16 19:19

    keil实现cc++混合编程

    参考touchgfx生成的代码,发现了一个不需要添加--cpp11 参数的解决方法,具体操作如下。 一、创建一个空白的C文件和头文件在头文件中定义c++文件中需要调用的函数,如图所示 二、在
    发表于 01-26 08:58

    内存拷贝函数 memcpy原理及实现

    内存拷贝函数memcpymemcpy是memory copy的缩写,意为内存复制,在写C语言程序的时候,我们常常会用到它。它的函原型如下:void *memcpy(void *dest
    发表于 12-26 08:03

    C语言与C++的区别及联系

    创建源文件时什么都不给,默认是.cpp。 3、返回值 C语言中,如果一个函数没有指定返回值类型,默认返回int类型;C++中,如果一个函数没有返回值则必须指定为void。 4、参
    发表于 12-24 07:23

    CC++之间的联系

    1、语法兼容性: C++完全兼容C语言的语法,这意味着任何有效的C语言程序都可以直接在C++编译器下编译通过。 2、底层控制: C++
    发表于 12-11 06:51

    C语言和C++之间的区别是什么

    区别 1、面向对象编程 (OOP): C语言是一种面向过程的语言,它强调的是通过函数将任务分解为一系列步骤进行执行。 C++C语言的基础上扩展了面向对象的特性,支持类(class)
    发表于 12-11 06:23

    C++程序异常的处理机制

    运行代码进行分离,使得程序更加模块化;另一方面,C++的异常处理可以不需要异常处理在异常发生时的同一个函数,而是可以在更上层合适的位置进行处理。 下面,我们一起来看看C++的异常处理。 2、异常处理
    发表于 12-02 07:12

    C/C++代码静态测试工具Perforce QAC 2025.3的新特性

     Perforce Validate 中 QAC 项目的相对/根路径的支持。C++ 分析也得到了增强,增加了用于检测 C++ 并发问题的新检查,并改进了实体名称和实
    的头像 发表于 10-13 18:11 708次阅读
    <b class='flag-5'>C</b>/<b class='flag-5'>C++</b>代码静态测试工具Perforce QAC 2025.3的新特性

    强实时运动控制内核MotionRT750(六):us级高速交互C++,为智能装备提速

    Windows下运动控制实时内核MotionRT750的高速交互C++
    的头像 发表于 09-04 14:50 902次阅读
    强实时运动控制内核MotionRT750(六):us级高速交互<b class='flag-5'>之</b><b class='flag-5'>C++</b>,为智能装备提速

    技能+1!如何在树莓派上使用C++控制GPIO?

    在使用树莓派时,你会发现Python和Scratch是许多任务(包括GPIO编程)中最常用的编程语言。但你知道吗,你也可以使用C++进行GPIO编程,而且这样做还有不少好处。借助WiringPi
    的头像 发表于 08-06 15:33 4461次阅读
    技能+1!如何在树莓派上使用<b class='flag-5'>C++</b>控制GPIO?

    C语言中的内联函数与宏

    C编程中,内联函数和宏都用于避免函数调用的开销并编写可复用的逻辑部分,但它们在工作方式和安全性方面存在显著差异。
    的头像 发表于 07-25 15:10 2049次阅读
    <b class='flag-5'>C</b>语言中的内联<b class='flag-5'>函数</b>与宏

    基于LockAI视觉识别模块:C++目标检测

    本文档基于瑞芯微RV1106的LockAI凌智视觉识别模块,通过C++语言做的目标检测实验。本文档展示了如何使用lockzhiner_vision_module::PaddleDet类进行目标检测,并通过lockzhiner_vision_module::Visualize函数
    的头像 发表于 06-06 13:56 1002次阅读
    基于LockAI视觉识别模块:<b class='flag-5'>C++</b>目标检测

    飞凌嵌入式ElfBoard ELF 1板卡-uboot编译system.map/uboot.map

    system.map是一个符号表,其中包括符号名、符号类型、符号值。符号(sysmbol):包括已定义的符号(对应全局变量和static变量和定义的函数的名字)和未定义符号(未定义的函数的名字和引用
    发表于 05-22 11:22

    主流的 MCU 开发语言为什么是 C 而不是 C++

    在单片机的地界儿里,C语言稳坐中军帐,C++想分杯羹?难喽。咱电子工程师天天跟那针尖大的内存空间较劲,C++那些花里胡哨的玩意儿,在这儿真玩不转。先说内存这道坎儿。您当stm32f4的256kRAM
    的头像 发表于 05-21 10:33 1190次阅读
    主流的 MCU 开发语言为什么是 <b class='flag-5'>C</b> 而不是 <b class='flag-5'>C++</b>?