简体   繁体   中英

Chaining an operator that doesn't return an object

I'm required to define a node class and that class needs to have an overloaded '+' operator function which returns the sum of two nodes.

I'm pretty comfortable doing this but I can't help but wonder why it should return the sum which would be say a double and thus, chaining for this operator would no longer be possible.

I mean, node1 + node2 works but, node1 + node2 + node3 won't.

How do I achieve this combined sum of 5 nodes making use of the overloaded '+' operator which returns a double?

Edit:

double Node::operator +(const Node& n) { return (this->weight + n.weight); }

There are two options. Either it makes sense for you to have "double + node", and you understand what that means, or you cannot return a double from the operator.

I'll elaborate. There is no tretinary operator + in C++ (nor any other language I'm aware of). Your node1 + node2 + node3 is really (node1 + node2) + node3. Let's number the operators, for easier reference, p1 and p2 (left is p1, right is p2).

Now you must decide which makes more sense. In particular, when looking at the semantics of what a "node" means, does it make sense to do "2.3 + node"? If so, simply define an operator+ that accepts one node and one double, and be done with it.

Taking this even further, if a node has little value beyond its value, you can create a node constructor that accepts a double, thus creating an implicit cast from double to node.

The alternative is to say that "double + node" makes no sense. Maybe a node has many aspects, its value being only one of them. If that's the case, and there is some meaningful way you can "add" two nodes, then you need your operator+ to return a node. No way around it.

Then there is the third option. If there is no way to add two nodes and get a third one, but there is also no sense in having "double + node", then you need a proxy class.

class node {
private:
  class node_value {
  public:
    double value;
    operator double() { return value; }
  }

  node_value operator+( const node &rhs );
  node_value operator+( const node_value &rhs );
};

operator+ for node returns a proxy class, which is implicitly convertible to double. It defines the first form of operator+ for the main addition, and the second form for the chained addition. You'd also need the swapped arguments operator defined outside the class, of course.

If you also implement a cast operator, eg operator double() , you'll be able to implicitly cast the result of chained additions, and the following should work:

Node a(3.0);
Node b(7.0);
Node c(24.0);
double x = a + b + c;

If it is possible to add a node and a double, you can support multiple additions by defining addition of Nodes and doubles:

class Node {
  public:
    friend double operator+(double a, Node &b);
    double operator+(double b) {
      // however you get the sum here
      // for example, if the sum is a field of the node:
      return this->weight + b;
    }
}
double operator+(double a, Node &b) { return b + a; }

Note that we have to define both Node + double and double + Node , in order to support things like a + (b + c) in addition to (a + b) + c .

Edit: in response to your edit, I updated the code.

For chaining, you can override operator double for Node like

struct Node {
   double operator+(const Node & n) const {
       return n.val + val;
   }

   Node(double val) : val(val) {}

   operator double() {
      return val;
   }

   double val;
};

Then you can do :

Node n1(1);
Node n2(2);
Node n3(3);
std::cout << n1 + n2 + n3 << endl; // 6

But this can cause confusion for the reader. Why ?? When you add two ints you expect a int . When you add two Nodes what do you expect ? A double or a Node ?

Therefore, if i have to do it:

struct NodeBetter {
  // Notice the return Type NodeBetter 
  NodeBetter operator+(const NodeBetter & n) const {
       return NodeBetter(n.val + val);
   }
   double val;
   NodeBetter(double val) : val(val) {}
};

 // in main()
 NodeBetter n1(1);
 NodeBetter n2(2);
 NodeBetter n3(3);
 std::cout << (n1 + n2 + n3).val << endl; // again 6. :)

See in Action : Code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM