2020-07-13

拷贝构造函数是一种特殊的构造函数,在创建对象时,它是使用同一类中之前创建过的对象来初始化新创建的对象。如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数,缺省的拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型成员变量,调用其相应类型的拷贝构造函数。

我们在编写程序的过程中,如果不主动编写拷贝构造函数和赋值函数,编译器将会调用默认的函数,如果类中含有指针变量,那么如果使用的默认的函数就会有错误,下面首先我们先进行简单的介绍,之后再用具体的例子来加以说明。

1.拷贝构造函数和赋值函数

拷贝构造函数,顾名思义,它是一个构造函数,所以它是在对象创建的时候被主动调用的函数,可以将
另外一个对象的变量拷贝给当前对象。赋值函数,是在对象已经存在的情况下才会进行调用。
#include <iostream>
#include <set>
using namespace std;class Test {public:Test() { // 默认构造函数cout << "Test()" << endl;};Test(int v) :value(v) { // 带参数的构造函数cout << "Test(int v)" << endl;}Test(const Test& obj){ //拷贝构造函数cout << "Test(const Test& obj)" << endl;}Test& operator=(const Test& obj){cout << "Test& operator=(const Test& obj)" << endl;return *this;}~Test() { // 析构函数}private:int value;
};int main() {Test a(1);Test c = a;Test d;d = a;getchar();return 0;
}


(1)拷贝构造函数和赋值函数

Test c = a;
d = a;

这里第一个"=“时对象c还没有存在,所以这里调用的是拷贝构造函数,第二个”="时对象d已经存在了,所以调用的是赋值函数

(2)拷贝构造函数
拷贝构造函数是其它构造函数的重载函数,它的参数是const对象的引用,const比较容易理解,我们将一个对象拷贝给另外一个对象,那该对象的值我们是不希望被改变了的,另外一个原因是,添加 const 限制后,就可以将 const 对象和非 const 对象传递给形参了,因为非 const 类型可以转换为 const 类型,如果没有 const 限制,就不能将 const 对象传递给形参,因为 const 类型不能转换为非 const 类型,这就意味着,不能使用 const 对象来初始化当前对象了;那么这里我们为什么选择传递对象的引用作为函数的参数呢?一个原因是引用传参的时候,形参是实参的一个别名,也就是说它们俩其实是相同的,但是如果我们不传递引用的话,在进入函数的时候,会另外分配一块存储空间给形参使用,形参将会初始化实参的值,在函数调用结束的时候,这块存储空间将会被释放掉,如果说对象比较大的话,在这个初始化的过程中将会比较的耗时;还有一个十分重要的原因是我们在调用拷贝构造函数的时候,如果传递的是对象的话,由于要将实参的值赋给形参,将会调用拷贝构造函数进行赋值,那么就会形成一个死循环,如果您将上述拷贝构造函数中的"&"删除掉,程序将会报错。

(3)赋值函数
赋值函数用到的是运算符的重载,它的返回值是对象的引用,参数是const对象的引用。对于返回值而言,我们希望保留运算符原有的特性,考虑到a=b=c,这个赋值语句的顺序应该是a=(b=c),所以赋值函数重载函数的返回值应该是类的对象,返回对象的引用是因为如果返回对象的话,将会把原先对象的值赋值给临时的对象,这样还会调用一次拷贝构造函数。赋值函数的参数是对象的引用,一个原因是节省时间,另外一个原因是使函数可以传递const的对象。

#include <iostream>
using namespace std;class Test {public:Test() { // 默认构造函数cout << "Test()" << endl;};Test(int v) :value(v) { // 带参数的构造函数cout << "Test(int v)" << endl;}Test(const Test& obj){ //拷贝构造函数cout << "Test(const Test& obj)" << endl;}Test operator=(const Test& obj){cout << "Test& operator=(const Test& obj)" << endl;return *this;}~Test() { // 析构函数}private:int value;
};int main() {Test a(1);Test c = a;Test d;d = c = a;getchar();return 0;
}


由于赋值函数的返回值是对象,这里在函数返回时就调用了拷贝构造函数。

2.何时调用拷贝构造函数

(1)定义一个对象时,以本类另一个对象作为初始值,发生拷贝构造。
(2)如果函数的形参是类的对象,调用函数时,将使用实参初始化形参,发生拷贝构造。
(3)如果函数的返回值是类的对象,函数执行完成返回主调函数时,将使用return语句中的对象初始化
一个临时的无名对象,传递给主调函数,发生拷贝构造。

3.浅拷贝和深拷贝

浅拷贝:如果用默认的拷贝构造函数(赋值函数)去赋值有指针类型的成员变量的对象,将会使两个对象
的指针地址也是一样的,也就是说这两个对象的指针成员变量指向的是相同的地址。
深拷贝:每个对象拥有自己的资源,此时需要显示提供拷贝构造函数和赋值函数。


如果调用了默认的拷贝构造函数(赋值函数),在拷贝过程中是按字节复制的,对于指针型成员变量只复制指针本身,而不复制指针所指向的目标,这将会使同一指针指向相同的区域,同时也会导致同一块资源被释放多次,从而造成错误。
下面的例子是显示定义的赋值函数。

#include <iostream>
#include <string.h>
using namespace std;class Test {public:Test():ptr(new char[1]) { // 带参数的构造函数cout << "Test():ptr(new char[1])" << endl;}Test operator=(const Test& obj){if (this == &obj) { // s=sreturn *this;}delete[] ptr;ptr = new char[strlen(obj.ptr) + 1];strcpy(ptr, obj.ptr);cout << "Test& operator=(const Test& obj)" << endl;return *this;}Test& operator=(const char *s){delete[] ptr;ptr = new char[strlen(s) + 1];strcpy(ptr, s);cout << "Test& operator=(const Test& obj)" << endl;return *this;}~Test() { // 析构函数delete[] ptr;}
private:char* ptr;
};int main() {Test a;a= "test";Test b;b= a;Test d;getchar();return 0;
}

C++中的深拷贝和浅拷贝(详解)相关推荐

  1. python深复制与浅复制_Python中的深拷贝和浅拷贝详解

    要说清楚Python中的深浅拷贝,需要搞清楚下面一系列概念: 变量-引用-对象(可变对象,不可变对象)-切片-拷贝(浅拷贝,深拷贝) [变量-对象-引用] 在Python中一切都是对象,比如说:3, ...

  2. python中深拷贝和浅拷贝_**Python中的深拷贝和浅拷贝详解

    甚至连type其本身都是对象,type对象 Python中变量与C/C++/Java中不同,它是指对象的引用,Python是动态类型,程序运行时候,会根据对象的类型 来确认变量到底是什么类型. 单独赋 ...

  3. python深拷贝一个对象_Python对象的深拷贝和浅拷贝详解

    本文内容是在<Python核心编程2>上看到的,感觉很有用便写出来,给大家参考参考! 浅拷贝 首先我们使用两种方式来拷贝对象,一种是切片,另外一种是工厂方法.然后使用id函数来看看它们的标 ...

  4. iOS开发——深拷贝与浅拷贝详解

    深拷贝和浅拷贝这个问题在面试中常常被问到,而在实际开发中,只要稍有不慎,就会在这里出现问题.尤其对于初学者来说,我们有必要来好好研究下这个概念.我会以实际代码来演示,相关示例代码上传至 这里 . 首先 ...

  5. c++拷贝构造函数(深拷贝,浅拷贝)详解

    一.什么是拷贝构造函数       首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=100; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成 ...

  6. 【Java深入】深拷贝与浅拷贝详解

    1.拷贝的引入 (1)引用拷贝 创建一个指向对象的引用变量的拷贝. 例1: Teacher teacher = new Teacher("Taylor",26); Teacher ...

  7. 基础面试题:深拷贝和浅拷贝详解以及实例

    深拷贝 vs 浅拷贝 浅拷贝 概念 复制基本类型的属性:引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针,不复制堆内存中的对象. 如图: ​ 特点 ​ 1.对于基本数据类型的成员对 ...

  8. python的sort方法是哪种_python中的sort方法使用详解

    Python中的sort()方法用于数组排序,本文以实例形式对此加以详细说明: 一.基本形式列表有自己的sort方法,其对列表进行原址排序,既然是原址排序,那显然元组不可能拥有这种方法,因为元组是不可 ...

  9. js 浅拷贝直接赋值_JS中实现浅拷贝和深拷贝的代码详解

    (一)JS中基本类型和引用类型 JavaScript的变量中包含两种类型的值:基本类型值 和 引用类型值,在内存中的表现形式在于:前者是存储在栈中的一些简单的数据段,后者则是保存在堆内存中的一个对象. ...

  10. python中关于深拷贝和浅拷贝的详解

    python中关于深拷贝和浅拷贝的详解 概述 在python的语法中,有两种变量的拷贝方式 一种是深拷贝,一种是浅拷贝 我们先说深拷贝 语法 这里需要通过导入系统的copy模块中的deepcopy才可 ...

最新文章

  1. c语言c++语言中静态变量,函数详解
  2. C语言过河问题主函数,c,c++_C语言踩石头过河问题,用DFS搜索递归了17万次但是没报错,请问是什么原因?,c,c++,算法 - phpStudy...
  3. C#中的DateTime:本周,本月,今年,本周
  4. python模块中的__all__属性
  5. spark集群详细搭建过程及遇到的问题解决(四)
  6. centos7安装java6_CentOS7.6安装jdk1.8
  7. 前端开发 跨平台的构架GSOAP
  8. Docker 的出现
  9. 关于Exchange Server 2010(WEB浏览证书)证书问题
  10. pycharm中的常用快捷键与常用设置
  11. 【优化算法】蜜獾优化算法(HBA)【含Matlab源码 1437期】
  12. 基于node.js和Vue的音乐管理系统 /音乐网站的设计与实现
  13. AutoCAD自动标注坐标和坐标输出宏
  14. 计算机二级c语言选择题资料,计算机二级C语言重点选择题笔试复习资料
  15. intel无线网络管理服务器,配置Intel无线网卡连接到管理帧保护(MFP) -启用网络
  16. 植物大战僵尸存档任务C1-01
  17. 使用 patchrom 移植 MIUI
  18. 机器学习两种参数估计方法:最大似然估计和最小二乘法估计
  19. i3 7100黑苹果_苹果连发三款新品,售价更低!性能更强!| 数码
  20. 基于30多万条招聘信息的热门城市、地域 、薪资、人才要求的R语言数据可视化分析

热门文章

  1. 学生PHP校园超市网站制作 学生PHP网页毕设源码 学生动态数据库网站作品 PHP电子商务商城购物网站
  2. 苹果发布 macOS 12——Monterey
  3. 极光推送 java api_JPush极光推送Java服务器端API
  4. 1.5 编程基础之循环控制 35 求出e的值
  5. STM32H743+CubeMX-使用ADC(16bit分辨率)模数转换器读取CPU的温度(串行方式)
  6. python中left是什么意思_Python left
  7. 下列哪个不是python元组的定义方式_Python基础知识笔试
  8. Java笔记-使用CXF开发WebService服务器
  9. Qt工作笔记-使用QGraphicsItem绘制复杂的图形
  10. 认识死锁之死锁的基本概念