When and why do we overload operators in C++ - c++

I'm new to C++ and my questions are: Why do we need to overload operators in C++ and when should we overload operators in C++, why don't we just use built-in variables to do calculations, comparison, output and input value. I just don't get it, what is the most appropriate situation where we would need to overload operators or should we always overload operators when dealing with classes?

If you look at a lot of C++ sources, you'd probably conclude
that the most frequent use of operator overloading (or
overloading in general, for that matter) is obfuscation.
Still...
First and foremost: in a number of cases, you'll have to
overload the assignment operator. The compiler will generate
one for you if you don't, and in a number of cases, the
generated one won't do what you want. (It's also frequent to
declare a private overloaded assignment, and not implement it,
in order to block assignment.)
If a class represents some sort of numerical value (e.g.
BigInteger or Decimal), then it definitely makes sense to
overload the arithmetic operators. It's a lot more readable to
write:
BigFloat
discriminant( BigFloat const& a, BigFloat const& b, BigFloat const& c )
{
return b*b - 4*a*c
}
than
BigFloat
discriminant( BigFloat const& a, BigFloat const& b, BigFloat const& c )
{
return sub(mult(b, b), mult(4, mult( a, c )));
}
In such cases, you should always overload all applicable
operators, with their natural meanings: it would be very uncool
if your type supported +, but not +=, or if it supported +
with the semantics of subtraction.
There are few legitimate extensions with regards to the
arithmetic operators: about the only one I'd find acceptable is
a string class using + (and +=) for concatenation.
(Normally, I'd expect + to be commutative, which concatenation
certainly isn't. But the convention is so well established in
languages that have built-in string types that you can hardly
avoid it.)
Types that are comparable should support == and !=, and if
there is a logical ordering, <, <=, > and >=. (On the
other hand, overloading < when there is only an arbitrary
ordering, just so you can call std::sort without an comparison
operator, is obfuscation.) Again, it's much more natural to
write a < b than isLessThan( a, b ). It's sometimes
difficult to decide: when I first started C++, I had a Set
class, based on bitmaps, and I defined < to be a strict
subset, <= a subset, etc. I don't know if I'd do this again;
the inequality operators should probably only be defined if the
relationship is transitive.
Beyond that, any time your type emulates in some way something
built in, like a pointer or an array, you will probably want to
overload the corresponding supported operators: a vector or an
array class which didn't support [] would be surprizing, as
would be a smart pointer which didn't support * and ->.
And finally, there are some standard C++ idioms which use
operator overloading:
If you define a type which can be inserted or extracted from a text stream, you do so by defining the << and >> operators.
C++ iterators are designed to look like pointers; if you want
iterators which can be used with the standard algorithms, they
should support the same operators as those of a smart pointer,
along with ++, and possibly --, and in some cases, all of
the pointer arithmetic operators (including [], which is
defined in terms of pointer arithmetic on raw pointers). This
is clearly obfuscation, and it certainly makes using the
iterators unnecessarily complicated, but it's hard to avoid if
you're using the C++ standard library.
The C++ library also makes extensive use of functional
objects, with an operator() (a function call operator).
Predicate objects have an operator() which returns a bool.
(One of the most frequent uses of predicate objects is to
implement an ordering relationship. If your class doesn't
support a logical < operator, you might want to provide
a separate functional object which defines an arbitrary order,
so that objects can still be inserted into std::set, or be
used as a key in std::map.) Arguably, this too should have
been a named function, but it's hard to imagine a good name that
would apply everywhere, and since the object does behave like
a function, it's not really too bad.
There are probably one or two other cases I've forgotten, but in
general, with regards to operator overloading, when in doubt,
don't.

Related

Overloading operator without having a class

