为什么类的拷贝构造函数必须传递引用对象而非值参数
类自身类型为参数的构造函数为什么必须用引用传参
核心矛盾:值传递会触发无法终止的无限递归
首先明确C++值传递的基本规则:函数传值的过程,本质是把实参拷贝一份生成和实参同类型的独立形参副本,这个拷贝动作会直接触发对应类型的拷贝构造函数。
假设你真的写了值传递形式的自身类型构造函数,比如:
class Numbers{ int a; public : Numbers(){}; // 错误写法:值传递形式的构造函数 Numbers(Numbers obj) { this->a = obj.a; } };
当你尝试调用这个构造函数时,比如写Numbers n2 = n1用现有对象n1初始化n2,整个流程会陷入死循环:
- 为了给形参
obj传值,需要把实参n1拷贝成一个独立的形参对象 - 这个拷贝动作需要调用类的拷贝构造函数,也就是上面写的
Numbers(Numbers obj) - 调用这个构造函数又需要给它的形参传值,又要生成新的形参副本,又要触发拷贝构造
- 流程无限循环,永远到不了构造函数内部的逻辑,编译器根本没法生成可运行的代码,会直接报编译错误
哪怕你给值参数加上const修饰,写成Numbers(const Numbers obj),这个问题也不会解决:const只限制你不能在构造函数内部修改形参,改变不了“值参数需要独立副本、需要拷贝实参生成副本”的本质,照样会触发无限递归。
这也是为什么C++语言标准明确规定,类的拷贝构造函数不能以自身类的值类型作为唯一参数的根本原因。
引用传参为什么能解决这个问题
引用本质是对象的别名,传引用的过程不会生成新的对象副本,也就不会触发拷贝构造的调用流程,从根源上避免了无限递归的问题。
实际写规范的拷贝构造函数时,一般会把参数写成常量引用形式,比如:
Numbers(const Numbers& obj) { this->a = obj.a; }
这种写法既不会产生多余的临时对象拷贝开销,也能保证构造函数不会意外修改传入的原对象,还能支持用const修饰的类对象做拷贝初始化,是行业通用的标准写法。
内容的提问来源于stack exchange,提问作者user15071349
相关产品推荐
相关产品推荐

