how to call operator + in operator += - c++

Is it right to define operator += in this way ?!
void operator +=(const BigNumber& other)
{
*this=(*this) + other;
}
In a class like this :
class BigNumber
{
public:
//....
BigNumber operator +(const BigNumber& other)
{
return sum(other);
}
//....
}

Yes. But the right way is to implement operator+ in terms of operator+=:
struct foo
{
int value;
foo& operator+=( const foo& other )
{
value += foo.value;
return *this ;
}
friend foo operator+( foo lhs , const foo& rhs )
{
return lhs += rhs;
}
};
Why?
First of all, the binary operator+() shouldn't be defined as member function instead of free function. This allows you to implement addition where the first parameter is not a foo. The common idiom is to declare it friend inside the class to ride over encapsulation.
Second, this way provides a coherent, maintainible, and efficient interface.
Coherency:
If you implement a += operation, the user spects (Except in rare cases) the type provides a binary addition too. Implementing + with += provides this ensuring that the behavior of the two operations is coherent.
Maintainability:
You have implemented + using +=, so the code which really performs the addition is written only once. If you need to change the operation in the future you have to change one code only, and if it has a bug that bug is in one site only. Reducing code duplication is a good practice in general.
Efficiency:
The way the operator+() is written allows the compiler to easily elide copies, boosting the performance of the binary addition.
The idiom used is "copy first operand, operate on it, return the copy". So the compiler can easily perform a return value optimization (RVO). Also, it passes the first operand by value instead of copying the operand by hand inside the function. This allows the compiler to perform more copy elisions when the first operand is an rvalue (Let the compiler decide when and how to copy).

Yes you can do it your way:
BigNumber& operator +=(const BigNumber& other)
{
*this=(*this) + other;
return *this;
}
The usual approach is the opposite way:
// Note a is no const reference
BigNumber operator + (BigNumber a, const BigNumber& b)
{
return a += b;
}
A reasoning for your approach might be memory allocation.

Related

How has += operator been implemented in c++?

This is a question I've always pondered on and have never found any resource stating the answer to this question. In fact its not only for +=, but also for its siblings i.e. -=, *=, /=, etc. (of course not ==).
Consider the example,
int a = 5;
a += 4;
//this will make 'a' 9
Now consider the equivalent expression:
a = a + 4;
//This also makes 'a' 9
If += were simply a shorthand for a = a + <rhs of +=>
overloading + operator should also implicitly overload +=, unless explicitly overloaded otherwise. But that isn't what happens. That means, a += b doesn't get converted to a = a + b. But then why wasn't it implemented this way? As in, wouldn't it have been easier to simply convert it to a = a + b during compilation instead of implementing it separately as an operator in itself? That would also help in operator overloading, where a += b, where a and b are objects of the same class would not have to be explicitly overloaded, and simply overloading + would have been enough?
EDIT:
My question becomes more clear with this answer
Let me explain my question with an example where one needs to overload the operators:
class A {
int ivar;
public:
A() = default;
A(int par_ivar) : ivar(par_ivar) { }
A(A& a) {
this.ivar = a.ivar;
}
A(A&& a) noexcept {
this.ivar = a.ivar;
}
A operator+(const A& a) const {
A temp_a;
temp_a.ivar = this.ivar + a.ivar;
return temp_a;
}
void operator=(const A& a) {
this.ivar = a.ivar;
}
~A() = default;
};
Now, let's take a look at the result of 2 programs:
prog1:
int main() {
A a1(2);
A a2(3);
a1 = a1 + a2; //a1.ivar = 5
return 0;
}
prog2:
int main() {
A a1(2);
A a2(3);
a1 += a2; //compilation error!!
return 0;
}
Even when both the programs meant to do, nay, do the same thing, one compiles and runs (hoping that my overloads are correct) the other does not even compile!! Had += been simply replaced by appropriate + and =, we would not have felt the need for an explicit overload of +=. Was this intended to be, or is this a feature waiting to be added?
Operators are not generated from others (except with/from <=> in C++20):
providing operator < doesn't allow a > b (which is indeed "logically" equivalent to b < a). You have to implement all (even by re-using some).
For classes, a += b is not a shorthand for a = a + b
but for a.operator +=(b) or operator +=(a, b)
In the same way a = a + b is a shorthand for a.operator=(operator +(a, b)) (or its variant)
In practice, it is more efficient to implement operator+ from operator += than the reverse.
Even if a user might expect similar behavior according to their names, they are regular functions.
I already saw a matrix iterator for which ++it increase column index whereas it++ increase row index.
If += were simply a shorthand for a = a + <rhs of +=> overloading + operator should also implicitly overload +=, unless explicitly overloaded otherwise. But that isn't what happens. That means, a += b doesn't get converted to a = a + b.
(Possible) rational to not generate might be performance and control:
Vector (for math) or Matrix are good example:
4 possible overloads
Matrix operator+(Matrix&& lhs, Matrix&& rhs) { return std::move(lhs += rhs); }
Matrix operator+(Matrix&& lhs, const Matrix& rhs) { return std::move(lhs += rhs); }
Matrix operator+(const Matrix& lhs, Matrix&& rhs) { return std::move(rhs += lhs); } // + is symmetrical :)
Matrix operator+(const Matrix& lhs, const Matrix& rhs) { auto tmp{lhs}; return tmp += rhs; }
Side effect of the decision allow to give different meanings to operators, as "name operator":
if (42 <in> std::vector{4, 8, 15, 16, 23, 42})
Using a = a + b will imply using a copy assignment (as operator = is used). On the other hand, a += b is by default a compound assignment.
According to cppreference,
copy assignment operator replaces the contents of the object a with a copy of the contents of b (b is not modified).
and
compound assignment operators replace the contents of the object a with the result of a binary operation between the previous value of a and the value of b.
Using a = a + b, would therefore cause an unnecessary memory usage, since a has to be copied once before its value is changed.