Can we use operator overloading on non-objects? e.g adding two vector<int>. Or do I need to make a class having vector<int> and then overload the + operator.
Also, I want to know if it is possible to have 2 different types of operands in a binary operator. If yes, how?
Can we use operator overloading on non-objects?
Operators are essentially implemented as functions and can accept a similar range of types as functions do.
There are a few restrictions, in particular, it is limited by the fact that at least one argument must be a class or enum (user or library type).
In addition, there are some operators that have to be implemented as member functions, so they will be associated with a class, but many can be declared and defined outside of a class.
The exact number of arguments is determined by the operator being implemented. Unary operators accept 1 argument, binary operators accept 2 arguments.
Generally, the advice is to offer behaviour similar to the canonical forms, but the language itself does not limit your implementation to just that behaviour.
Also, I want to know if it is possible to have 2 different types of operands in a binary operator. If yes, how?
Yes. Again, just as functions do.
Can we use operator overloading on non-objects? e.g adding two vector.
I think you meant to ask whether it's possible to use operator overloading outside of a class definition. And yes, it definitely is possible as already stated by other people here. Here's a simple example of overloading the '+' operator for a custom 'MyClass' type:
MyClass operator+(const MyClass& a, const MyClass& b)
{
return MyClass(a.value + b.value);
}
However, there is a reason why std::vector doesn't have overloads for arithmetic operators as the result is ambiguous. Do you want '+' to link two vectors together or should the components be added? How do you handle vectors which differ in size? Often, containers of the STL provide special methods for these purposes and don't rely on operators when it's not clear so make sure you've checked the specification of std::vectors
You're free to implement such operators as you see fit, especially with your own types but you risk creating unintuitive behaviour and ultimately, bad code. In the case of std::vector, it might be better to write a function with a descriptive name which operates on std::vector in the way you desire:
std::vector<int> addComponents(const std::vector<int>& a, const std::vector<int>& b);
Can we use operator overloading on non-objects? e.g adding two vector[?]
The premise of your question is broken, because a vector<int> is an object.
Overload all you like.
Also, i want to know if it is possible to have 2 different types of operands in a binary operator.
Try it.
If yes, how?
By typing it.

Style guideline/convention for defining binary operator in a class (C++)

This is a bit of a general question, but I have some classes that I'd like to define some binary "operations" on, and there are several different ways of doing so. For example, suppose I have a Vector class that I'd like to implement an addition operation on. On one hand, I could just overload the '+' operator, but I have read from a few sources that this isn't a very good practice (which begs one to ask why this is a language feature at all). I can see in many cases why methods are preferable to operator overloading, but vector addition is widely agreed upon and so using '+' should be very natural.
On the other hand, I could define an add() method in the class. I could just define it as a normal method and use x.add(y) to perform x + y, but it doesn't showcase itself as a binary operator so I'm not sure if this should be preferred. I could also define it as a static method, for instance Vector.add(x, y). Finally, I could also define add() as a friend function of the class, which is very (mathematically) natural but in my opinion is a bit contrary to the philosophy of OOP. I'm hoping to get a bit of insight into which methods are preferable (and why).
The usual approach is to define reflexive operators (+=, *=, etc.) as members that modify the object they are applied to, and to define non-reflexive operators (+, *, etc.) as non-members that create a copy of one of their arguments, use the corresponding reflexive operator to do the operation, and return the new object as their result.
While Java programmers believe that add functions are a good thing, they do so because Java doesn't have operator overloading. Named operations lead to really long and unreadable expressions for things that should be simple.
The advantage to defining your binary operator as a friend function (potentially as a set of overloads) is to permit the left-hand value to be other than an instance of your class. This is commonly done for stream inserters/extractors. Note that the friend status is only necessary if your operator requires access to the internals of one of its operands. It's best if the operator can work through the public interfaces of each operand, avoiding the need for friend and the resulting tighter coupling.

Why not overload operator+=() for std::vector?

