【C++基础】——拷贝构造函数的浅拷贝和深拷贝

本文介绍了C++中使用拷贝构造函数进行实例拷贝的过程,特别关注了如何正确地处理包含指针类型成员的类的深拷贝,避免析构函数错误和内存泄漏的问题。

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

C++中用拷贝构造函数来进行实例拷贝时的操作


如下例子,我们在进行实例复制时,发现默认构造方法并没有被重复调用,事实上是调用了拷贝构造函数来进行实例的复制操作。

#include<stdlib.h>
#include<iostream>
#include<string>

using namespace std;

class Apple{
public:
	Apple(string _name){
		m_name=_name;
		cout<<"Apple"<<endl;
	}
	void setColor(string _color){
		m_color=_color;
	}
private:
	string m_name;
	string m_color;
};
int main(void){
	Apple a11("apple1");//复制实例的两种方式
	Apple a22(a11);     //1
	Apple a33=a11;      //2
	system("pause");
	return 0;
}
结果显示如下,构造函数只调用了一次。

Apple
请按任意键继续...


当我们的类中的属性成员有的指针类型时再来看看是如何拷贝指针类型的。

创建一个Array实体类的头文件

//本例用来解释拷贝构造函数的深拷贝和浅拷贝
class Array{
public:
	Array(int _count);
	Array(const Array &array);
	~Array();
	void setCount(int _count);
	int getCount();
	void printAddr();
	void printArr();
private:
	int m_Count;
	int *m_pArr;
};
Array类

#include "Array.h"
#include <iostream>
using namespace std;
Array::Array(int _count){
	m_Count=_count;
	m_pArr=new int[m_Count];
	for(int i=0;i<m_Count;i++){
		m_pArr[i]=i;
	}
	cout<<"Array"<<endl;
}
Array::Array(const Array &array){  //拷贝构造函数,此处对指针类型直接赋了值
	m_Count=array.m_Count;
	m_pArr=array.m_pArr;//就是这里,想想会有什么问题吗?
	
	
	cout<<"Array &"<<endl;
}
Array::~Array(){
	delete []m_pArr;
	m_pArr=NULL;
	cout<<"~Array"<<endl;
}
void Array::setCount(int _count){
	m_Count=_count;
}
int Array::getCount(){
	return m_Count;
}
void Array::printAddr(){
	cout<<"mAddr="<<m_pArr<<endl;
}
void Array::printArr(){
	for(int i=0;i<m_Count;i++){
		cout<<m_pArr[i]<<endl;
	}
};
运行:

#include<stdlib.h>
#include<iostream>
#include<string>

#include "Array.h"
using namespace std;

int main(void){
	Array arr1(5);
	Array arr2(arr1);
	cout<<arr1.getCount()<<endl;
	cout<<arr2.getCount()<<endl;
	arr1.printArr();
	arr2.printArr();
	Apple a1;
	system("pause");
	return 0;
}
运行时并没有出错,点击任意键退出的时候程序报错了,想想上面我们对指针进行的操作,指针直接赋值之后,析构函数在回收内存的时候就会出错,同一个地址回收的两次。

所以,我们要做的是要给指针类型的成员的拷贝构造的时候重新分配内存。

</pre>如下:<pre name="code" class="cpp">Array::Array(const Array &array){
	m_Count=array.m_Count;
	m_pArr=new int[m_Count];
	for(int i=0;i<m_Count;i++){
		m_pArr[i]=array.m_pArr[i];
	}
	
	cout<<"Array &"<<endl;
}







### C++ 中类的拷贝构造函数的作用用法 #### 拷贝构造函数的作用 C++中的拷贝构造函数是一种特殊的构造函数,主要用于通过已存在的对象来初始化新创建的对象。它的主要作用是在以下场景中实现对象的深拷贝浅拷贝[^1]。 当一个类中有动态分配的资源(如指针指向堆内存),仅依赖于编译器生成的默认拷贝构造函数可能导致浅拷贝问题。在这种情况下,两个对象可能共享相同的资源地址,从而引发未定义行为。因此,为了安全地管理这些资源,程序员需要显式定义自己的拷贝构造函数以执行深拷贝操作[^3]。 --- #### 创建并使用拷贝构造函数 以下是关于如何声明、定义以及调用拷贝构造函数的具体方法: ##### 声明拷贝构造函数 拷贝构造函数接受一个常量引用参数作为输入,该参数是一个同类型的对象实例。其基本形式如下所示: ```cpp class MyClass { public: // 构造函数 MyClass(); // 拷贝构造函数 MyClass(const MyClass& other); private: int* ptr; }; ``` ##### 定义拷贝构造函数 在定义过程中,需确保目标对象能够独立拥有源对象的数据副本而非仅仅复制指针本身。下面展示了一个完整的例子,其中包含了动态内存分配的情况: ```cpp MyClass::MyClass(const MyClass& other) : ptr(nullptr) { if (other.ptr != nullptr) { ptr = new int(*other.ptr); } } ``` 上述代码片段展示了如何从`other`对象中复制数据到当前正在构建的新对象上,并且避免了简单的指针赋值所造成的潜在风险[^2]。 ##### 调用拷贝构造函数的情形 - **函数返回值为对象时** - **传递非常量左值引用以外的方式传参给函数时** - **显式的类型转换表达式** 例如,在以下程序段里,当我们把`obj1`赋值给`obj2`的时候实际上触发的就是拷贝构造过程。 ```cpp #include <iostream> class MyClass { public: int x; MyClass(int val): x(val){} // 自定义拷贝构造函数 MyClass(const MyClass& other){ this->x = other.x; std::cout << "Copy Constructor Called!" << std::endl; } }; int main(){ MyClass obj1(10); MyClass obj2 = obj1; // 这里会调用拷贝构造函数 return 0; } ``` --- #### 默认与自定义的区别 如果不提供任何版本的拷贝构造函数,则编译器将会自动合成一个默认版本出来供我们使用。然而这个默认版只会做最基础的事情——逐字段进行位级上的简单复制工作而已。对于那些含有复杂内部结构或者是持有外部资源所有权之类特性的类来说,默认的行为往往不足以满足需求[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值