2

I've been going through Deitel's C++ Fundamentals and mr. Deitel accented on overloading standard operators to provide standard functionality to custom classes and their members. What I mean is for example instead of cout << object.memberFunction(); I can simply say cout << object;

This technique does allow chaining and quicker typing, but it requires operator overloading implementation and even thou I am still a newb, I fell like the code actually gets less readable, especially if there are many class members you have to remember which ones are operators overloaded for and so on. Without overloaded operators code is much more readable plus you save the overloading code.

So my question is whether I should take the time to learn operator overloading? I am new to C++ and answers from people with more practice and experience is welcome. Will the benefits of operator overloading outweigh the efforts to implement it and the reduced code readability?

dtech
  • 47,916
  • 17
  • 112
  • 190
  • [This](http://stackoverflow.com/questions/4421706/operator-overloading) excellent FAQ should be a good read. – Alok Save Oct 27 '11 at 08:57

5 Answers5

4

You should of course take the time to learn operator overloading. This however doesn't mean you should or shouldn't use operator overloading. But without learning, you can't really decide. Deciding on using something you're not familiar with is difficult if not impossible. You'll always find something you have no knowledge with harder to use, even if it actually is easier.

That being said, do what you assume is best on a case-to-case basis. If in your case you find the code less readable with operator overloading, by all means, don't do it. There are however situations when it is useful. But since in general overloading operators is done for the purpose of readability, if you find it doesn't apply in your case, stay away from it.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
2

I'm tempted to say that there isn't anything to learn about operator overloading; overloaded operators are just funny named functions. What you do have to learn is when overloading is appropriate, and when it is not. Certain idioms are more or less standard: numeric types overload the appropriate numeric operators (+, etc.), smart pointers overload the pointer ops (* and ->), container types which support indexation overload [], and functional objects overload (). And that's about it for the special cases. And while it's arguably an abuse, if you define an iterator, you'll want it to support the standard iterator idiom (which means ++, *, -> and ==/!=).

In addition to these, there are three operators which will be overloaded for many different types of classes: assignment is done using =, and insertion into and extraction from streams is done using << and >>. If you want your class to support any of these, you should use the overload. And comparison uses == and != for equality, and <, <=, > and >= for inequality. But don't overload for inequality unless it is semantically significant. It's better to provide an explicit ordering function for use with std::map and std::set than to mislead readers into thinking you've defined as semantically significant ordering. You might want to specialize std::less on your class in this case; < won't work, or will have inappropriate semantics for use as a key, but std::less will define an arbitrary ordering which will. And while it's not operator overloading, if the type is to be used as a key in associative containers, you'll also want to provide a function hash_code and an instantiation of struct std::hash.

In many cases, it's best to define the overload in terms of some more global function: for example: I use compare (returning an int less than, equal to, or greater than 0), for inequality; I'll define a public function compare in the class, and then derive from something like:

template<typename T>
struct ComparisonOperators
{
    friend bool operator==( T const& lhs, T const& rhs )
    {
        return lhs.compare() < 0;
    }
    //  ...
    //  The same for the other five operators.
};

(My implementation is actually somewhat more complex, as it uses metaprogramming to use isEqual for == and != if the class provides it.)

I use a similar techique for the binary arithmetic operators, defining + in terms of +=, etc. I also use it for IO, defining << in terms of print and >> in terms of parse; this is mainly useful when the operators need to be polymorphic.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
1

Operator overloading improves readability in many cases, and these are the cases when it's useful. You probably had an unlucky example your first time around; especially with the operator<<, this happens, and you have learned the first operator overloading lesson: Sometimes, an explicit method call is clearer. But sometimes it is not. For an example, consider a typical matrix multiplication in C++ (e.g. with Eigen matrices):

a = b * c;

and in Java:

a = b.multiplyUsingTheMatrixMultiplicationAlgorithmThatsMathYay(c);

Operator overloading made the code much more readable. For these cases, you should study or at least know about operator overloading, and only in these cases it should be applied.

thiton
  • 35,651
  • 4
  • 70
  • 100
0

Actually, I took the standard overloaded operators for granted and didn't account for the fact there are separate implementations for every type. So operator overloading is actually quite important in many aspects like for example when using templates, so the time saving goes much deeper than I initially realized.

dtech
  • 47,916
  • 17
  • 112
  • 190
-1

It's a normal practice using a friend external operator for this purpose, something like this

friend std::ostringstream & operator<<(std::ostringstream &oss, Type &type);

and

std::ostringstream & operator<<(std::ostringstream &oss, Type &type)
{
    oss << type.attr1;
    oss << type.attr2;
    oss << type.attr3;

    return oss;
}

so you can invoke like:

Type val;
...
std::cout << val << std::end;
Tio Pepe
  • 3,071
  • 1
  • 17
  • 22