禁止类的拷贝构造函数和复制构造函数(转)

什么时候需要拷贝构造函数和赋值构造函数?

每个C++类只有一个析构函数,但可以有多个构造函数和多个赋值函数。其中构造函数包括默认构造函数(无参,或参数全有默认值),拷贝构造函数。在编程时,如果程序员不显式声明和定义上述函数,编译器将自动产生4个public inline的默认函数。形式为:

A();
A(const A&);
A& operator=(const A& a);
~A();

如果类的成员中有指针的话,浅拷贝方式的结果是两个不同对象的指针指向同一块内存区域,容易出现访问冲突,多次delete等错误,不是我们所希望的。

禁止拷贝/赋值

将拷贝构造函数和重载赋值运算符设为private来禁止拷贝

#define DISABLE_COPY(Class) \
Class(const Class &); \
Class &operator=(const Class &)

class Widget  
{  
public:  
    int* pi;  
private:  
DISABLE_COPY(Widget);
};
转自:http://biancheng.dnbcw.info/c/449194.html

参考:http://www.cnblogs.com/OSLover/archive/2013/04/05/3001080.html

http://zh.wikipedia.org/wiki/C%2B%2B11

<think>好的,我现在需要回答用户关于拷贝构造函数与普通构造函数区别的问题。首先,我需要回顾之前的回答用户提供的引用资料,确保信息准确一致。 用户之前询问了拷贝构造函数的定义、实现以及深浅拷贝的问题,我的回答详细介绍了这些内容,并引用了相关引用标记。现在用户的新问题是两者的区别,需要明确区分拷贝构造函数普通构造函数。 首先,根据引用[1][4],普通构造函数用于初始化新对象,而拷贝构造函数用于通过同型对象初始化新对象。这点需要强调两者的主要用途不同。普通构造函数处理的是对象的初始创建,而拷贝构造函数处理的是对象的复制。 接下来,引用[2]中的代码示例展示了普通构造函数的不同形式,包括无参、有参拷贝构造函数。这说明普通构造函数可以有多种形式,而拷贝构造函数有特定的语法(参数为同对象的const引用)。需要指出语法上的区别,比如拷贝构造函数的参数必须是同对象的引用,否则会导致无限递归调用。 引用[3][4]提到,如果不显式定义拷贝构造函数,编译器会生成默认的浅拷贝版本。而普通构造函数如果没有定义,编译器也会生成默认的无参构造函数,但如果用户定义了任何构造函数,编译器就不会再生成默认的。这里需要对比两者的默认行为,尤其是在用户未显式声明时的情况。 另外,引用[3][4]讨论了深浅拷贝的问题,拷贝构造函数在涉及指针或动态资源时需要显式定义深拷贝避免问题。而普通构造函数主要负责分配资源初始化成员变量,不涉及复制现有对象的数据。这也是两者在实现上的关键区别。 引用[5]提到了移动构造函数,但用户的问题集中在拷贝普通构造函数,所以可能不需要深入讨论移动构造,但可以作为扩展点,在相关问题中提及。 需要确保回答结构清晰,分点说明区别,包括用途、语法、默认行为、调用场景实现要求。同时,结合用户之前的回答,保持引用标记的一致,比如引用[1]、[3]、[4]等。 最后,生成的相关问题应引导用户进一步探索,如深浅拷贝的影响、默认构造函数的生成规则等,这有助于用户更全面理解主题。</think>### 拷贝构造函数与普通构造函数的区别 以下是两者核心区别的对比分析,结合代码示例引用内容说明: --- #### **1. 核心用途不同** | **构造函数** | **拷贝构造函数** | |----------------------------|--------------------------------| | 初始化**新对象**的成员变量 | 通过**已有对象**初始化新对象 | | 处理对象**首次创建**的逻辑 | 处理对象**复制行为**的逻辑 | | 例如:分配资源、设置默认值 | 例如:深拷贝指针、避免资源冲突 | - **普通构造函数**示例(引用[2]): ```cpp class Test2 { public: Test2() { /* 无参构造函数 */ } Test2(int a) { /* 有参构造函数 */ } }; ``` - **拷贝构造函数**示例(引用[4]): ```cpp Test2(const Test2& obj) { /* 复制逻辑 */ } ``` --- #### **2. 语法与参数限制** | **特性** | 普通构造函数 | 拷贝构造函数 | |-------------------------|----------------------------------|----------------------------------| | **参数型** | 任意型(或无参数) | **必须为同对象的`const`引用** | | **默认生成规则** | 未定义任何构造函数时生成默认版本 | 未显式定义时生成浅拷贝版本 | | **显式定义必要性** | 根据需要定义不同重载形式 | 含指针/动态资源时必须显式定义 | - **关键区别**(引用[1][3][4]): - 拷贝构造函数参数必须为引用,否则会导致无限递归调用(例如:`Test2(Test2 obj)`会触发拷贝构造,而拷贝构造又需要传值,形成死循环)。 - 普通构造函数无此限制,可自由定义参数型。 --- #### **3. 调用场景对比** | **场景** | 普通构造函数调用 | 拷贝构造函数调用 | |-------------------------|----------------------------------|----------------------------------| | **对象首次创建** | `Test2 obj;` | 不调用 | | **对象复制初始化** | 不调用 | `Test2 obj2(obj1);` | | **函数传参(值传递)** | 不调用 | 调用(生成形参副本) | | **函数返回对象** | 可能调用(创建临时对象) | 可能调用(复制返回值) | - **示例说明**(引用[3][4]): ```cpp Test2 func() { Test2 t; // 调用普通构造函数 return t; // 可能调用拷贝构造函数(生成临时对象) } Test2 a; // 调用普通构造函数 Test2 b = a; // 调用拷贝构造函数 ``` --- #### **4. 默认行为差异** | **行为** | 普通构造函数 | 拷贝构造函数 | |-----------------------|----------------------------------|----------------------------------| | **未显式定义时** | 若未定义任何构造函数,编译器生成默认无参构造函数 | 编译器生成**浅拷贝**版本 | | **显式定义影响** | 若定义了有参构造函数,则默认无参构造函数不再自动生成 | 显式定义深拷贝避免资源冲突 | - **关键问题**(引用[3][4]): - 默认浅拷贝复制指针地址,导致新旧对象共享资源(如内存、文件句柄),可能引发双重释放或数据篡改。 - 普通构造函数不涉及对象复制,因此无此问题。 --- #### **5. 实现要求** | **场景** | 普通构造函数 | 拷贝构造函数 | |-----------------------|----------------------------------|----------------------------------| | **资源管理** | 需显式初始化成员变量 | **必须显式实现深拷贝** | | **仅含基本型成员** | 无需特殊处理 | 无需显式定义(默认浅拷贝安全) | - **深拷贝必要性示例**(引用[3][4]): ```cpp class ResourceHolder { int* data; public: ResourceHolder(int val) { data = new int(val); } // 普通构造函数 ResourceHolder(const ResourceHolder& other) { // 拷贝构造函数(深拷贝) data = new int(*other.data); } }; ``` --- ### 总结对比表 | **维度** | 普通构造函数 | 拷贝构造函数 | |----------------|----------------------------------|----------------------------------| | **核心目的** | 初始化新对象 | 复制已有对象 | | **语法特征** | 无参数型限制 | 参数必须为`const ClassName&` | | **默认行为** | 生成默认无参构造函数(条件受限) | 生成浅拷贝版本 | | **关键风险** | 无 | 浅拷贝导致资源冲突 | | **显式定义场景** | 需要定制初始化逻辑时 | 含指针/动态资源时必须定义 | --- ### 相关问题 1. 如何通过`delete`关键字禁止拷贝构造函数? 2. 浅拷贝在哪些场景下是安全的? 3. 移动构造函数如何进一步优化对象复制的性能? 4. 为什么拷贝构造函数的参数必须为引用型? --- [^1]: 普通构造函数用于对象的首次初始化。 [^3]: 默认拷贝构造函数执行浅拷贝,可能导致资源冲突。 [^4]: 显式定义拷贝构造函数是深拷贝的必要条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值