Geo Drawkcab
Geo Drawkcab

Reputation: 61

Purpose of overloading operators in C++?

What is the main purpose of overloading operators in C++?

In the code below, << and >> are overloaded; what is the advantage to doing so?

#include <iostream>
#include <string>

using namespace std;

class  book {
    string name,gvari;
    double cost;
    int year;
    public:
    book(){};

    book(string a, string b, double c, int d) { a=name;b=gvari;c=cost;d=year; }
    ~book() {}
    double setprice(double a) { return a=cost; }
    friend ostream& operator <<(ostream& , book&);
    void printbook(){
        cout<<"wignis saxeli "<<name<<endl;
        cout<<"wignis avtori "<<gvari<<endl;
        cout<<"girebuleba "<<cost<<endl;
        cout<<"weli "<<year<<endl;
    }
};

ostream& operator <<(ostream& out, book& a){
    out<<"wignis saxeli "<<a.name<<endl;
    out<<"wignis avtori "<<a.gvari<<endl;
    out<<"girebuleba "<<a.cost<<endl;
    out<<"weli "<<a.year<<endl;
    return out;
}

class library_card : public book {
    string nomeri;
    int raod;
    public:
    library_card(){};
    library_card( string a, int b){a=nomeri;b=raod;}
    ~library_card() {};
    void printcard(){
        cout<<"katalogis nomeri "<<nomeri<<endl;
        cout<<"gacemis raodenoba "<<raod<<endl;
    }
    friend ostream& operator <<(ostream& , library_card&);
};

ostream& operator <<(ostream& out, library_card& b) {
    out<<"katalogis nomeri "<<b.nomeri<<endl;
    out<<"gacemis raodenoba "<<b.raod<<endl;
    return out;
}


int main() {
    book A("robizon kruno","giorgi",15,1992);
    library_card B("910CPP",123);
    A.printbook();
    B.printbook();
    A.setprice(15);
    B.printbook();

    system("pause");
    return 0;
}

Upvotes: 0

Views: 457

Answers (8)

Michael Anderson
Michael Anderson

Reputation: 73530

The purpose of overloading operators is mostly syntactic sugar. It makes ugly stuff look nice. But it's also about unifying interfaces, and an important reason for unifying interfaces is polymoprphism, in this case especially with templates.

Imagine we have a lovely complex number class Complex, and we want to have a Taylor series approximation of sine that we want to make work for Complex and double types.

If we support operator overloading on *, =, / etc. then we can write it like this:

template<typename T>
T sin(T t)
{
  T t2 = t*t;
  return t*(1 - t2/6 + (t2*t2)/120 );
}

