重载运算符+

Overloading operator +

本文关键字:运算符 重载      更新时间:2023-10-16

Movie类中有以下代码:

Movie& operator+ (const Movie& other);

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

当我尝试做:

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

它给了我错误:

must take zero or one argument

在搜索过程中,我看到了一些解决方案,但没有一个对我有效。

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

实现operator+的最佳方法是为类实现operator+=,然后根据operator+=operator+编写为非成员函数。这为您提供了两个运算符,价格相当于一个运算符,降低了代码重复,并相对于隐式转换对称地处理左右参数。

实现的一个问题是返回对Movie的引用。这将需要动态分配Movie并记住删除它(效率低、容易出错),返回对本地的引用(未定义的行为),或者有一些更复杂的系统(不必要)。您应该只按值返回。

以下是实现的样子:

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;
}

您不必重载运算符来添加许多对象,这已经由您的operator+处理了。您应该只更改它以返回一个值而不是引用:

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+()的重载定义。

Movie MOVIE5 = MOVIE1+MOVIE2+MOVIE3+MOVIE4;

为了理解,您可以将其扩展为

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

operator+MOVIE3.opertor+(MOVIE4)返回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

它之所以有效,是因为运算符返回了对Movie(函数声明中的Movie&)的非常数引用。此返回值将成为下一个operator +的左操作数。

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

EDIT:正如TartanLlama所指出的,您可能想将第一个方法的签名更改为:

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

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

运算符可以正常链接:如果定义了用于添加两个Widget并返回一个Widget的运算符+,则可以使用它添加任意数量的Widgets。原因很简单:

a + b + c + d

被解析为

((a + b) + c) + d

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

一般来说,处理这样的操作员的最佳方式是执行操作&类中的赋值变量,并在此基础上将二进制运算符构建为非成员函数。类似这样的东西:

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(可能不是),否则出于可维护性的考虑,我会坚持使用命名函数。

+运算符是所谓的binary运算符(与unary相反)。这意味着它只需要两个论点:"left hand side" <operator> "right hand side"

只有非成员二进制运算符接受两个参数。

由于成员方法中的左手边始终是当前对象this,因此所有成员二进制运算符都只接受一个参数。

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

相反,您可以返回一系列电影。