赋值运算符可替代拷贝构造函数拷贝对象值,为何仍需拷贝构造函数?
为啥C++里有了赋值运算符还需要拷贝构造函数?
这问题问得太到位了!刚学C++面向对象的朋友几乎都会有这个疑问,咱们结合你的代码和实际场景来掰扯清楚。
首先得明确:拷贝构造函数和赋值运算符的作用场景完全不一样,根本不是互相替代的关系。
核心区别:初始化新对象 vs 更新已有对象
- 拷贝构造函数是用来创建一个全新的对象,并且直接用另一个已存在的对象的内容来初始化它。比如你代码里的
example b(a);(哦对,你代码里笔误写成example a(b);啦,应该是创建新对象b),这时候b还不存在,是刚被定义出来的,必须通过拷贝构造来完成初始化。 - 赋值运算符
b = a;则是给已经存在的对象赋值,这时候b已经被创建(不管是默认构造还是其他方式初始化过),只是把a的值覆盖给它。
你试试把代码改成这样,就能直观看到区别:
#include <iostream> using namespace std; class example { int data; public: example() { cout << "默认构造函数被调用" << endl; } example(int x) { data = x; cout << "带参构造函数被调用" << endl; } example(const example& other) { data = other.data; cout << "拷贝构造函数被调用" << endl; } example& operator=(const example& other) { data = other.data; cout << "赋值运算符被调用" << endl; return *this; } }; int main() { example a(50); // 调用带参构造 example b(a); // 调用拷贝构造:创建新对象b并初始化 example c; // 调用默认构造:先创建c c = a; // 调用赋值运算符:给已存在的c赋值 return 0; }
运行这段代码,你会清晰看到两个函数被调用的时机完全不同。
这些场景必须用拷贝构造函数
如果没有拷贝构造函数,很多C++的基础操作都会直接失效:
- 函数传值参数:比如定义
void print_example(example obj),当你调用print_example(a)时,会创建一个obj的拷贝,这一步必须调用拷贝构造函数。 - 函数返回对象:比如
example create_example(int x) { return example(x); },返回的临时对象也是通过拷贝构造来初始化的(虽然现代编译器可能做RVO优化,但标准层面依然要求拷贝构造函数是可访问的)。 - 容器存储对象:比如
vector<example> vec; vec.push_back(a);,push_back的时候会把a拷贝到容器里,这也需要拷贝构造。
浅拷贝的坑:自定义拷贝构造的必要性
另外,当你的类里包含动态分配的资源(比如指针、堆内存)时,编译器默认生成的拷贝构造函数只会做浅拷贝——也就是直接复制成员变量的值。比如:
class String { char* str; public: String(const char* s) { str = new char[strlen(s)+1]; strcpy(str, s); } ~String() { delete[] str; } };
如果用默认拷贝构造创建新对象String s2(s1);,s1和s2的str指针会指向同一块堆内存,当两个对象析构时,会重复释放同一块内存,直接导致程序崩溃。这时候必须自定义拷贝构造函数来做深拷贝,重新分配内存并复制内容,而赋值运算符也需要做同样的处理,但两者的场景还是完全分开的。
总结一下:拷贝构造和赋值运算符是各司其职的,一个管“生新对象”,一个管“给老对象换内容”,缺了哪个都不行~
内容的提问来源于stack exchange,提问作者Ibra noor
相关产品推荐
相关产品推荐