If we cant have overloading on *, / etc. then it starts to get ugly, as we need a helper class to unify the interface for doubles and Complex, heres what it might look like. (I'm still allowing overloading of operator=, otherwise it gets even worse).

template<typename T>
T sin(T t)
{
  T t2 = helper<T>::mult( t, t );
  T t4 = helper<T>::mult( t2, t2 );
  T s(1);
  helper<T>::sincrement( &s, -1./6, t2);
  helper<T>::sincrement( &s, -1./120, t4);
  return helper<T>::mult( t, s );
}

template<>
struct helper<double>
{
  static double mult( double a, double b) { return a*b; }
  static void sincrement( double * v, double s, double x) { *v += s*x; }
}

template<>
struct helper<Complex>
{
  static Complex mult( Complex a, Complex b ) { return a.mult(b); }
  static void sincrement( Complex * v, double s, Complex x ) { v->add( x.scale(s) ); }
}

Now I know operator overloading can be ugly, and can hide what's really happening, but used correctly I think that it makes cases like this much easier to understand.

Upvotes: 2

gcochard
gcochard

Reputation: 11734

Overloading the << operator allows your objects to be written out to the output in a way you specify, when passed to cout.

Otherwise, cout would just write out the address to your object.

Upvotes: 2

Injektilo
Injektilo

Reputation: 579

The thing about C++ is it passes objects by value, as a fundamental aim of how it works, and this really greatly changes how objects work compared to reference-semantics oriented languages like Java and Objective-C.

Whereas in one of those languages there is a clear distinction between primitive types and objects in terms of how you use them - that is, you copy primitives a lot, you stick them into expressions involving operators, that sort of thing, whereas your interaction with objects is mainly instantiating them, calling methods on them and passing the references to them into functions - in C++ you can use objects pretty much the same way as you use primitives. This brings up a lot of complicated issues that C++ programmers have to deal with, like object lifetimes, whether an object is an lvalue or rvalue (that is, if it has a lifetime outside the expression it appears in), etc.

One thing your question brings up is why a class would overload << and >>. The C++ standard library uses this convention for iostream classes, and highlights another big difference from reference-semantics based languages - in a value-semantics oriented language, class inheritance is inadequate to fully describe what you want to do with an object. We can loosely say that if an object overloads << and >> to stream data in and out of some resource, then it satisfies the concept of an iostream, even if it doesn't inherit from iostream, or ios_base, or something. The meaning of this is twofold:

  1. If you put a value of this type into an expression and used <<, it would behave as expected.
  2. If you instantiate a template with this type as a parameter, which calls operator<< on the object, the code will compile successfully.

I deliberately used the word concept above because there was going to be a feature in C++11 (it got postponed to the next version) called Concepts which would formalise this idea in the language. The situation we have now is a sort of duck typing - if a template wants to use a certain operator with a type, it will compile if the type provides that operator and won't if it doesn't, regardless of what the operator actually means. operator<< is a case in point - in its original meaning, for an integer type, it means "leftward signed bit-shift", but when you are using the concept of iostream, it means "stream data from the object on the right into the object to the left".

Upvotes: 1

nurettin
nurettin

Reputation: 11746

With an overloaded operator, you can use standard library algorithms which require that operator to be overloaded.

For example:

struct wtf{ wtf(int omg): omg(omg){} int omg; };

wtf operator+ (wtf const &omg, wtf const &lol)
{
    return wtf(omg.omg+ lol.omg);
}

#include <iostream>
#include <numeric>

int main()
{
    wtf lol[3]= { wtf(1), wtf(2), wtf(3) };
    std::cout<< std::accumulate(lol, lol+ 3, wtf(0)).omg;
}

6

Upvotes: 1

oblitum
oblitum

Reputation: 12016

Your main purpose overloading the << and >> operators is to create an API in the spirit of the C++ standard library, so it becomes more natural for experienced C++ programmers to use your types.

It's so this way that the operators << and >> are known as insertion/extraction operators when used with the STL streams. From C they were just bit shift operators.

Since in the realm of standard C++ they acquired that meaning and even received new nomenclatures for that, It's aways good to reuse already established programming jargon.

Now, originally in the C++ creation, why it has gone this way for stream operations? by getting the shift operators and labeling them as insertion and extraction operators, I don't know, maybe a matter of taste to better express the idea of insertion/extraction given the appearance of the shift operators, a meaning which now, has become standard and suits to be reused.

Upvotes: 0

dubvfan87
dubvfan87

Reputation: 641

You could easily use a member function instead, it just provides a "syntactic sugar" in most cases. For example in some languages adding 2 strings does a concat.

stringOne = stringOne + stringTwo;

Though it could easily be implemented with a member function like

stringOne.concat(stringTwo);

Upvotes: 1

Shane
Shane

Reputation: 667

Overloading operators allows a special case of polymorphism.

The best example I can think of is a string class with the + operator overloaded.

In this case the operator would be overloaded to concatenate strings instead of "adding" two strings which doesn't make any sense.

To answer your question specifically overloading operators can (in some cases) produce more readable and maintainable code. However, what "makes sense" for one person may not make sense for the person maintaining the code.

Upvotes: 1

abarnert
abarnert

Reputation: 365915

It doesn't ever have to be used; it's just a convenience, a way of letting user-defined types act more like built-in types.

For example, if you overload operator<<, you can stream books the same way as integers and strings:

cout << "Book #" << n << " is " << books[n] << endl;

If you don't, you'd have to write the same thing like this:

cout << "Book #" << n << " is ";
books[n].printbook();
cout << endl;

Similarly, if you create a Fraction class and give it an operator+, you can use fractions the same way you use integers, and so on.

It's sometimes a tough design choice whether your class should act like a native type in one way or another (for example, does string's operator+ make sense?), but the point is that C++ gives you the choice.

Upvotes: 7

Related Questions