【问题标题】:Operator overloading+ to add multiple objects运算符重载+添加多个对象
【发布时间】:2016-01-09 18:19:06
【问题描述】:

我需要使用运算符重载添加多个对象,如下所示:

ex1 operator+(const ex1 &c1, const ex1 &c2, more++){
    return ex1(c1 + c2 + more++);
}

这个函数添加了两个对象,但是我想添加多个对象。这可能吗?

int main(){
  // first for example I want to add 3 objects
  ex1 ob1, ob2, ob3;
  ob1 + ob2 + ob3;

  code..
  code..

  // and after that I want to add for example 10 or more objects  
  ex1 ob1, ob2, ob3,..., ob10;
  ob1 + ob2 + ob3 +....+ ob10;
}

【问题讨论】:

  • 不管你想把多少个“值”(或对象)加在一起,操作符函数仍然只需要一个(对于成员函数)或两个(对于非成员函数)参数.编译器将为您级联调用。
  • 你能解释一下你的回复吗?你说我可以用任意数量的参数调用operator+?
  • 否,编译器将生成正确数量的运算符函数调用。该函数将始终只使用一个或两个参数调用(取决于它的声明位置),但调用次数会随着您添加更多值而增加。
  • 只是为了实验,你为什么不写一个简单的operator+ 函数,它只打印一些东西并返回一个默认构造的对象,当然只有两个参数才能使它工作。这样您就可以很容易地看到该函数被调用了两次,例如a + b + ca + b + c + d 等三遍
  • 另外,想一想:加法(+ 运算符)是一个 二元 运算符,这意味着它有 两个 操作数:一个左手边和一个右手边。这就是加法的工作原理,无论是在 C++ 中还是在现实生活中。左边是另一个加法的结果并不重要,运算符仍然只有两个操作数。

标签: c++ class overloading operator-keyword


【解决方案1】:

只要定义

ex1 operator+(const ex1 &c1, const ex1 &c2){
    return ex1(c1.inner_value + c2.inner_value);
}

然后

a + b + c

将被解释为

operator+(  operator+(a,b) , c )

所以它应该可以工作

【讨论】:

  • 我想要多个类对象 .. 不是 3 而是多个,3 就是一个例子
  • 虽然操作符函数签名正确且调用顺序正确,但该函数实际上不会工作,因为operator+函数将被递归调用。
  • 对。我将 operator+ 定义固定为不递归。
  • 你能检查我的更新吗?
【解决方案2】:

两个对象只需要overload +。如果您尝试添加三个或更多对象,它将自动工作,因为a + b + c 等效于(a+b)+c,或者就操作符函数调用而言:

 operator+(operator+(a, b), c)

只要您从 + 例程中返回适当的类型,就可以了。

如果你有一个对象数组并且想把它们全部加起来,你只需要为两个对象重载 operator + 然后你就可以使用 <numeric> 标头中的 std::accumulate 函数:

std::vector<ex1> objects = {/*...lots of objects*/};
ex1 sum = std::accumulate(objects.begin(), objects.end(), ex1());

重新更新: 通过在 C++ 中重载运算符,您可以更改运算符的返回类型和语义,但不能更改以下任何内容:

  • 运算符的优先级(即不能使a+b*c 等同于(a+b)*c
  • 运算符的数量(即,您不能重载一元运算符以获取 2 个操作数,反之亦然。例如,您不能使 % work like %a 或 a%
  • 如果(一元)运算符是后缀或前缀,则无法更改,因此您无法使语法 a-a+ 起作用

所以第二个问题的答案是否定的。

【讨论】:

  • 你能给我举个例子吗?
  • @therealp: a+b+c+d+e 等价于 (((a+b)+c)+d)+e
  • 你能用类似的问题检查我的更新吗??
【解决方案3】:

如果您希望您的重载运算符适用于多个对象,您需要的是 chaining*,当您通过引用返回结果时可以确保这一点:

ex1& operator+(const ex1 &c1, const ex1 &c2){

    return ex1.var = c1.var + c2.var;
}

或者如果操作符是类成员:

ex1& operator+(const ex1 &rhs) {

    return ex1.var = this.var + rhs.var; 
}

一旦有了上面的定义,就可以添加多个对象,如下:

ex1 + ex2 + ex3

相当于:

(ex1 + ex2) + ex3 => sum(ex1,ex2) + ex3 => sum(sum(ex1,ex2), ex3)

即它总是简化为两个操作数之间的二元运算。

为了回答您更新的问题,这里列出了 all the operators that could be overloaded,无论它们的元数(一元、二进制)或词缀(前缀、后缀)如何。对于您更新的问题,您正在寻找后缀、一元运算符重载。

*多个方法调用,其中每个方法返回一个对象,允许在单个语句中将调用链接在一起,而不需要变量来存储中间结果

【讨论】:

  • 很高兴能帮上忙! :)
  • 你能检查我的更新吗?
  • @therealp 我建议您接受满足问题第一部分的答案,然后用新主题提出一个新问题。 :)
  • 感谢帮助我是这个社区的新手,但系统不允许我创建新线程:(
  • @simplicis veritatis 您正在通过引用返回一个局部变量。任何打电话给你operator+ 的人都会看到未定义的行为。
【解决方案4】:

除了一个例外,C++ 只有一元运算符和二元运算符。一个例外是三元运算符,例如x = condition ? 0 : 42;。对于operator+,要么是一元运算符(例如+42),要么是二元运算符(40+2)。

您可以轻松创建一个自定义函数,该函数将三个ex1 对象作为输入,并以某种方式计算这三个对象的总和。但是,您不能调用此函数operator+。在 C++ 中没有接受三个参数的 operator+ 的位置。

有很多方法可以绕过这个限制。最简单的方法是创建二进制operator+ 的重载,计算一对ex1 对象的总和,创建一个新的ex1 对象作为输出。语句ex1 d=a+b+c; 将导致对ex1 operator+(const ex1&amp;, const ex1&amp;) 的两次调用。两者都将创建一个ex1 类型的临时对象。然后将表示a+b+c 值的临时值传递给ex1::operator= 以将该表达式的值分配给d

如果您一遍又一遍地这样做,这些临时对象的创建很可能会成为性能瓶颈。如果您只这样做几次,那么性能瓶颈不是问题。您唯一需要担心的是这是否是一个问题,并确定是否是您需要解决的问题。

克服这一性能瓶颈的一种方法是创建一个(或多个)函数,该函数将两个以上的对象作为输入,并从这些多个对象中创建一个总和。缺点是你不能将此函数命名为operator+,因此你不能使用d=a+b+c。相反,您必须使用 ex1::add_three(ex1&amp;d, const ex1&amp;a, const ex1&amp;b, const ex1&amp;c) 之类的东西。

另一种方法是使用expression templates 作为实现lazy evaluation 的一种方式。您的operator+(const ex1&amp; a, constex1&amp; b) 实际上并没有计算a+b。相反,它会创建一个最终会计算a+b的对象。表达式a+b+c 反过来创建另一个对象,最终将计算该结果。最后,表达式d=a+b+c 计算该表达式并将其分配给d,并且(如果实现正确)这样做而不创建任何临时对象。

这种方法也有其缺点。有时最好创建一个临时的。 Eigen 包在确定何时创建临时而不是使用延迟计算的表达式模板方面做得非常好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多