C++复制构造函数

 什么是复制构造函数:

复制构造函数是一种特殊的构造函数,顾名思义就是用于复制一个对象。主要出现在以下3种情况:
(1)对象以值传递的形式作为函数参数。
(2)对象以值传递的形式作为函数返回值。
(2)用一个对象实例初始化一个新建对象。
复制构造函数的参数列表必须包含一个该类对象的引用而且可以包含有默认值的其他参数如:
现有类
class test{
public:
	test(){}//构造函数
	test(test& x){} //复制构造函数
	test(const test& x){} //复制构造函数
	test(const test& x , int i = 0 , int j =1){} //复制构造函数,除了对象引用之外还有其他含有默认值参数,这样的构造函数也是复制构造函数
	test(const test& x , int i , int j){} //不是复制构造函数
private:
	int i;
	int j;
};

对象以值传递的形式作为函数参数:

#include <iostream>
using namespace std;
class test{
public:
	test(){}//构造函数
	test(test& x){ cout<<"复制构造函数执行"<<endl; } //复制构造函数
private:
	int i;
	int j;
};

void fun(test a){  //函数参数为以值传递形式的test对象
}

void main(){
	test a;
	fun(a);
}



对象以值传递的形式作为函数的返回值:

#include <iostream>
using namespace std;
class test{
public:
	test(){}//构造函数
	test(test& x){ cout<<"复制构造函数执行"<<endl; } //复制构造函数
private:
	int i;
	int j;
};

test fun(){  //函数参数为以值传递形式的test对象
	test a;
	return a;
}

void main(){
	fun();
}



用于对象的初始化:

#include <iostream>
using namespace std;
class test{
public:
	test(){}//构造函数
	test(test& x){ cout<<"复制构造函数执行"<<endl; } //复制构造函数
private:
	int i;
	int j;
};


void main(){
	test a;
	test b(a);  // b(a)与 test b = a等效
	test c = a;
}

什么时候需要自定义复制构造函数?

当类的成员变量包含指针或静态变量时需要考虑自定义复制构造函数,要知道如果不自定义复制构造函数,编译器会提供一个默认的复制构造函数,以上面的test类为例,编译器会自动提供形式为test(test & x);或者test(const test & x);这种形式的复制构造函数,功能是简单的成员变量赋值操作:
test(test &x){
   this.i = x.i;
   this.j = x.j;
}

如果成员变量为指针或静态变量时,也仅仅是简单的赋值操作,这是很危险的。以成员指针为例:
#include <iostream>
using namespace std;
class test{
public:
	test(){int *a = new int(1); p = a;}  //构造函数
	~test(){delete p;} //析构函数
private:
	int *p;
};


void main(){
	test a;
	test b(a);  /*调用默认的复制构造函数函数使得a和b中的成员指针p都指向同一块堆空间
				  在程序结束后会先析构b对象释放b中p所指向的堆空间,接着析构a对象释放a中p
				  所指向的堆空间,然而a和b指向的是同一块堆空间,造成了二次释放,所以程序
				  运行会出现错误
				  */
}




当成员变量包含静态变量时,也要注意自定义复制构造函数
#include <iostream>
using namespace std;
class test{
public:
	test(){i++;}  
	static int i; //统计创建的对象数,每创建一个对象i就加1
};

int test::i = 0;
void main(){
	test a;
	test b;
	cout<<b.i<<endl; //已经创建了2个对象,i的值应该为2
	test c = a; //调用默认的复制构造函数
	cout<<c.i<<endl; //创建了3个对象,i的值按道理应该为3,但实际却为2
}
创建C对象时,调用了默认的复制构造函数而没有调用构造函数,所以没有实现静态变量的变化,完成的仅仅是变量的赋值操作,因而创建3个对象后,i的值仍然为2.

赋值运算与复制构造函数的区别:

#include <iostream>
using namespace std;
class test{
public:
	test(){ cout<<"构造函数执行"<<endl;}//构造函数
	test(test& x){ cout<<"复制构造函数执行"<<endl; } //复制构造函数
private:
	int i;
	int j;
};

void main(){
	test a,c;  //创建了2个对象
	test b = a; //调用复制构造函数
	a = c; //没有调用复制构造函数,但完成了成员变量的赋值操作
}

运行后构造函数执行了2次,复制构造函数执行了1次。可见a=c这种赋值操作,并没有调用复制构造函数。