I've started learning C++, so I don't know in my lack of knowledge/experience why something so seemingly simple to a rookie as what I'm about to describe isn't already in the STL. To add a vector to another vector you have to type this:
v1.insert(v1.end(), v2.begin(), v2.end());
I'm wondering whether in the real world people just overload the += operator to make this less verbose, for example to the effect of
template <typename T>
void operator+=(std::vector<T> &v1, const std::vector<T> &v2) {
v1.insert(v1.end(), v2.begin(), v2.end());
}
so then you can
v1 += v2;
I also have this set up for push_back to "+=" a single element to the end. Is there some reason these things should not be done or are specifically avoided by people who are proficient in C++?
This is actually a case where I would like to see this functionality in the form of an overload of append(). operator+= is kinda ambiguous, do you mean to add the elements of each vector to each other? Or you mean to append?
However, like I said, I would have welcomed: v1.append(v2); It is clear and simple, I don't know why it isn't there.
I think the main reason is that the semantics of += aren't obvious. There's the meaning that you have here, but there's also an equally valid meaning, which is element-wise addition of each element of equal-sized vectors. Due to this ambiguity I assume they decided it was better to rely on the user to call insert diretly.
Operators should be overloaded only when you are not changing the meaning of those operators.*
What that means is, for example, if there is no mathematical definition of the product of two objects, don't overload the multiplication operator for those objects. If there was a mathematical correspondence, operators overloading can make a class more convenient to use by allowing equations to be expressed in the form a*b + c rather than the more verbose (a.multiply(b)).add(c) Where addition and multiplication operators are used, addition and multiplication should be the intent. Any other meaning is more than likely to confuse others. Some other types where overloading operators is acceptable (and, in my opinion, preferable) are smart pointers, iterators, complex numbers, vectors, and bignums.
This follows from one of the design goals of C++, that it should be possible to define classes that are as easy to use as built in types. Of course there are operators you can define on classes which are not mathematical concepts either. You may wish to overload the == and != operators instead of writing an isEqual method, and might want to overload = because the compiler's default assignment operator is not what you want.
On the other hand, overloading an operator to do something unexpected, like defining ^ to translate a string to Japanese, is obscure and dangerous. Your fellow programmers will not be happy to find out that what looked like an exclusive or comparison was actually something very different. The solution then is to write your classes to make it easy to write clear and maintainable code, whether that means using operator overloading or avoiding it.
Adding two vectors is too ambiguous to warrent defining an operator. As others have shown, many people have different ideas of what this means, whereas for a string it is universally understood that adding two strings together means concatenation. In your example, it isn't entirely clear whether you want to do a component wise add on all the elements, add an element to the end, or concat two vectors together. Although it may be more concise to do it that way, using operator overloading to create your own programming language isn't the best way to go.
*Yes, I know Stroustrup overloaded << and >> to do stream operations rather than bitshifts. But those weren't used often compared to arithmetic and pointer operators in the first place, and it could be argued that now that everyone knows how to use cout, it's generally understood that << and >> are the inserter and extractor operators. (He originally tried to use just < and > for input and output, but the meaning of those operators was so ingrained in everyone's minds that the code was unreadable.)
In addition to what others mentioned about this syntax not being intuitive and therefore error prone, it also goes against a good design rule making general algorithms applied to various containers free functions, and container specific algorithms -- member functions. Most containers follow this rule, except std::string, which got a lot of flack from Herb Sutter for its monolithic design.

How to dis-ambiguate operator definitions between objects/classes in a programming language?

I'm designing my own programming language (called Lima, if you care its on www.btetrud.com), and I'm trying to wrap my head around how to implement operator overloading. I'm deciding to bind operators on specific objects (its a prototype based language). (Its also a dynamic language, where 'var' is like 'var' in javascript - a variable that can hold any type of value).
For example, this would be an object with a redefined + operator:
x =
{ int member
operator +
self int[b]:
ret b+self
int[a] self:
ret member+a
}
I hope its fairly obvious what that does. The operator is defined when x is both the right and left operand (using self to denote this).
The problem is what to do when you have two objects that define an operator in an open-ended way like this. For example, what do you do in this scenario:
A =
{ int x
operator +
self var[b]:
ret x+b
}
B =
{ int x
operator +
var[a] self:
ret x+a
}
a+b ;; is a's or b's + operator used?
So an easy answer to this question is "well duh, don't make ambiguous definitions", but its not that simple. What if you include a module that has an A type of object, and then defined a B type of object.
How do you create a language that guards against other objects hijacking what you want to do with your operators?
C++ has operator overloading defined as "members" of classes. How does C++ deal with ambiguity like this?
Most languages will give precedence to the class on the left. C++, I believe, doesn't let you overload operators on the right-hand side at all. When you define operator+, you are defining addition for when this type is on the left, for anything on the right.
In fact, it would not make sense if you allowed your operator + to work for when the type is on the right-hand side. It works for +, but consider -. If type A defines operator - in a certain way, and I do int x - A y, I don't want A's operator - to be called, because it will compute the subtraction in reverse!
In Python, which has more extensive operator overloading rules, there is a separate method for the reverse direction. For example, there is a __sub__ method which overloads the - operator when this type is on the left, and a __rsub__ which overloads the - operator when this type is on the right. This is similar to the capability, in your language, to allow the "self" to appear on the left or on the right, but it introduces ambiguity.
Python gives precedence to the thing on the left -- this works better in a dynamic language. If Python encounters x - y, it first calls x.__sub__(y) to see if x knows how to subtract y. This can either produce a result, or return a special value NotImplemented. If Python finds that NotImplemented was returned, it then tries the other way. It calls y.__rsub__(x), which would have been programmed knowing that y was on the right hand side. If that also returns NotImplemented, then a TypeError is raised, because the types were incompatible for that operation.
I think this is the ideal operator overloading strategy for dynamic languages.
Edit: To give a bit of a summary, you have an ambiguous situation, so you really only three choices:
Give precedence to one side or the other (usually the one on the left). This prevents a class with a right-side overload from hijacking a class with a left-side overload, but not the other way around. (This works best in dynamic languages, as the methods can decide whether they can handle it, and dynamically defer to the other one.)
Make it an error (as #dave is suggesting in his answer). If there is ever more than one viable choice, it is a compiler error. (This works best in static languages, where you can catch this thing in advance.)
Only allow the left-most class to define operator overloads, as in C++. (Then your class B would be illegal.)
The only other option is to introduce a complex system of precedence to the operator overloads, but then you said you want to reduce the cognitive overhead.
I'm going to answer this question by saying "duh, don't make ambiguous definitions".
If I recreate your example in C++ (using a function f instead of the + operator and int/float instead of A/B, but there really isn't much difference)...
template<class t>
void f(int a, t b)
{
std::cout << "me! me! me!";
}
template<class t>
void f(t a, float b)
{
std::cout << "no, me!";
}
int main(void)
{
f(1, 1.0f);
return 0;
}
...the compiler will tell me precisely that: error C2668: 'f' : ambiguous call to overloaded function
If you create a language powerful enough, it's always going to be possible to create things in it that don't make sense. When this happens, it's probably ok to just throw up your hands and say "this doesn't make sense".
In C++, a op b means a.op(b), so it's unambigious; the order settles it. If, in C++, you want to define an operator whose left operand is a built-in type, then the operator has to be a global function with two arguments, not a member; again, though, the order of the operands determines which method to call. It is illegal to define an operator where both operands are of built-in types.
I would suggest that given X + Y, the compiler should look for both X.op_plus(Y) and Y.op_added_to(X); each implementation should include an attribute indicating whether it should be a 'preferred', 'normal', 'fallback' implementation, and optionally also indicating that it is "common". If both implementations are defined, and they implementations are of different priorities (e.g. "preferred" and "normal"), use the type to select a preference. If both are defined to be of the same priority, and both are "common", favor the X.op_plus(Y) form. If both are defined with the same priority and they are not both "common", flag an error.
I would suggest that the ability to prioritize overloads and conversions would IMHO a very important feature for a language to have. It is not helpful for languages to squawk about ambiguous overloads in cases where both candidates would do the same thing, but languages should squawk in cases where two possible overloads would have different meanings, each of which would be useful in certain contexts. For example, given someFloat==someDouble or someDouble==someLong, a compiler should squawk, since there can be usefulness to knowing whether the numerical quantities represented by two values match, and there can also be usefulness in knowing whether the left-hand operand holds the best possible representation (for its type) of the value in the right-hand operand. Java and C# do not flag ambiguity in either case, opting instead to use the first meaning for the first expression and the second for the second, even though either meaning might be useful in either case. I would suggest that it would be better to reject such comparisons than to have them implement inconsistent semantics.
Overall, I'd suggest as a philosophy that a good language design should let a programmer indicate what's important and what isn't. If a programmer knows that certain "ambiguities" aren't problems, but other ones are, it should be easy to have the compiler flag the latter but not the former.
Addendum
I looked briefly through your proposal; it sees you're expecting bindings to be fully dynamic. I've worked with a language like that (HyperTalk, circa 1988) and it was "interesting". Consider, for example, that "2X" < "3" < 4 < 10 < "11" < "2X". Double dispatch can sometimes be useful, but only in cases where operators overloads with different semantics (e.g. string and numeric comparisons) are limited to operating on disjoint sets of things. Forbidding ambiguous operations at compile time is a good thing, since the programmer will be in a position to specify what's intended. Having such ambiguity trigger a run-time error is a bad thing, because the programmer may be long gone by the time an error surfaces. Consequently, I really can't offer any advice for how to do run-time double dispatch for operators except to say "don't", unless at compile time you restrict the operands to combinations where any possible overload would always have the same semantics.
For example, if you had an abstract "immutable list of numbers" type, with a member to report the length or return the number at a particular index, you could specify that two instances are equal if they have the same length, and every for every index they return the same number. While it would be possible to compare any two instances for equality by examining every item, that could be inefficient if e.g. one instance was a "BunchOfZeroes" type which simply held an integer N=1000000 and didn't actually store any items, and the other was an "NCopiesOfArray" which held N=500000 and {0,0} as the array to be copied. If many instances of those types are going to be compared, efficiency could be improved by having such comparisons invoke a method which, after checking overall array length, checks whether the "template" array contains any non-zero elements. If it doesn't, then it can be reported as equal the bunch-of-zeroes array without having to perform 1,000,000 element comparisons. Note that the invocation of such a method by double dispatch would not alter the program's behavior--it would merely allow it to execute more quickly.

operator overloading c++

When overloading operators, is it necessary to overload >= <= and !=?
It seems like it would be smart for c++ to call !operator= for !=, !> for operator<= and !< for operator>=.
Is that the case, or is it necessary to overload every function?
Boost operators might be what you are looking for. These will derive most of your operators based on a few fundamental ones.
That C++ does not provide this automatically makes sense, as one could give totally different meanings to < and >, for example (although it would often be a bad idea).
I am going to take a minority viewpoint here. If you already use boost then using boost operators is not that big of a deal. It may be the correct and tested way to do things but adding boost dependency just for the operators is an overkill.
It is possible to write complex C++ programs without boost (which I personally find aesthetically unpleasant) and so to Keep It Simple (Stupid), to answer OP's question, if you overload operator ==, you should also overload operator !=. Same is true for <, >, ++ etc.
Yes, it is necessary, if you want all of them to work the way you want them to work.
C++ does not force any specific semantics on most of the overloadable operators. The only thing that is fixed is the general syntax for the operator (including being unary or binary and things like precedence and associativity). This immediately means that the actual functionality that you implement in your overload can be absolutely arbitrary. In general case there might not be any meaningful connection between what operator == does and what operator != does. Operator == might write data to a file, while operator != might sort an array.
While overloading operators in such an arbitrary fashion is certainly not a good programming practice, the C++ language cannot assume anything. So, no, it cannot and will not automatically use ! == combination in place of !=, or ! > combination in place of <=.
No, you only need to overload operator == and operator <, the standard library will take care of the rest :)
(EDIT: see using namespace std::rel_ops ;)
Yes it is necessary to overload whichever operators you want to be used as you define them - C++ will not make the decision you describe above; however, keep in mind that if the reason you are overloading is to sort your class, than you only need to override the operators used by the sort routine. In the case of the RTL sort algorithm you only need to override < and =.
Yes! They are each technically different operators. C++ compilers are not inherently inference engines, they are parsers/compilers. They will only do as much as you say to do.
http://www.parashift.com/c++-faq-lite/operator-overloading.html, http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B
There are a few shortcuts you can use, such as CRTP to get them automatically injected (see the various Compare classes) into your class.
C++ does not, as a language, define any operator in terms of any other overloaded operator. Just because you have operator+, doesn't mean you get operator+= for free (unlike Ruby and Scala). Just because you have operator < and == doesn't mean you get <= for free. Just because you have operator == doesn't mean you get != for free (unlike Ruby and Scala). Just because you have unary operator * (unary) doesn't mean you get operator -> for free.
std::relops (if imported correctly) and provide default definitions, and Boost provides some mix-ins that define all of the comparison operators in terms of < and ==.
You can use overloading to use user defined names.
Operator overloading means using the same operator to do perform operation on different items which are not in that category. Function overloading means using the same name of function but different arguments, so as to overcome the overhead when the same function is called during looping.