复制构造函数总结

本文详细介绍了复制构造函数的使用场景,包括对象初始化、参数传递、返回值、容器元素初始化及数组元素初始化等,并讨论了复制构造函数的行为以及如何禁止复制。

转载:http://blog.youkuaiyun.com/mishifangxiangdefeng/article/details/7195369



1.用同一类型的对象来初始化另一对象需要调用复制构造函数(复制构造函数是形参为const类类型的引用的构造函数)

例1:

[cpp]  view plain copy
  1. class A  
  2. {  
  3. public:  
  4.     A(){}  
  5.     A(const A& a){cout<<"copy"<<endl;}  
  6. };  
  7. int main()  
  8. {  
  9.     A a, c;  
  10.     A b = a;//显式复制构造函数(1)  
  11.     c = a;//赋值函数(2)  
  12.     return 0;  
  13. }  
本例要注意的是(1)和(2)的区别:

复制构造函数也是构造函数的一种。只要是构造函数,就要开辟空间。

(1)在初始化的同时还要完成开辟空间的任务,所以在复制构造函数

(2)在L9已经开辟了空间(变通构造函数),这里只是赋值


2.复制构造函数可用于传参或返回值(仅限于按值传递)

例2:

[cpp]  view plain copy
  1. class A  
  2. {  
  3. public:  
  4.     A(){}  
  5.     A(const A& a){cout<<"copy"<<endl;}  
  6. };  
  7. A Test(A a)  
  8. {  
  9.     return a;  
  10. }  
  11. int main()  
  12. {  
  13.     A a;  
  14.     Test(a);//调用了两次构造函数,一次传参,一次是返回值  
  15.     return 0;  
  16. }  


3.复制构造函数可用于初始化顺序容器中的元素,顺序容包括vector、list、deque

例3:

[cpp]  view plain copy
  1. class A  
  2. {  
  3.     int x;  
  4. public:  
  5.     A(int i):x(i){cout<<"construct "<<i<<endl;}  
  6.     A(const A& a){cout<<"copy"<<endl;}  
  7. };  
  8. int main()  
  9. {  
  10.     list<A> a(10, 5);  
  11.     return 0;  
  12. }  
输出:

construct 5
copy
copy
copy
copy
copy
copy
copy
copy
copy
copy

先构造一个临时对象,再把它依次复制到容器中


4.根据元素初始化列表初始化数组元素时也调用复制构造函数

例:

[cpp]  view plain copy
  1. class A  
  2. {  
  3.     int x;  
  4. public:  
  5.     A(){cout<<"construct "<<endl;}  
  6.     A(int i):x(i){cout<<"construct "<<i<<endl;}  
  7.     A(const A& a){cout<<"copy"<<endl;}  
  8. };  
  9. int main()  
  10. {  
  11.     cout<<"****Test1****"<<endl;  
  12.     A s1[5];  
  13.     cout<<"****Test2****"<<endl;  
  14.     A s2[5] = {1, 2, 3, 4, 5};  
  15.     cout<<"****Test3****"<<endl;  
  16.     A a(1), b(2), c(3), d(4), e(5);  
  17.     A s[5] = {a, b, c, d, e};  
  18.     return 0;  
  19. }  
输出结果:

****Test1****
construct
construct
construct
construct
construct
****Test2****
construct 1
construct 2
construct 3
construct 4
construct 5
****Test3****
construct 1
construct 2
construct 3
construct 4
construct 5
copy
copy
copy
copy
copy

分析结果:

Test1:构造

Test2:构造(隐式类型转换)

Test3:L16是构造L17是复制


5.如果定义了自己的构造函数,系统还是会提供一个默认的复制构造函数

如果定义了自己的复制构造函数,系统不会提供一个默认的构造函数


6.复制构造函数的行为:依次复制每一个非static成员,只是复制内容,称为浅层复制。

如果类中有指针成员,浅层复制会出错。需要定义自己的复制构造函数,使用深层复制。


7.如果要禁止复制,可以复制构造函数声明为私有

如果连友元和成员也要禁止复制,可声明为私有,且只声明不定义。


8.iostream类禁止复制,它的复制构造函数是私有的

### 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++ 中的复制构造函数是非常重要的概念之一,尤其当涉及到复杂数据结构或者外部资源管理时更是如此。合理运用它可以保障程序的安全性和稳定性;反之,则容易造成难以追踪的错误。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值