对象之间的赋值运算是指两个已经实例化的对象之间的一种运算,默认完成成员变量之间的赋值操作与默认的复制构造函数的功能相似,但并没有创建新的对象。而复制构造函数是为了创建并初始化一个对象,这是两者根本的区别。如果成员变量包含指针或静态变量,要对赋值操作符进行重载,具体原因上面已经介绍过。

转载于:https://www.cnblogs.com/xiaogua918/p/4181584.html

### C++ 复制构造函数 使用详解 #### 什么是复制构造函数复制构造函数是一种特殊的构造函数,用于通过已存在的对象初始化一个新的对象。它通常在以下情况下被调用: - 当一个对象以值传递方式传入函数时; - 当一个对象以值返回方式从函数返回时; - 当创建一个对象并将其初始化为另一个同类型的对象时。 如果没有显式定义复制构造函数,编译器会自动生成一个默认的复制构造函数[^4]。然而,默认的复制构造函数仅执行浅拷贝操作,即简单地将源对象的数据成员逐个赋值给目标对象的数据成员。这可能导致某些问题,特别是在涉及动态内存管理的情况下[^2]。 --- #### 浅拷贝与深拷贝的区别 ##### 浅拷贝 浅拷贝是指仅仅复制指针或其他资源的地址,而不是实际的内容。这意味着两个对象可能会共享同一块动态分配的内存区域。这种行为可能导致未定义的行为,尤其是在析构函数释放内存时发生双重删除的情况[^5]。 ##### 深拷贝 深拷贝则是完全独立地复制整个对象及其所拥有的资源。这样可以确保每个对象都有自己的数据副本,从而避免潜在的风险。 --- #### 自定义复制构造函数的实现方法 为了防止浅拷贝带来的问题,在设计类时应考虑是否需要提供自定义的复制构造函数来完成深拷贝。以下是具体实现的一个示例: ```cpp #include <iostream> using namespace std; class MyClass { public: int* data; // 构造函数 MyClass(int value) : data(new int(value)) {} // 复制构造函数 (深拷贝) MyClass(const MyClass& other) { data = new int(*other.data); cout << "Deep copy performed!" << endl; } // 析构函数 ~MyClass() { delete data; } void display() const { cout << "Value: " << *data << endl; } }; int main() { MyClass obj1(10); MyClass obj2(obj1); // 调用了复制构造函数 obj1.display(); obj2.display(); return 0; } ``` 在这个例子中,`MyClass` 的复制构造函数实现了深拷贝逻辑,确保 `obj1` 和 `obj2` 各自有其独立的动态分配整型变量。 --- #### 编译器生成的默认复制构造函数的特点 如果用户没有定义任何特殊形式的构造函数(如复制构造函数或移动构造函数),则编译器会自动合成一个默认版本。此默认版本会对所有非静态成员逐一进行位级复制。需要注意的是,一旦开发者提供了自定义的复制构造函数,编译器就不会再生成默认版本[^3]。 --- #### 示例分析:解决浅拷贝引发的问题 以下是一个典型的因浅拷贝而导致崩溃的例子以及如何修复它的解决方案: ```cpp // 原始代码存在浅拷贝问题 class StringWrapper { private: char* buffer; public: StringWrapper(const char* str) { size_t length = strlen(str); buffer = new char[length + 1]; strcpy(buffer, str); } ~StringWrapper() { delete[] buffer; } // 添加自定义复制构造函数以支持深拷贝 StringWrapper(const StringWrapper& other) { size_t length = strlen(other.buffer); buffer = new char[length + 1]; strcpy(buffer, other.buffer); } void printBuffer() const { cout << buffer << endl; } }; void testCopyConstructor() { StringWrapper original("Hello"); StringWrapper copied(original); original.printBuffer(); // 输出 Hello copied.printBuffer(); // 输出 Hello } int main() { testCopyConstructor(); return 0; } ``` 在此修正后的程序里,新增加了一个复制构造函数用来处理字符串缓冲区的深层复制过程,有效规避了原始方案中的隐患[^5]。 --- #### 总结 C++ 中的复制构造函数是非常重要的概念之一,尤其当涉及到复杂数据结构或者外部资源管理时更是如此。合理运用它可以保障程序的安全性和稳定性;反之,则容易造成难以追踪的错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值