重载运算符 +

Overloading operator +

我里面有下面的代码 Movie class:

Movie& operator+ (const Movie& other);

现在我想重载几次,比如 MOVIE1 + MOVIE2 + MOVIE3 + MOVIE4

当我尝试做的时候:

Movie& operator+ (const Movie& left, const Movie& right);

它给我错误:

must take zero or one argument

在搜索时我看到了一些解决方案,none 其中对我有用。

您不需要 operator+().

的重载定义
Movie MOVIE5 = MOVIE1+MOVIE2+MOVIE3+MOVIE4;

要理解你可以将其展开为

Movie MOVIE5 = MOVIE1+MOVIE2+MOVIE3.opertor+(MOVIE4);

operator+MOVIE3.opertor+(MOVIE4) returns Movie object,然后与 MOVIE2 object 相加,它们的结果将依次与 MOVIE1 相加,最终返回结果 MOVIE5 object

第一个定义:

Movie& operator+ (const Movie& other);

已经允许您将 operator + 链接到您要编写的语句中:

MOVIE1+MOVIE2+MOVIE3+MOVIE4; // assumes all those variable are of type Movie

它起作用的原因是运算符return是对Movie(函数声明中的Movie&)的非常量引用。此 return 值成为下一个 operator +.

的左操作数

MOVIE1+MOVIE2+MOVIE3;语句等同于(MOVIE1+MOVIE2)+MOVIE3;。我们可以看到它由两个表达式组成(两者的运算符都是+)。评估的第一个表达式是 MOVIE1+MOVIE2。 return 值成为第二次加法的左操作数,MOVIE3 作为右操作数。

编辑:正如 TartanLlama 所指出的,您可能希望将第一个方法的签名更改为:

Movie operator+ (const Movie& other); // return a value instead of a reference

因为您可能会return引用本地对象,这将导致未定义的行为。

+ 运算符是所谓的 binary 运算符(相对于 unary)。这意味着它正好需要两个参数: "left hand side" <operator> "right hand side"

只有非成员二元运算符有两个参数。

由于成员方法的左侧始终是当前对象 this,所有成员二元运算符都只接受一个参数。

这就是您找不到解决方案的原因。

您可以改为 return 一组电影。

您不必重载运算符来添加许多对象,这已经由您拥有的 operator+ 处理了。您应该只将其更改为 return 值而不是参考值:

struct A {
    int value;
    A() : value(1) {}
    A operator+(const A& other){
        A result;
        result.value = this->value + other.value;
        return result;
    }
}; 

int main() {
    A a,b,c;
    A d = a + b + c;
    std::cout << d.value << std::endl;
    return 0;
}

您不需要任何特殊的链式添加,您只需要正确的运算符重载。

实现operator+的最佳方法是为你的class实现operator+=,然后根据[=12]将operator+写成非成员函数=].这可以让您以一个运算符的价格获得两个运算符,减少代码重复,并在隐式转换方面对称地处理左右参数。

您的实施存在一个问题,即您 return 引用了 Movie。这将需要动态分配 Movie 并记住删除它(效率低下,容易出错),return 对本地的引用(未定义的行为)或有一些更复杂的系统(不必要的) .您应该按值 return。

下面是一个实现的样子:

class Movie {
public:
    Movie& operator+= (const Movie& rhs) { 
        m_data += rhs.m_data;
        return *this;
    }

private:
    int m_data; //assume some data
};

Movie operator+ (Movie lhs, const Movie& rhs) {
    lhs += rhs;
    return lhs;
}

运算符可以正常链接:如果您定义运算符 + 以添加两个 Widget 并返回一个 Widget,您可以添加尽可能多的 Widgets随心所欲。原因很简单:

a + b + c + d

被解析为

((a + b) + c) + d

但是,您的运算符声明有问题:您将 reference 返回给 Movie。这对于像 + 这样的运算符来说毫无意义,它创建一个新值而不是修改现有值。您应该在运算符中创建一个单独的 Movie 对象,并按值返回它。

通常,处理此类运算符的最佳方法是在 class 中实现运算和赋值变体,并在此基础上将二元运算符构建为非成员函数。像这样:

class Movie
{
  // ...
  Movie& operator+= (const Movie &rhs)
  {
    //somehow add rhs to this
    return *this;
  }
  // ...
};

inline Movie operator+ (const Movie &lhs, const Movie &rhs)
{
  Movie result = lhs;
  result += rhs;
  return result;
}

还有一点:虽然。首先将两部电影加在一起是什么意思?为了某些任意的、单一的操作的较短语法而重载运算符会导致不可读,因此无法维护,因此 糟糕 代码。

除非你正在构建一个 DSL(你可能不是),为了可维护性,我会坚持使用命名函数。