重载运算符 +
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(你可能不是),为了可维护性,我会坚持使用命名函数。
我里面有下面的代码 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(你可能不是),为了可维护性,我会坚持使用命名函数。