拷贝构造函数详解及存在的一些问题

C++拷贝构造函数(复制构造函数)详解篇 拷贝和复制是一个意思,对应的英文单词都是copy。对于计算机来说,拷贝是指用一份原有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。 在C++中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对象创建出一个新的对象。从本质上讲,对象也是一份数据,因为它会占用内存。 严格来说,对象的创建包括两个阶段.. 阅读详情

1.概念

拷贝构造函数用于创建一个与当前对象相同的新对象。

拷贝构造函数只有一个参数,形参是对本类类型对象的引用,一般用const修饰。当用一个已存在的对象创建新对象时系统自动调用。

2.特征

1. 拷贝构造函数是构造函数的一个重载形式。

2.1传参导致的无穷递归

1. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,
因为会引发无穷递归调用。

拷贝构造函数写法及使用如下:

#include <iostream>
using namespace std;


class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
    //拷贝构造函数写法    
	// Date(const Date& d) // 正确写法
	Date(const Date d) // 错误写法:编译报错,会引发无穷递归
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2(d1); //此处系统自动调用拷贝构造函数
	return 0;
}


用d1拷贝d2时,d2调用拷贝构造,d1传值给形参date

d1传值给形参date时,date要调动拷贝构造获得d1的值,此时date调用拷贝构造,d1传值给date′

d1传值给date′时,date′又要调动拷贝构造获得d1的值,此时date′调用拷贝构造,d1传值给date′′。

这样就会一直递归下去。

2.2默认拷贝构造函数及浅拷贝

1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按
字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

#include <iostream>
using namespace std;

class Time
{
public:
	Time()
	{
		_hour = 1;
		_minute = 1;
		_second = 1;
	}
	//自定义的浅拷贝
	Time(const Time& t)
	{
		_hour = t._hour;
		_minute = t._minute;
		_second = t._second;
		cout << "Time::Time(const Time&)" << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	// 基本类型(内置类型)
	int _year = 1970;
	int _month = 1;
	int _day = 1;
	// 自定义类型
	Time _t;
};
int main()
{
	Date d1;
	// 用已经存在的d1拷贝构造d2,此处会调用Date类的拷贝构造函数
	// 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构造函数
	Date d2(d1);
	return 0;
}

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定
义类型是调用其拷贝构造函数完成拷贝的。

2.3 深拷贝

1. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?
当然像日期类这样的类是没必要的。但若是涉及到动态开辟空间会造成一些问题,如下。

#include <iostream>
using namespace std;

// 这里会发现下面的程序会崩溃掉?这里就需要深拷贝去解决。
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2(s1);
	return 0;
}

 在类中显示定义深拷贝:

	Stack(const Stack& s)
	{
		_array = (DataType*)malloc(s._capacity * sizeof(DataType));
		_size = s._size;
		_capacity = s._capacity;
		for (int i = 0; i < s._capacity; i++)
		{
			_array[i] = s._array[i];
		}
	}

给新创建的类的_array也开辟相同大小的空间并赋值可以使新类与旧类的_array地址不同,也就不会造成同一对象两次析构了。

注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请
时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

2.4拷贝构造函数典型调用场景

1. 使用已存在对象创建新对象
2. 函数参数类型为类类型对象
3. 函数返回值类型为类类型对象

#include <iostream>
using namespace std;

