[c++]构造函数之拷贝构造

本文详细介绍了C++中构造函数的调用规则,包括默认构造函数、有参构造函数和拷贝构造函数。当用户自定义构造函数时,编译器如何提供默认构造函数和拷贝构造函数。同时,讨论了拷贝构造函数的调用时机,如对象初始化、函数参数传递和函数返回值。最后,通过实例讲解了深拷贝和浅拷贝的区别,强调了深拷贝在处理动态内存分配时的重要性,避免了内存重复释放的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 构造函数调用规则

  • 一般情况下,编译器至少给类添加3个成员函数:
    • 默认构造函数(无参,函数体为空)
    • 默认析构函数(无参,函数体为空)
    • 拷贝构造函数, 对属性进行值拷贝
#include <iostream>
using namespace std;

class Object {};

int main()
{
	//正确,调用编译器提供的默认构造函数
	Object obj_1;		
	//错误,No constructor could take the source type, or constructor overload resolution was ambiguous		
	Object obj_2(10);	
	//正确,调用编译器提供的默认拷贝构造函数		
	Object obj_3(obj_1);		

	system("pause");
	return 0;
}
  • 如果用户自定义了有参构造函数,编译器不再提供默认构造函数,但会提供拷贝构造函数。
#include <iostream>
using namespace std;

class Object 
{
public:
	Object(int) {
		cout << "calling the parametric constructor" << endl;
	}
};

int main()
{
	//错误, no appropriate default constructor available
	Object obj_1;					
	//正确, 调用自定义的有参构造函数
	Object obj_2(10);	
	//正确, 调用编译器提供的默认拷贝构造函数		
	Object obj_3(obj_2);		

	system("pause");
	return 0;
}
  • 如果用户自定义了拷贝构造函数,编译器不再提供其他构造函数。
#include <iostream>
using namespace std;

class Object 
{
public:
	Object(const Object& obj) {
		cout << "calling the self-define copy constructor" << endl;
	}
};

int main()
{
	//错误, no appropriate default constructor available
	Object obj_1;		
	//错误, Object::Object(const Object &)': cannot convert argument 1 from 'int' to 'const Object &		
	Object obj_2(10);			

	system("pause");
	return 0;
}

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

  • 使用一个已存在对象初始化一个新对象。
  • 值传递的方式给函数参数传值。
  • 值方式返回函数的局部对象。
#include <iostream>
using namespace std;

class Object
{
public:
	Object() {
		cout << "calling the default constructor" << endl;
	}
	Object(int) {
		cout << "calling the parametric constructor" << endl;
	}
	Object(const Object& obj) {
		cout << "calling the copy constructor" << endl;
	}
	~Object() {
		cout << "calling the destructor" << endl;
	}
};
void test01(Object obj) {
	return;
}
Object test02() {
	Object obj_4;						//calling the default constructor
	return obj_4;
}

int main()
{
	Object obj_1;						//calling the default constructor
	Object obj_2(10);					//calling the parametric constructor

	//使用一个已存在对象初始化一个新对象
	Object obj_3(obj_1);				//calling the copy constructor
	
	//值传递的方式给函数参数传值
	test01(obj_1);						//calling the copy constructor
	
	//值方式返回函数的局部对象
	Object obj_5 = test02();			//calling the copy constructor
	
	system("pause");
	return 0;
}

3. 深拷贝和浅拷贝

  • 浅拷贝:简单的赋值拷贝操作。
  • 浅拷贝带来的问题就是堆区的内存重复释放
  • 以下代码中,obj_1和obj_2中的m_b在内存中共用同一片内存地址,调用析构函数时会重复释放该堆区内存。
#include <iostream>
using namespace std;

class Object 
{
public:
	Object(int a, int b)	//有参构造函数
	{
		m_a = a;
		m_b = new int(b);
	}
	~Object()
	{
		if (m_b != NULL)	//手动释放堆区开辟的内存
		{
			delete m_b;
			m_b = NULL;
		}
	}
private:
	int m_a;
	int* m_b;
};

int main()
{
	Object obj_1(10, 20);				
	Object obj_2(obj_1);			

	system("pause");
	return 0;
}
  • 深拷贝:在堆区重新申请空间,进行拷贝操作。
#include <iostream>
using namespace std;

class Object 
{
public:
	Object(int a, int b)			//有参构造函数
	{
		m_a = a;
		m_b = new int(b);
	}
	Object(const Object& obj)	
	{
		m_a = obj.m_a;
		//m_b = obj.m_b;			//浅拷贝默认的实现方式
		m_b = new int(*obj.m_b);	//深拷贝重新在堆区开辟内存
	}


	~Object()
	{
		if (m_b != NULL)			//手动释放堆区开辟的内存
		{
			delete m_b;
			m_b = NULL;
		}
	}
private:
	int m_a;
	int* m_b;
};

void test()
{
	Object obj_1(10, 20);
	Object obj_2(obj_1);
}
int main()
{
	test();

	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值