Operator overloading in C ++

If I want to overload the + operator, which prototype is correct?

  • D operator+(const D& lhs, const D& rhs);
    then declare it as a friend function from D.

  • D operator+(const D& s);
    Then declare it as a member function of D.

+4
source share
10 answers

The first is right, the second is wrong. You can improve the second by writing this

 D operator+(const D& s) const; 

but it is still wrong. The reason is that the compiler will apply different rules to the left and right sides of your + operator in the second version. For example, this code

 class C { }; class D { public: D(const C&); }; C c; D d; d = d + c; // legal with both versions d = c + d; // not legal with the second version 

The difference is that the compiler will create a temporary object D from the C object for the argument of the method or function, but it will not do this to cause the method to be called on the temporary object.

In short, the first version applies to the left and right sides equally and therefore is better aligned with the expectations of the encoders.

+3
source

The second should be

 D operator+(const D& s) const; 

Then either good.

First of all, you need to be a friend: only if he really needs access to something private. You can usually implement it in terms of an open interface, usually with the corresponding operator+= :

 D operator+(D lhs, const D& rhs) { //copy left-hand side return lhs += rhs; //add the right-hand side and return by value } 
+2
source

I would advise you to follow the third path: Add operator+= as a member function, and then implement operator+ in terms of the previous type:

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

The advantage of the third method is that with the same code you provide both + and += , and you get the opportunity to implement operator+ as a free function, which is an advantage in terms of symmetry, if your class has implicit conversions, it will allow d + t and t + d for any object d type d and any other object of type t implicitly convertible to d . The version of the member function will only apply transformations to the right side, which means that d + t will be allowed, but not t + d .

[warning about own advertising] You can read a more detailed explanation on this issue here

+2
source

Go with the first one. However, if he needs to access private members, only then make him a friend , otherwise make him a function different from each other.

+1
source

I think both are correct. But one thing that you missed (it may or may not apply) is that if the value on the left can be something other than D (for example, an integer or something else), then the option is used for this 1

 D operator+(int lhs, const D& rhs); 

Then you can do something like:

 D d1; D d2 = 5 + d1; 
+1
source

Both methods are almost correct. These are just two ways to do almost the same thing. But when you need to apply the binary operator to types other than D (like int + D), you need to use the second.

Parameter 1 does not have to be a friend if it does not need access to private members.

Parameter 2 should be slightly corrected. You are missing D:: .

 DD::operator+(const D& s) const { } 
0
source

You only need to declare the function as a friend of the class if you plan to access private class variables through this function. In the first prototype, you do not need to declare the function as a friend, since you pass all the values ​​that you plan to use. In the second prototype, you can declare a function as a friend, since you will need to access another variable, but it is best to simply declare this function as a member.

0
source

The first has a different behavior if D has implicit constructors.

Consider

 struct D { D(int); }; D operator+(const D&, const D&); 

Then you can do 1 + d and d + 1 , which you cannot do with the operator+ element (lhs should be D , and the conversion should not take place).

0
source

The principle of least surprise suggests that your overload should behave more or less like built-in operators. The usual solution here is not to implement operator+ at all, but to implement:

 D& operator+=( D const& rhs ); 

as a member, and then get something like:

 template<typename T> class ArithmeticOperators { friend T operator+( T const& lhs, T const& rhs ) { T result( lhs ); result += rhs; return result; } // Same thing for all of the other binary operators... }; 

Thus, you do not need to rewrite the same thing every time you define a class that overloads arithmetic operators, and you are guaranteed that the semantics of + and += correspond.

(The friend in the above just allows you to put the function, along with its implementation, in the class itself, where ADL finds it.)

0
source

Both are correct (after fixing the match correctness problem that others have indicated), but I recommend a member statement. It can be overridden by polymorphic behavior if it is virtual, has better grip on the class, and as a result, it is easier to maintain and document. Try to avoid friends functions if you can.

As for the “derived = base + derived” case, I recommend not mixing the operations of semantics of meaning and polymorphism, it can have unforeseen consequences due to various implicit transformations and partitioning of objects. This example may be equivalent to derived = Derived(base) + derived , but it may be derived = Derived(base + Base(derived)) if the base has a + operator.

Use only explicit conversion and casting, and you will not encounter any cryptic strange behavior. And think twice before applying operators to a polymorphic class.

0
source

All Articles