class Date
{
public:
	Date(int year, int minute, int day)
	{
		cout << "Date(int,int,int):" << this << endl;
	}
	Date(const Date& d)
	{
		cout << "Date(const Date& d):" << this << endl;
	}
	~Date()
	{
		cout << "~Date():" << this << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
Date Test(Date d)
{
	Date temp(d);
	return temp;
}
int main()
{
	Date d1(2022, 1, 13);
	Test(d1);
	return 0;
}

 为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用
尽量使用引用。

如何在软件复位后保留指定RAM区域的数据 本文主要介绍S32K144的RAM retention功能 阅读详情

相关推荐

LaTeX双栏浮动结构实战:用dblfloatfix解决跨栏图表排版难题

本文深入探讨了LaTeX双栏浮动结构在学术论文排版中的常见问题,特别是IEEE会议论文中的跨栏图表定位难题。通过介绍dblfloatfix包的整合解决方案,帮助用户实现精准的底部定位和浮动顺序保持,提升排版效率与质量。

weixin_30872499的博客 442

浅谈拷贝构造函数的类型为什么必须使用引用类型

如果拷贝构造函数中的参数不是一个引用,即形如PersonInfo(const PersonInfo obj),那么就相当于使用了传值调用,而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。 例如在main函数中有PersonInfo b = a;那么就相当于b(a), 然后调用拷贝构造函数,使得b(a)的形参c = a,接着就相当于c(a), 然后再次调用拷贝构造函数,使得c(a)的形参d= a,接着会发生d(a), 这样一直递归下去,造成错误。 因此拷贝构造函数的参数必.

TOP_LUCK的博客 1460

字节跳动已上岸测试工程师的面试经验

这个时候发面经已经有点晚了,所以现在打算让这篇面经主要面向即将秋招的童鞋,当然现在还在春招的童鞋也可以看哈,我和大家一起聊聊关于测试的二三事。   一、测试工程师的工作是什么?   测试工程师简单点说就是找bug,然后反馈给开发人员,不要小看这个工作。   首先很明显的bug开发人员有时候自己就能找到,测试人员要有比开发人员更加全面的想法才能找到深层次的问题点,   其次,要端正一个态度就是测试人员不是一个电脑小白,相反国外顶级的测试开发工程师同时也是顶级的开发工程师甚至更厉害,所以作为一个测试工程师一定要

m0_60745607的博客 2933

【C++从0到王者】第三站:类和对象(中)拷贝构造函数

拷贝构造函数

青色_忘川的博客 637

PHP服务端 苹果支付(IAP)处理

公司做的app需要做IAP订阅支付,开始觉得和微信的支付流程差不多,做起来还是有点麻烦,主要是网上的文章很少,不能拿来主义。自己做完总结一下,希望对小伙伴们有帮助我就很欣慰了。代码写的不好 不要喷我。。。 首先讲一下我的业务逻辑,也就是php服务端需要做什么事情。 先上图: 下面我详细的讲一下每...

山水的博客 1万+

ArduSub程序学习(1)——ardupilot框架整理

AP_HAL层(硬件抽象层)是我们制作 ArduPilot 的方式可移植到许多不同的平台。有一个顶级AP_HAL libraries/AP_HAL,用于定义代码其余部分的接口 有针对具体的板子特性,然后就有了AP_HAL_XXX 子目录,例如,AP_HAL_AVR 用于基于 AVR 的 开发板,AP_HAL_PX4用于 Pixhawk 开发板和 AP_HAL_Linux 基于 Linux 开发板。工具目录tools directories工具目录是杂项支持目录。

weixin_49839886的博客 2812

使用缺省的拷贝构造函数带来的危险性

我此前另外一篇文章通过类String看拷贝构造函数,赋值函数的作用和区别 对于更深的拷贝构造函数讨论大家可以参见这篇帖子 C++类对象的复制-拷贝构造函数 通过编写类String的拷贝构造函数和赋值函数介绍了一些拷贝构造数.本文着重介绍拷贝构造函数的作用和重要性。 首先介绍下拷贝构造函数的使用范围即作用: 1) 一个对象以值传递的方式传入函数体; 2) 一个对象以值传递

RealOnlyme的专栏 2961

荔枝派Lichee Nano全志F1C100s烧录避坑指南:从Fel模式到SPI Flash完整流程

本文详细介绍了荔枝派Lichee Nano基于全志F1C100s芯片的SPI Flash烧录完整流程,从FEL模式进入技巧到定制化sunxi-tools编译,再到分区策略与实战烧录步骤。针对开发者常见的烧录程序问题提供了专业解决方案,帮助用户高效完成嵌入式系统部署。

tea88的博客 788

拷贝构造函数必须写引用吗?

拷贝构造函数必须写引用吗? 是的,因为如果不写成引用,就会有一个很尬尴的情况,就是因为是值传递,所以传进来的参数会被拷贝一次,但这个拷贝,只能使用拷贝构造函数来拷贝,而使用这个,就得又拷贝一次,然后会这样陷入死循环。所以只能用引用。而const倒是无所谓,有const最好。 ...

learner_pu的博客 831

OpenClaw人人养虾:发现与传输

客户端需要先"发现"Gateway 的地址和端口,才能建立连接。OpenClaw 支持多种发现(Discovery)和传输(Transport)机制。

王国平的博客 572

C++编程 拷贝(复制)构造函数 案例详细解析

C++编程 拷贝(复制)构造函数 案例详细解析

m0_56051805的博客 3416

AI自动化时代:一人公司的崛起与商业机会

AI技术正在重塑商业格局,催生"一人公司"创业新模式。这种轻资产、高效率的商业模式通过AI自动化运营,让个人创业者能以极低成本挑战传统企业。核心机会包括:1)AI自主公司替代人力密集型业务;2)为企业提供AI转型解决方案;3)利用AI工具实现个人创业。创业者需快速验证创意,聚焦人机协作,把握当前AI发展窗口期。未来,AI赋能的"一人公司"将成为商业新常态,带来更高的专业化和灵活性。抓住AI红利,学会人机协作,是个人创业成功的关键。

