跳转到内容

C++ 赋值运算符重载

来自代码酷

C++赋值运算符重载[编辑 | 编辑源代码]

赋值运算符重载是C++中一个重要的特性,它允许程序员自定义类对象之间的赋值行为。通过重载赋值运算符,可以确保对象在赋值时执行特定的操作,如深拷贝、资源管理或其他自定义逻辑。

介绍[编辑 | 编辑源代码]

在C++中,赋值运算符(`=`)用于将一个对象的值赋给另一个对象。对于内置类型(如`int`、`float`等),赋值操作是直接且简单的。但对于用户自定义的类类型,默认的赋值运算符可能无法满足需求,尤其是在涉及动态内存分配或其他资源管理时。这时,就需要通过重载赋值运算符来自定义赋值行为。

赋值运算符重载的函数声明通常如下:

ClassName& operator=(const ClassName& other);

其中:

  • `ClassName`是自定义类的名称。
  • `operator=`是重载的赋值运算符。
  • `const ClassName& other`是被赋值的对象(右值)。
  • 返回类型为`ClassName&`,通常返回`*this`以支持链式赋值(如`a = b = c`)。

基本语法与示例[编辑 | 编辑源代码]

以下是一个简单的示例,展示如何重载赋值运算符:

#include <iostream>
#include <cstring>

class String {
private:
    char* data;
    size_t length;

public:
    // 构造函数
    String(const char* str = "") {
        length = strlen(str);
        data = new char[length + 1];
        strcpy(data, str);
    }

    // 析构函数
    ~String() {
        delete[] data;
    }

    // 赋值运算符重载
    String& operator=(const String& other) {
        if (this != &other) { // 防止自赋值
            delete[] data; // 释放原有资源
            length = other.length;
            data = new char[length + 1];
            strcpy(data, other.data);
        }
        return *this;
    }

    // 打印字符串
    void print() const {
        std::cout << data << std::endl;
    }
};

int main() {
    String str1("Hello");
    String str2;
    str2 = str1; // 调用赋值运算符重载

    str1.print(); // 输出: Hello
    str2.print(); // 输出: Hello

    return 0;
}

代码解释[编辑 | 编辑源代码]

1. **构造函数**:动态分配内存并初始化字符串。 2. **析构函数**:释放动态分配的内存。 3. **赋值运算符重载**:

  - 检查自赋值(`if (this != &other)`),避免释放资源后访问无效内存。
  - 释放原有资源(`delete[] data`)。
  - 分配新内存并复制数据。
  - 返回`*this`以支持链式赋值。

4. **输出结果**:`str1`和`str2`的内容相同,表明赋值成功。

自赋值问题[编辑 | 编辑源代码]

自赋值(如`a = a`)是一个容易被忽视的问题。如果不检查自赋值,可能会导致资源被提前释放,进而引发未定义行为。例如:

String& operator=(const String& other) {
    delete[] data; // 如果 this == &other,data 已被释放
    length = other.length;
    data = new char[length + 1];
    strcpy(data, other.data);
    return *this;
}

如果`this == &other`,`delete[] data`会释放`data`,后续的`strcpy`将访问无效内存。

移动赋值运算符(C++11及以上)[编辑 | 编辑源代码]

C++11引入了移动语义,允许更高效的资源转移。移动赋值运算符的声明如下:

ClassName& operator=(ClassName&& other);

示例:

String& operator=(String&& other) {
    if (this != &other) {
        delete[] data;
        data = other.data; // 转移资源
        length = other.length;
        other.data = nullptr; // 确保 other 析构时不会释放资源
        other.length = 0;
    }
    return *this;
}

使用场景[编辑 | 编辑源代码]

移动赋值运算符适用于临时对象(右值)的赋值,避免不必要的拷贝。

实际应用案例[编辑 | 编辑源代码]

假设有一个`Matrix`类,表示二维矩阵:

class Matrix {
private:
    size_t rows, cols;
    double** data;

public:
    Matrix(size_t rows, size_t cols) : rows(rows), cols(cols) {
        data = new double*[rows];
        for (size_t i = 0; i < rows; ++i) {
            data[i] = new double[cols](); // 初始化为0
        }
    }

    ~Matrix() {
        for (size_t i = 0; i < rows; ++i) {
            delete[] data[i];
        }
        delete[] data;
    }

    Matrix& operator=(const Matrix& other) {
        if (this != &other) {
            // 释放原有资源
            for (size_t i = 0; i < rows; ++i) {
                delete[] data[i];
            }
            delete[] data;

            // 分配新资源并复制数据
            rows = other.rows;
            cols = other.cols;
            data = new double*[rows];
            for (size_t i = 0; i < rows; ++i) {
                data[i] = new double[cols];
                std::copy(other.data[i], other.data[i] + cols, data[i]);
            }
        }
        return *this;
    }
};

说明[编辑 | 编辑源代码]

- 动态分配二维数组时,需要逐行释放和复制。 - 使用`std::copy`高效复制数据。

总结[编辑 | 编辑源代码]

赋值运算符重载是C++中管理资源的重要工具。关键点包括: 1. 检查自赋值。 2. 释放原有资源。 3. 分配新资源并复制数据。 4. 返回`*this`以支持链式赋值。 5. 在C++11及以上版本中,考虑实现移动赋值运算符以提高性能。

通过合理重载赋值运算符,可以确保类对象在赋值时行为正确且高效。