C++重载=(赋值运算符)详解
在 C++ 中,赋值运算符 = 是可以被重载的,重载后的 = 可以用于类对象之间的赋值。
重载 = 的语法格式如下:
例如,为 MyClass 类重载 =:
默认情况下,如果不为类提供赋值运算符,编译器也会自动为其添加一个赋值运算符。不过编译器添加的赋值运算符,只是傻瓜式地将 obj 对象中各个成员变量的值赋值给目标对象(浅拷贝),当类中有指针成员变量的时候可能无法正常地工作。
下面是一个使用 C++ 重载赋值运算符的完整实例:
重载 = 赋值运算符时,通常的做法是先释放对象当前持有的资源,然后分配新的资源,特别是无法保证被赋值对象(即other对象)和赋值对象(即*this对象)有相同大小的资源时,能有效避免越界访问、资源泄漏等问题。
什么时候调用拷贝构造函数,什么时候调用赋值运算符重载函数,很多初学者分不清楚,下面以 MyClass 类为例帮读者区分这两个概念:
默认情况下,如果不手动为类提供赋值运算符,编译器也会自动为其添加一个赋值运算符,自动添加的赋值运算符是以浅拷贝的方式完成赋值的,而不是深拷贝。
重载 = 的语法格式如下:
类类型 & operator=(参数);重载函数的参数列表中只能有一个参数。类类型指的是当前类的类型,也就是说,返回的是当前类的对象的引用。
例如,为 MyClass 类重载 =:
class MyClass{ public: MyClass& operator=(const MyClass & obj); // 重载 = 赋值运算符 }注意,重载 = 赋值运算符只能以成员函数的方式,而不能以全局函数(友元函数)的方式。
默认情况下,如果不为类提供赋值运算符,编译器也会自动为其添加一个赋值运算符。不过编译器添加的赋值运算符,只是傻瓜式地将 obj 对象中各个成员变量的值赋值给目标对象(浅拷贝),当类中有指针成员变量的时候可能无法正常地工作。
下面是一个使用 C++ 重载赋值运算符的完整实例:
#include <iostream> class MyClass { private: int* data; int size; public: MyClass(int size): size(size) { data = new int[size]; // 初始化数组(可选) for (int i = 0; i < size; ++i) { data[i] = 0; } } // 重载赋值运算符 MyClass& operator=(const MyClass& other) { if (this == &other) { return *this; // 处理自我赋值 } delete[] data; // 释放当前对象的资源 size = other.size; data = new int[size]; // 分配新资源 // 深拷贝数据 for (int i = 0; i < size; ++i) { data[i] = other.data[i]; } return *this; // 返回*this以支持连续赋值 } // 析构函数 ~MyClass() { delete[] data; } }; int main() { MyClass obj1(10); MyClass obj2(20); obj1 = obj2; // 使用重载的赋值运算符 return 0; }MyClass 类中对 = 赋值运算符进行了重载,重载函数中采用深拷贝的方式,使得每个对象都有其自己独立的 data 数组。
重载 = 赋值运算符时,通常的做法是先释放对象当前持有的资源,然后分配新的资源,特别是无法保证被赋值对象(即other对象)和赋值对象(即*this对象)有相同大小的资源时,能有效避免越界访问、资源泄漏等问题。
赋值运算符VS拷贝构造函数
赋值和复制构造函数是不同的,赋值发生在两个已有的对象之间,是用一个存在的对象的数据来设置另外一个对象,复制构造函数是用一个已经存在的对象来生成一个新对象。什么时候调用拷贝构造函数,什么时候调用赋值运算符重载函数,很多初学者分不清楚,下面以 MyClass 类为例帮读者区分这两个概念:
MyClass c1(10); // 定义 c1 对象,调用有参构造函数 MyClass c3 = c1; // 定义 c3 对象,调用拷贝构造函数 MyClass c4(10); c4 = c3; // 用 c3 给 c4 赋值,调用赋值运算符重载函数也就是说,创建新的类对象时调用的是拷贝构造函数,已有的两个类对象之间的赋值过程调用的是赋值运算符重载函数。
总结
赋值运算符只能以成员函数的方式重载,重载函数接收一个与当前类相同类型的参数,最终返回 *this 的引用。默认情况下,如果不手动为类提供赋值运算符,编译器也会自动为其添加一个赋值运算符,自动添加的赋值运算符是以浅拷贝的方式完成赋值的,而不是深拷贝。