运算符重载的概念与介绍
对于常见的运算符,比如+,-,> <,[],大家应该都很熟悉。但是这些东西只能在一些基础数据类型或者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),是会调用拷贝构造函数的。实际上,它会调用移动构造函数。
当我们使用重载的 + 运算符对 str1 和 str2 进行拼接时,会创建一个临时的 MyString 对象,该对象存储了拼接后的结果。然后,这个临时对象被移动构造函数所接管,并将其值移动(而不是复制)到 str3 对象中。
移动构造函数
移动构造函数是 C++11 引入的特性,它允许在对象之间进行资源的高效转移,而不需要进行额外的复制操作。通过移动构造函数,我们可以将临时对象的资源(例如内存)直接转移到目标对象中,避免了不必要的复制开销。 在这个例子中,由于临时对象是通过拼接操作创建的,并且在同一行代码中被移动到 str3 对象中,所以编译器会自动选择调用移动构造函数来优化性能。 总结起来, MyString result = str1 + str2; 这行代码会调用移动构造函数而不是拷贝构造函数,以提高性能和效率。
总结
-
运算符重载可以简化一些繁琐的函数调用,使代码更简洁、易读,并提高程序的可扩展性和灵活性。
-
当一个函数返回值是对象的时候,如果没有c++编译优化,会产生额外的临时对象,也就是会调用拷贝构造函数和析构函数,如果构造对象复杂,这些都是开销,会损耗性能。所以C++11 引入移动构造函数来做优化。