首页 > 编程笔记

C++重载=(赋值运算符)详解

在 C++ 中,赋值运算符 = 是可以被重载的,重载后的 = 可以用于类对象之间的赋值。

重载 = 的语法格式如下:
类类型 & 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 的引用。

默认情况下,如果不手动为类提供赋值运算符,编译器也会自动为其添加一个赋值运算符,自动添加的赋值运算符是以浅拷贝的方式完成赋值的,而不是深拷贝。

推荐阅读