C++重新认知:拷贝构造函数

本文详细解释了拷贝构造函数的作用,浅拷贝和深拷贝的区别,以及何时会自动调用拷贝构造函数。重点强调了避免无效拷贝以提高效率的重要性。
摘要由CSDN通过智能技术生成

一、什么是拷贝构造函数

对于简单变量来说,可以轻松完成拷贝。

int a = 10;
int b = a;

但是对于复杂的类对象来说,不仅存在变量成员,也存在各种函数等。因此相同类型的类对象是通过拷贝构造函数来完成复制过程的。

#include<iostream>

using namespace std;

class String
{
private:
    char* m_buffer;
	unsigned int m_size;
public:
	String(const char* string)
	{
		m_size = strlen(string);
		m_buffer = new char[m_size + 1];
		memcpy(m_buffer, string, m_size);
		m_buffer[m_size] = 0;
	}
	~String()
	{
		delete[] m_buffer;
	}
	friend ostream& operator <<(ostream& stream, const String& string);
};
ostream& operator <<(ostream& stream,const String& string)
{
	stream << string.m_buffer;
	return stream;
}
int main()
{
	String a = "A";
	String b = a;//这里执行拷贝构造函数
	cout << a << endl;
	cout << b << endl;
	getchar();
	return 0;
}


在这里插入图片描述
可以看到成功拷贝了我们自己设计的String类(这里拷贝指的是默认拷贝构造函数即也是浅拷贝),当然这段代码是存在问题的
在这里插入图片描述
我们可以看到两块指向m_buffer内存地址相同,所以会出现多次析构的情况(即a对象析构完了,将m_buffer释放掉后,因为b对象指向的也是m_buffer区域又要释放一次已经释放掉的),这也是浅拷贝,下面会详细讲解浅拷贝和深拷贝。

二、拷贝构造函数的格式

拷贝构造函数的格式

类名(const 变量类型& other)
{
.......
}

要注意变量一定是本类型的可引用变量

三、拷贝构造函数的调用时机

1. 对象以值传递的方式传入函数参数

在这里插入图片描述

2.对象以值传递的方式从函数返回

在这里插入图片描述

3.对象需要通过另一个对象进行初始化

Test a(0,1);
Test b(a);
Test c = a;

四、浅拷贝和深拷贝

1.浅拷贝(上面样例中有涉及到这里就不在详细讲)

2.深拷贝

为了解决浅拷贝导致拷贝的对象指向内存与原被拷贝对象一致,导致析构两次的问题,我们需要手动提供另一种拷贝构造函数的方式————深拷贝。

#include<iostream>

using namespace std;

class String
{
private:
    char* m_buffer;
	unsigned int m_size;
public:
	String(const char* string)
	{
		m_size = strlen(string);
		m_buffer = new char[m_size + 1];
		memcpy(m_buffer, string, m_size + 1);
		m_buffer[m_size] = 0;
	}

	String(const String& other)
		:m_size(other.m_size)
	{
		m_buffer = new char[m_size + 1];
		memcpy(m_buffer, other.m_buffer, m_size + 1);
	}

	~String()
	{
		delete[] m_buffer;//防止内存泄露
	}
	char& operator[](unsigned int index)
	{
		return m_buffer[index];
	}
	friend ostream& operator <<(ostream& stream, const String& string);
};
ostream& operator <<(ostream& stream,const String& string)
{
	stream << string.m_buffer;
	return stream;
}
int main()
{
	String a = "A";
	String b = a;//这里执行拷贝构造函数
	b[0] = 'B';
	cout << a << endl;
	cout << b << endl;
	getchar();
	return 0;
}

深拷贝函数代码

String(const String& other)
		:m_size(other.m_size)
	{
		m_buffer = new char[m_size + 1];
		memcpy(m_buffer, other.m_buffer, m_size + 1);
	}

在这里插入图片描述
在这里插入图片描述
可以看到两个对象的m_buffer地址不再一样。即拷贝的对象又重新分配了一份自己的m_buffer地址。

但是当我们比如有一些函数,我们本来就不需要让他拷贝(例如输出之类的函数),因为拷贝他们没有任何意义。
这里举一个例子:
在这里插入图片描述
在这里插入图片描述
这里执行后的结果:

在这里插入图片描述
可以看到,跟我们上面二中对象以值传递的方式传入函数参数说的一样它会调用拷贝函数,但是这是非常没有效率的,因为我们仅仅只是希望它输出,而非拷贝一份在输出,这样是没有任何意义的。
我们该如何做呢?很简单
我们只需要传引用(&)就可以
在这里插入图片描述
在这里插入图片描述
这样就可以防止无效拷贝导致效率降低的问题了。

重要:总是通过const引用去传递对象来减少无效的拷贝来增加效率

以上就是拷贝构造函数的所有内容了如果读者觉得本文章对你有收益,还请关注,点赞!

  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rain_ZZX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值