这里汇聚了前沿的技术分享与实用的开发技巧,带你探索从创意到企业的技术创业之路。 518

拷贝构造函数详解

拷贝构造函数详解 拷贝构造函数 int main() { int a; int b = 10; int c(b); return 0 } //结果就是b和c的结果都是10 int main() { int a; int b = 10; int c(b); string s1("hello"); string s2(s1); //用s1去构造s2,然后s1和s2的内容就一模一样了 return 0 } //但是通过监视可以看出,s1和s2的地址是一样的,也就是说s1和

weixin_43831728的博客 8043

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【拷贝构造函数】c++类拷贝构造函数详解

【拷贝构造函数】c++类拷贝构造函数详解 一、什么是拷贝构造函数 也称为复制构造函数。 复制构造函数参数为类对象本身的引用,根据一个已存在的对象复制出一个新的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中。 先来看一个例子: 定义一个Time类,该类有三个公有成员 Hour,Minute,Second。 将该类定义在“Time.h”的头文件里。建一个main.cpp用来放主函数。 “Time.h”: #include<iostream> using namespace

leiyulu的博客 6967

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C++拷贝构造函数详解

在C++中,拷贝构造函数是一种特殊的构造函数,用于创建一个新对象,并将其初始化为现有对象的副本。拷贝构造函数的函数名必须与类名相同,并且参数为该类的一个常引用。拷贝构造函数是一种特殊的构造函数,用于创建对象的副本。他接受一个同类型的对象(本类对象的引用)作为参数,并使用该对象的数据来初始化新对象。拷贝构造函数通常用于在程序中复制对象,以便在不修改原始对象的情况下对其进行操作。拷贝构造函数通常会执行深拷贝操作,即复制指针指向的数据,而不是仅仅复制指针本身。

m0_62573214的博客 4073

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

【C++】拷贝构造函数详解

文章目录一、什么是拷贝构造函数二、拷贝构造函数的调用时机1. 当函数的参数为类的对象时2. 函数的返回值是类的对象3. 对象需要通过另外一个对象进行初始化三、浅拷贝与深拷贝1. 默认拷贝构造函数2. 浅拷贝3. 深拷贝3. 防止默认拷贝发生小结:四、拷贝构造函数的几个细节1.为什么拷贝构造函数必须是引用传递,不能是值传递?2. 拷贝构造函数的作用。3.参数传递过程到底发生了什么?4. 在类中有指针数据成员时,拷贝构造函数的使用?5. 拷贝构造函数里能调用private成员变量吗?6. 以下函数哪个是拷贝构造

Mr_kanger的博客 1121

拷贝构造函数关于指针的拷贝问题

1.拷贝构造函数的定义:如果一个构造函数的第一个参数是自身类型的引用,且任何额外参数都有默认值。 !拷贝构造函数的第一个参数必须是一个引用类型。 合成拷贝构造函数: 如果我们没有为一个类定义拷贝构造函数,编译器会为我们定义一个。编译器从给定对象中,依次将每个非static成员拷贝到正在创建的对象中。 2.拷贝初始化: 拷贝初始化不仅在我们使用=定义变量时会发生,在下列情况

xiepengcheng11的博客 9848

c++拷贝构造函数详解

文章转至:https://www.cnblogs.com/alantu2018/p/8459250.html c++拷贝构造函数详解 一、什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=100; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。 下面看一个类对象拷贝的简单例...

zggzgw的博客 1352

C++ 拷贝构造函数详解

C++ 拷贝构造函数详解 下面的讲解将以C++标准库的string类作为讲解对象,string类:class with pointer member(s) 1、拷贝构造函数和拷贝赋值函数 1.1引入 下面是给出的测试函数,也是我们要能在自己设计的myString类中实现的功能: int main() { myString s1(); //无参数构造函数 myString s2("Hello world!"); //传入字符串的构造函数 myString s3(s1); //

weixin_45745854的博客 4147

详解拷贝构造函数

基本规则 拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量。所以类中可以存在多个拷贝构造函数。 编译器会自动生成默认构造函数,这个构造函数很简单,仅仅使用“老对象”的数据成员的值对“新对象”的数据成员逐个进行赋值,也就是浅拷贝。 默认拷贝构造函数不处理静态变量。如果静态成员变量在构造、析构实例的时候需要修改,那么通常需要手工实现拷贝构造函数和...

yao5hed的专栏 1313
上一篇: NULL与nullptr的区别
下一篇: 赋值运算符重载详解及注意事项
风间琉璃大师
博客等级 码龄4年 123粉丝 30原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值