C++运算符重载

106 阅读3分钟

运算符重载的概念与介绍

对于常见的运算符,比如+,-,> <,[],大家应该都很熟悉。但是这些东西只能在一些基础数据类型或者string这样的系统提供的类中来使用。如果我们想在自定义的类对象中使用这种运算符,就需要用到运算符重载。

通过运算符重载,我们可以对自定义类型的对象进行像内置类型一样的运算操作,提供更直观和方便的语法。运算符重载还能够提高代码的可读性,因为它允许我们使用习惯的运算符来表示特定的操作,而不需要使用繁琐的函数调用或方法调用

实现类string + 号拼接

在这个demo中,为了简化运算符重载,我操作的数据类型是系统提供的string,实际上通过char数组来操作更合适些。

class MyString {
private:
    string _data;
public:
    MyString(const string &s) : _data(s) {
        cout << " MyString(const string &s)" << endl;
    }

    MyString(const MyString &myString) {
        cout << " MyString(const MyString &myString)" << endl;
        this->_data = myString._data;
    }

    MyString operator+(const MyString &other) {
        cout << "operator+(const MyString &other)" << endl;
        return MyString(_data + other._data);
    }

    void printStr() {
        cout << _data << endl;
    }
};

int main() {
    MyString s1("Hello, ");
    MyString s2("C++");
    MyString s3 = s1 + s2;
    s3.printStr();
    return 0;
}

运算符重载,本质上也是调用一个函数。只不过这个函数格式比较固定,通过operator关键字来实现,后面紧随运算符号,形参是当前类对象

继续来解析下operator这个函数。首先它是个运算符重载函数,由左操作数调用,右操作数作为实参传递给函数。 相当于

str1 + str2 = str1. operator+(str2)

一个疑问

这个demo中 MyString s3 = s1 + s2;这句代码并没有触发拷贝构造函数。在之前的文章说过,用一个已经创建的对象(s1 + s2),去初始化一个新对象(s3),是会调用拷贝构造函数的。实际上,它会调用移动构造函数。

当我们使用重载的 + 运算符对 str1str2 进行拼接时,会创建一个临时的 MyString 对象,该对象存储了拼接后的结果。然后,这个临时对象被移动构造函数所接管,并将其值移动(而不是复制)到 str3 对象中。

移动构造函数

移动构造函数是 C++11 引入的特性,它允许在对象之间进行资源的高效转移,而不需要进行额外的复制操作。通过移动构造函数,我们可以将临时对象的资源(例如内存)直接转移到目标对象中,避免了不必要的复制开销。 在这个例子中,由于临时对象是通过拼接操作创建的,并且在同一行代码中被移动到 str3 对象中,所以编译器会自动选择调用移动构造函数来优化性能。 总结起来, MyString result = str1 + str2; 这行代码会调用移动构造函数而不是拷贝构造函数,以提高性能和效率。

总结

  1. 运算符重载可以简化一些繁琐的函数调用,使代码更简洁、易读,并提高程序的可扩展性和灵活性。

  2. 当一个函数返回值是对象的时候,如果没有c++编译优化,会产生额外的临时对象,也就是会调用拷贝构造函数和析构函数,如果构造对象复杂,这些都是开销,会损耗性能。所以C++11 引入移动构造函数来做优化。