调用拷贝构造函数的场景
1.默认构造函数
默认构造函数是一个系统生成的,参数列表和函数体都为空的函数。
如果类中声明了默认构造函数(无论是否有参数),编译器便不再会为之生成隐含的构造函数。
2.析构函数
- 析构函数的函数列表为空,因此不能实现重载。
- 可以显式调用析构函数。例如可以通过对象名等进行调用,
obj.~A();
3.拷贝构造函数
拷贝构造函数的参数必须是引用类型。参数是指针不会编译报错,但是3.1中的场景不能触发调用拷贝构造函数。
3.1 调用拷贝构造函数的3种场景
- 用一个类的对象去初始化另一个类的对象时
Point a(1, 2); Point b(a); // 调用复制构造函数 Point c = a; // 调用复制构造函数
- 函数的形参是类对象,当调用函数,进行形参和实参结合时
void fun(Point obj) {} int main() { Point a(1, 2); fun(a); // 调用复制构造函数 }
- 如果函数的返回值是类对象,当函数执行完成返回调用者时
实际上,由于编译器的优化,可能不会调用。例如:gcc需要指定**-fno-elide-constructors**
编译选项才会调用。
Point fun() { Point a(1, 2); return a; // 调用复制构造函数 } b = fun();
4.赋值运算符
4.1 注意点
- 拷贝构造函数必须以引用的方式传递参数,基本上都是传常量引用的方式传递函数参数。
- 赋值运算符函数的返回值类型要声明为该类型的引用,并在函数结束前返回实例自身的的引用(*this)。只有返回一个引用,才能进行连续赋值。否则,如果函数的返回值是void,则应用该赋值运算符将不能进行连续赋值。假设有3个Person对象:p1、p2、p3,在程序中语句p1=p2=p3将不能通过编译。
- 关于深拷贝和浅拷贝:当类有指针成员或有动态分配空间,都应实现自定义的拷贝构造函数。提供了拷贝构造函数,最后也实现赋值运算符。
4.2 和拷贝构造函数的区别
- 区别:拷贝构造函数使用已有的对象创建一个新的对象,赋值运算符是将一个对象的值复制给另一个已存在的对象。区分是调用拷贝构造函数还是赋值运算符,主要是否有新的对象产生。
#include <iostream> using namespace std; class A { public: A(string str) : name(str) { cout << "construct " << name << endl; } // 构造函数 A(const A &other) { // 拷贝构造函数 name = "copy " + other.name; cout << name << endl; } A& operator = (const A &other) { // 赋值运算符重载 name = "equal " + other.name; cout << name << endl; return *this; } string name; }; void fun1(A obj) {} A fun2() { A obj1("obj1"); return obj1; } int main() { A a("a"); // 下面3行都是调用拷贝构造函数 A b(a); A c = a; fun1(a); cout << "-----------" << endl; fun2(); cout << "-----------" << endl; // 调用赋值运算符 b = a; } /* 输出: construct acopy a copy a copy a ----------- construct obj1 copy obj1 (指定-fno-elide-constructors编译选项才有这一项输出) ----------- equal a */
参考文献
1. C++ 拷贝构造函数和赋值运算符
2. C++ 拷贝构造函数和赋值运算符函数及其必要性和意义
3. 为什么拷贝构造函数自己的参数必须是引用类型 - 知乎
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现