c++ Overload operator bool() gives an ambiguous overload error with operator+

I'm compiling some c++ code of a class MegaInt which is a positive decimal type class that allows arithmetic operations on huge numbers.
I want to overload operator bool to allow code like this:
MegaInt m(45646578676547676);
if(m)
cout << "YaY!" << endl;
This is what I did:
header:
class MegaInt
{
public:
...
operator bool() const;
};
const MegaInt operator+(const MegaInt & left, const MegaInt & right);
const MegaInt operator*(const MegaInt & left, const MegaInt & right);
implementation:
MegaInt::operator bool() const
{
return *this != 0;
}
const MegaInt operator+(const MegaInt & left, const MegaInt & right)
{
MegaInt ret = left;
ret += right;
return ret;
}
Now, the problem is if I do:
MegaInt(3424324234234342) + 5;
It gives me this error:
ambiguous overload for 'operator+' in 'operator+(const MegaInt&, const MegaInt&)
note: candidates are: operator+(int, int) |
note: const MegaInt operator+(const MegaInt&, const MegaInt&)|
I don't know why. How is the overloaded bool() causing operator+ to become ambiguous?¸
Thank You.
Well, everyone gave me great answers, unfortunately, none of them seem to solve my problem entirely.
Both void* or the Safe Bool Idiom works. Except for one tiny problem, I hope has a workaround:
When comparing with 0 like:
if (aMegaInt == 0)
The compiler gives an ambiguous overload error again. I understand why: it doesn't know if we're comparing to false or to MegaInt of value 0. None the less, in that case, I'd want it to cast to MegaInt(0). Is there a way to force this?
Thank You Again.
The C++ compiler is allowed to automatically convert bool into int for you, and that's what it wants to do here.
The way to solve this problem is to employ the safe bool idiom.
Technically, creating an operator void* is not an example of the safe bool idiom, but it's safe enough in practice, because the bool/int problem you're running into is a common error, and messes up some perfectly reasonable and otherwise correct code (as you see from your question), but misuses of the void* conversion are not so common.
The wikipedia entry on explicit conversion operators for C++0x has a decent summary of why you see this error pre-C++0x. Basically, the bool conversion operator is an integral conversion type, so it will be used in an integral arithmetic expression. The pre-C++0x fix is to instead use void * as the conversion operator; void * can be converted to a boolean expression, but not to an integral expression.
As Erik's answer states, the problem here is that by providing an implicit conversion to bool you are opening the door to expressions that can mean multiple things; in this case the compiler will complain of ambiguity and give your an error.
However, note that providing an implicit conversion to void* will not let you off the hook; it will just change the set of expressions which present a problem.
There are two airtight solutions to this issue:
Make the conversion to bool explicit (which can be undesirable if the class represents an entity with an intuitive "true/false" value)
Use the safe bool idiom (this really covers all bases, but as many good things in life and C++ is way too complicated -- you pay the price)
The problem is that bool can freely convert to int. So the expression MegaInt(3424324234234342) + 5; can equally validly be interpreted this way:
(bool)(MegaInt(3424324234234342)) + 5;
or:
MegaInt(3424324234234342) + MegaInt(5);
Each one of those expressions involves one user defined conversion and are equal in the eyes of the compiler. Conversion to bool is highly problematic for this reason. It would be really nice to have a way to say it should only happen in a context that explicitly requires a bool, but there isn't. :-/
The conversion to void * that someone else suggests is a workaround, but I think as a workaround it has problems of its own and I wouldn't do it.
MegaInt(3424324234234342) + 5;
MegaInt + int;
Should the compiler convert your MegaInt to an integral (bool is an integral type) or the integer to MegaInt (you have an int constructor)?
You fix this by creating an operator void * instead of an operator bool:
operator void *() const { return (*this != 0) ? ((void *) 1) : ((void *) 0); }
Others have mentioned the Safe Bool Idiom. However, for objects like yours it is a bad idea to add all this nasty, special logic when you want full algebra support anyway.
You're defining a custom integer type. You get far more for your effort by defining "operator==" and "operator!=", then implementing "operator bool()" as something like:
operator bool()
{
return (*this != 0);
}
Just from those 3 functions you get all of the "if" idioms for integers, and they'll behave the same for your custom ints as the built-in ones: "if(a==b)", "if(a!=b)", "if(a)", "if(!a)". Your implicit "bool" rule will also (if you're careful) work intuitively as well.
Besides, the full "Safe Bool Idiom" is unnecessary. Think about it- the only time you need it is "1) comparison of 2 objects is ill-defined or undefined, 2) cast to (int) or other primitive types needs to be protected and 3) object validity IS well-defined (the actual source of the returned bool)."
Well, 2) is only a consideration if you actually wish to SUPPORT casting to a numeric type like int or float. But for objects that have NO well-defined notion of equality (# 1), providing such casts unavoidably creates the risk of the very "if(a==b)" logic bombs the idiom supposedly protects you from. Just declare "operator int()" and such private like you do with the copy ctor on non-copyable objects and be done with it:
class MyClass {
private:
MyClass(const MyClass&);
operator int();
operator long();
// float(), double(), etc. ...
public:
// ctor & dtor ..
bool operator==(const MyClass& other) const { //check for equality logic... }
bool operator!=(const MyClass& other) const { return !(*this == other); }
operator bool() { return (*this != 0); }
};

Eliminating temporaries in operator overloading

Note: as noted by sellibitze I am not up-to-date on rvalues references, therefore the methods I propose contain mistakes, read his anwser to understand which.
I was reading one of Linus' rant yesterday and there is (somewhere) a rant against operator overloading.
The complaint it seems is that if you have an object of type S then:
S a = b + c + d + e;
may involve a lot of temporaries.
In C++03, we have copy elision to prevent this:
S a = ((b + c) + d) + e;
I would hope that the last ... + e is optimized, but I wonder how many temporaries are created with user defined operator+.
Someone in the thread suggested the use of Expression Templates to deal with the issue.
Now, this thread dates back to 2007, but nowadays when we think elimination of temporaries, we think Move.
So I was thinking about the set of overload operators we should write not to eliminate temporaries, but to limit the cost of their construction (stealing resources).
S&& operator+(S&& lhs, S const& rhs) { return lhs += rhs; }
S&& operator+(S const& lhs, S&& rhs) { return rhs += lhs; } // *
S&& operator+(S&& lhs, S&& rhs) { return lhs += rhs; }
Does this set of operator seems sufficient ? Is this generalizable (in your opinion) ?
*: this implementation supposes commutativity, it doesn't work for the infamous string.
If you're thinking about a custom, move-enabled string class, the proper way to exploit every combination of argument value categories is:
S operator+(S const& lhs, S const& rhs);
S operator+(S && lhs, S const& rhs);
S operator+(S const& lhs, S && rhs);
S operator+(S && lhs, S && rhs);
The functions return a prvalue instead of an xvalue. Returning xvalues is usually a very dangerous thing – std::move and std::forward are the obvious exceptions. If you were to return an rvalue reference you'd break code like:
for (char c : my_string + other_string) {
//...
}
This loop behaves (according to 6.5.4/1 in N3092) as if the code is:
auto&& range = my_string + other_string;
This in turn results in a dangling reference. The temporary object's life-time is not extended because your operator+ doesn't return a prvalue. Returning the objects by value is perfectly fine. It'll create temporary objects but these objects are rvalues, so we can steal their resources to make it very effective.
Secondly, your code should also not compile for the same reason this won't compile:
int&& foo(int&& x) { return x; }
Inside the function's body x is an lvalue and you can't initialize the "return value" (in this case the rvalue reference) with an lvalue expression. So, you'd need an explicit cast.
Thirdly, you're missing an const&+const& overload. In case both of your arguments are lvalues, the compiler won't find a usable operator+ in your case.
If you don't want so many overloads, you could also write:
S operator+(S value, S const& x)
{
value += x;
return value;
}
I intentionally didn't write return value+=x; because this operator probably returns an lvalue reference which would have led to copy construction of the return value. With the two lines I wrote the return value will be move constructed from value.
S x = a + b + c + d;
At least this case is very efficient because there is no unnecessary copying involved even if the compiler isn't able to elide the copies – thanks to a move-enabled string class. Actually, with a class like std::string you can exploit its fast swap member function and make it effective in C++03 as well provided you have a reasonably smart compiler (like GCC):
S operator+(S value, S const& x) // pass-by-value to exploit copy elisions
{
S result;
result.swap(value);
result += x;
return result; // NRVO applicable
}
See David Abraham's article Want Speed? Pass by Value. But these simple operators won't be as effective given:
S x = a + (b + (c + d));
Here the left hand side of the operator is always an lvalue. Since operator+ takes its left hand side by value this leads to many copies. The four overloads from above deal perfectly with this example, too.
It's been a while since I read Linus' old rant. If he was complaining about unnecessary copies with respect to std::string, this complaint is no longer valid in C++0x, but it was hardly valid before. You can efficiently concatenate many strings in C++03:
S result = a;
result += b;
result += c;
result += d;
But in C++0x you can also use operator+ and std::move. This will be very efficient, too.
I actually looked at the Git source code and its string management (strbuf.h). It looks well thought through. Except for the detach/attach feature you get the same thing with a move-enabled std::string with the obvious advantage that the resource it automatically managed by the class itself as opposed to the user who needs to remember to call the right functions at the right times (strbuf_init, strbuf_release).

What is an overloaded operator in C++?

I realize this is a basic question but I have searched online, been to cplusplus.com, read through my book, and I can't seem to grasp the concept of overloaded operators. A specific example from cplusplus.com is:
// vectors: overloading operators example
#include <iostream>
using namespace std;
class CVector {
public:
int x,y;
CVector () {};
CVector (int,int);
CVector operator + (CVector);
};
CVector::CVector (int a, int b) {
x = a;
y = b;
}
CVector CVector::operator+ (CVector param) {
CVector temp;
temp.x = x + param.x;
temp.y = y + param.y;
return (temp);
}
int main () {
CVector a (3,1);
CVector b (1,2);
CVector c;
c = a + b;
cout << c.x << "," << c.y;
return 0;
}
From http://www.cplusplus.com/doc/tutorial/classes2/ but reading through it I'm still not understanding them at all. I just need a basic example of the point of the overloaded operator (which I assume is the "CVector CVector::operator+ (CVector param)").
There's also this example from wikipedia:
Time operator+(const Time& lhs, const Time& rhs)
{
Time temp = lhs;
temp.seconds += rhs.seconds;
if (temp.seconds >= 60)
{
temp.seconds -= 60;
temp.minutes++;
}
temp.minutes += rhs.minutes;
if (temp.minutes >= 60)
{
temp.minutes -= 60;
temp.hours++;
}
temp.hours += rhs.hours;
return temp;
}
From "http://en.wikipedia.org/wiki/Operator_overloading"
The current assignment I'm working on I need to overload a ++ and a -- operator.
Thanks in advance for the information and sorry about the somewhat vague question, unfortunately I'm just not sure on it at all.
Operator overloading is the technique that C++ provides to let you define how the operators in the language can be applied to non-built in objects.
In you example for the Time class operator overload for the + operator:
Time operator+(const Time& lhs, const Time& rhs);
With that overload, you can now perform addition operations on Time objects in a 'natural' fashion:
Time t1 = some_time_initializer;
Time t2 = some_other_time_initializer;
Time t3 = t1 + t2; // calls operator+( t1, t2)
The overload for an operator is just a function with the special name "operator" followed by the symbol for the operator being overloaded. Most operators can be overloaded - ones that cannot are:
. .* :: and ?:
You can call the function directly by name, but usually don't (the point of operator overloading is to be able to use the operators normally).
The overloaded function that gets called is determined by normal overload resolution on the arguments to the operator - that's how the compiler knows to call the operator+() that uses the Time argument types from the example above.
One additional thing to be aware of when overloading the ++ and -- increment and decrement operators is that there are two versions of each - the prefix and the postfix forms. The postfix version of these operators takes an extra int parameter (which is passed 0 and has no purpose other than to differentiate between the two types of operator). The C++ standard has the following examples:
class X {
public:
X& operator++(); //prefix ++a
X operator++(int); //postfix a++
};
class Y { };
Y& operator++(Y&); //prefix ++b
Y operator++(Y&, int); //postfix b++
You should also be aware that the overloaded operators do not have to perform operations that are similar to the built in operators - being more or less normal functions they can do whatever you want. For example, the standard library's IO stream interface uses the shift operators for output and input to/from streams - which is really nothing like bit shifting. However, if you try to be too fancy with your operator overloads, you'll cause much confusion for people who try to follow your code (maybe even you when you look at your code later).
Use operator overloading with care.
An operator in C++ is just a function with a special name. So instead of saying Add(int,int) you say operator +(int,int).
Now as any other function, you can overload it to say work on other types. In your vector example, if you overload operator + to take CVector arguments (ie. operator +(CVector, CVector)), you can then say:
CVector a,b,res;
res=a+b;
Since ++ and -- are unary (they take only one argument), to overload them you'd do like:
type operator ++(type p)
{
type res;
res.value++;
return res;
}
Where type is any type that has a field called value. You get the idea.
What you found in those references are not bad examples of when you'd want operator overloading (giving meaning to vector addition, for example), but they're horrible code when it comes down to the details.
For example, this is much more realistic, showing delegating to the compound assignment operator and proper marking of a const member function:
class Vector2
{
double m_x, m_y;
public:
Vector2(double x, double y) : m_x(x), m_y(y) {}
// Vector2(const Vector2& other) = default;
// Vector2& operator=(const Vector2& other) = default;
Vector2& operator+=(const Vector2& addend) { m_x += addend.m_x; m_y += addend.m_y; return *this; }
Vector2 operator+(const Vector2& addend) const { Vector2 sum(*this); return sum += addend; }
};
From your comments above, you dont see the point of all this operator overloading?
Operator overloading is simply 'syntactic sugar' hiding a method call, and making code somehwhat clearer in many cases.
Consider a simple Integer class wrapping an int. You would write add and other arithmetic methods, possibly increment and decrement as well, requiring a method call such as my_int.add(5). now renaming the add method to operator+ allows my_int + 5, which is more intuitive and clearer, cleaner code. But all it is really doing is hiding a call to your operator+ (renamed add?) method.
Things do get a bit more complex though, as operator + for numbers is well understood by everyone above 2nd grade. But as in the string example above, operators should usually only be applied where they have an intuitive meaning. The Apples example is a good example of where NOT to overload operators.
But applied to say, a List class, something like myList + anObject, should be intuitively understood as 'add anObject to myList', hence the use of the + operator. And operator '-' as meaning 'Removal from the list'.
As I said above, the point of all this is to make code (hopefully) clearer, as in the List example, which would you rather code? (and which do you find easier to read?) myList.add( anObject ) or myList + onObject? But in the background, a method (your implementation of operator+, or add) is being called either way. You can almost think of the compiler rewritting the code: my_int + 5 would become my_int.operator+(5)
All the examples given, such as Time and Vector classes, all have intuitive definitions for the operators. Vector addition... again, easier to code (and read) v1 = v2 + v3 than v1 = v2.add(v3). This is where all the caution you are likely to read regarding not going overboard with operators in your classes, because for most they just wont make sense. But of course there is nothing stopping you putting an operator & into a class like Apple, just dont expect others to know what it does without seeing the code for it!
'Overloading' the operator simply means your are supplying the compiler with another definition for that operator, applied to instances of your class. Rather like overloading methods, same name... different parameters...
Hope this helps...
The "operator" in this case is the + symbol.
The idea here is that an operator does something. An overloaded operator does something different.
So, in this case, the '+' operator, normally used to add two numbers, is being "overloaded" to allow for adding vectors or time.
EDIT: Adding two integers is built-in to c++; the compiler automatically understands what you mean when you do
int x, y = 2, z = 2;
x = y + z;
Objects, on the other hand, can be anything, so using a '+' between two objects doesn't inherently make any sense. If you have something like
Apple apple1, apple2, apple3;
apple3 = apple1 + apple2;
What does it mean when you add two Apple objects together? Nothing, until you overload the '+' operator and tell the compiler what it is that you mean when you add two Apple objects together.
An overloaded operator is when you use an operator to work with types that C++ doesn't "natively" support for that operator.
For example, you can typically use the binary "+" operator to add numeric values (floats, ints, doubles, etc.). You can also add an integer type to a pointer - for instance:
char foo[] = "A few words";
char *p = &(foo[3]); // Points to "e"
char *q = foo + 3; // Also points to "e"
But that's it! You can't do any more natively with a binary "+" operator.
However, operator overloading lets you do things the designers of C++ didn't build into the language - like use the + operator to concatenate strings - for instance:
std::string a("A short"), b(" string.");
std::string c = a + b; // c is "A short string."
Once you wrap your head around that, the Wikipedia examples will make more sense.
A operator would be "+", "-" or "+=". These perform different methods on existing objects. This in fact comes down to a method call. Other than normal method calls these look much more natural to a human user. Writing "1 + 2" just looks more normal and is shorter than "add(1,2)". If you overload an operator, you change the method it executes.
In your first example, the "+" operator's method is overloaded, so that you can use it for vector-addition.
I would suggest that you copy the first example into an editor and play a little around with it. Once you understand what the code does, my suggestion would be to implement vector subtraction and multiplication.
Before starting out, there are many operators out there! Here is a list of all C++ operators: list.
With this being said, operator overloading in C++ is a way to make a certain operator behave in a particular way for an object.
For example, if you use the increment/decrement operators (++ and --) on an object, the compiler will not understand what needs to be incremented/decremented in the object because it is not a primitive type (int, char, float...). You must define the appropriate behavior for the compiler to understand what you mean. Operator overloading basically tells the compiler what must be accomplished when the increment/decrement operators are used with the object.
Also, you must pay attention to the fact that there is postfix incrementing/decrementing and prefix incrementing/decrementing which becomes very important with the notion of iterators and you should note that the syntax for overloading these two type of operators is different from each other. Here is how you can overload these operators: Overloading the increment and decrement operators
The accepted answer by Michael Burr is quite good in explaining the technique, but from the comments it seems that besides the 'how' you are interested in the 'why'. The main reasons to provide operator overloads for a given type are improving readability and providing a required interface.
If you have a type for which there is a single commonly understood meaning for an operator in the domain of your problem, then providing that as an operator overload makes code more readable:
std::complex<double> a(1,2), b(3,4), c( 5, 6 );
std::complex<double> d = a + b + c; // compare to d = a.add(b).add(c);
std::complex<double> e = (a + d) + (b + c); // e = a.add(d).add( b.add(c) );
If your type has a given property that will naturally be expressed with an operator, you can overload that particular operator for your type. Consider for example, that you want to compare your objects for equality. Providing operator== (and operator!=) can give you a simple readable way of doing so. This has the advantage of fulfilling a common interface that can be used with algorithms that depend on equality:
struct type {
type( int x ) : value(x) {}
int value;
};
bool operator==( type const & lhs, type const & rhs )
{ return lhs.value == rhs.value; }
bool operator!=( type const & lhs, type const & rhs )
{ return !lhs == rhs; }
std::vector<type> getObjects(); // creates and fills a vector
int main() {
std::vector<type> objects = getObjects();
type t( 5 );
std::find( objects.begin(), objects.end(), t );
}
Note that when the find algorithm is implemented, it depends on == being defined. The implementation of find will work with primitive types as well as with any user defined type that has an equality operator defined. There is a common single interface that makes sense. Compare that with the Java version, where comparison of object types must be performed through the .equals member function, while comparing primitive types can be done with ==. By allowing you to overload the operators you can work with user defined types in the same way that you can with primitive types.
The same goes for ordering. If there is a well defined (partial) order in the domain of your class, then providing operator< is a simple way of implementing that order. Code will be readable, and your type will be usable in all situations where a partial order is required, as inside associative containers:
bool operator<( type const & lhs, type const & rhs )
{
return lhs < rhs;
}
std::map<type, int> m; // m will use the natural `operator<` order
A common pitfall when operator overloading was introduced into the language is that of the 'golden hammer' Once you have a golden hammer everything looks like a nail, and operator overloading has been abused.
It is important to note that the reason for overloading in the first place is improving readability. Readability is only improved if when a programmer looks at the code, the intentions of each operation are clear at first glance, without having to read the definitions. When you see that two complex numbers are being added like a + b you know what the code is doing. If the definition of the operator is not natural (you decide to implement it as adding only the real part of it) then code will become harder to read than if you had provided a (member) function. If the meaning of the operation is not well defined for your type the same happens:
MyVector a, b;
MyVector c = a + b;
What is c? Is it a vector where each element i is the sum of of the respective elements from a and b, or is it a vector created by concatenating the elements of a before the elements of b. To understand the code, you would need to go to the definition of the operation, and that means that overloading the operator is less readable than providing a function:
MyVector c = append( a, b );
The set of operators that can be overloaded is not restricted to the arithmetic and relational operators. You can overload operator[] to index into a type, or operator() to create a callable object that can be used as a function (these are called functors) or that will simplify usage of the class:
class vector {
public:
int operator[]( int );
};
vector v;
std::cout << v[0] << std::endl;
class matrix {
public:
int operator()( int row, int column );
// operator[] cannot be overloaded with more than 1 argument
};
matrix m;
std::cout << m( 3,4 ) << std::endl;
There are other uses of operator overloading. In particular operator, can be overloaded in really fancy ways for metaprogramming purposes, but that is probably much more complex than what you really care for now.
Another use of operator overloading, AFAIK unique to C++, is the ability to overload the assignment operator. If you have:
class CVector
{
// ...
private:
size_t capacity;
size_t length;
double* data;
};
void func()
{
CVector a, b;
// ...
a = b;
}
Then a.data and b.data will point to the same location, and if you modify a, you affect b as well. That's probably not what you want. But you can write:
CVector& CVector::operator=(const CVector& rhs)
{
delete[] data;
capacity = length = rhs.length;
data = new double[length];
memcpy(data, rhs.data, length * sizeof(double));
return (*this);
}
and get a deep copy.
Operator overloading allows you to give own meaning to the operator.
For example, consider the following code snippet:
char* str1 = "String1";
char* str2 = "String2";
char str3[20];
str3 = str1 + str2;
You can overload the "+" operator to concatenate two strings. Doesn't this look more programmer-friendly?

Canonical operator overloading?

Is there a canonical or recommended pattern for implementing arithmetic operator overloading in C++ number-like classes?
From the C++ FAQ, we have an exception-safe assignment operator that avoids most problems:
class NumberImpl;
class Number {
NumberImpl *Impl;
...
};
Number& Number::operator=(const Number &rhs)
{
NumberImpl* tmp = new NumberImpl(*rhs.Impl);
delete Impl;
Impl = tmp;
return *this;
}
But for other operators (+, +=, etc..) very little advice is given other than to make them behave like the operators on built-in types.
Is there a standard way of defining these? This is what I've come up with - are there pitfalls I'm not seeing?
// Member operator
Number& Number::operator+= (const Number &rhs)
{
Impl->Value += rhs.Impl->Value; // Obviously this is more complicated
return *this;
}
// Non-member non-friend addition operator
Number operator+(Number lhs, const Number &rhs)
{
return lhs += rhs;
}
In Bjarne Stroustrup's book "The C++ Programming Language", in chapter 11 (the one devoted to Operator Overloading) he goes through witting a class for a complex number type (section 11.3).
One thing I do notice from that section is that he implements mixed type operations... this is probably expected for any numeric class.
In general, what you've got looks good.
The big thing to consider when writing any operator is that member operators do not undergo conversions on the left parameter:
struct example {
example(int);
example operator + (example);
};
void foo() {
example e(3), f(6);
e + 4; // okay: right operand is implicitly converted to example
e + f; // okay: no conversions needed.
6 + e; // BAD: no matching call.
}
This is because conversion never applies to this for member functions, and this extends to operators. If the operator was instead example operator + (example, example) in the global namespace, it would compile (or if pass-by-const-ref was used).
As a result, symmetric operators like + and - are generally implemented as non-members, whereas the compound assignment operators like += and -= are implemented as members (they also change data, meaning they should be members). And, since you want to avoid code duplication, the symmetric operators can be implemented in terms of the compound assignment ones (as in your code example, although convention recommends making the temporary inside the function).
The convention is to write operator+(const T&) and operator-(const T&) in terms of operator+=(const T&) and operator-=(const T&). If it makes sense to add and subtract to/from primitive types then you should write a constructor that constructs the object from the primitive type. Then the overloaded operators will also work for primitive types, because the compiler will call the appropriate constructor implicitly.
As you mentioned yourself, you should avoid giving access privileges to functions that don't need it. But in your code above for operator+(Number, const Number&) I'd personally make both parameters const references and use a temp. I think it isn't surprising the commenter below your question missed this; unless you have a good reason not to, avoid surprises and tricks and be as obvious as possible.
If you want your code to integrate with other numeric types, say std::complex, watch out for cyclic conversions. That is, don't supply operator OtherNumeric() in Numeric if OtherNumeric supplies a constructor that takes a Numeric parameter.
It is traditional to write the operator X in terms of the operator =X
It is also traditional the all parameters to the standard operators are const
// Member operator
// This was OK
Number& Number::operator+= (Number const& rhs)
{
Impl->Value += rhs.Impl->Value; // Obviously this is more complicated
return *this;
}
// Non-member non-friend addition operator
Number operator+(Number const& lhs,Number const& rhs)
{
// This I would set the lhs side to const.
// Make a copy into result.
// Then use += add the rhs
Number result(lhs);
return result += rhs;
}
You mention assignment operator.
But you did not mention the copy constructor. Since your class has ownership of a RAW pointer I would expect you to define this as well. The Assignment operator is then traditionally written in terms of the copy constructor.