KEY: DSE002 DumanDOCS!

Press on this button to view the code on DumanDOCS!
Where you can find code examples to support the understanding.


Why do we need operator overloading? To make operators work in a way that we want, obviously.

Let’s start with the hard ones. Here’s ostream and istream operator overloadings. It may look scary at the first glance but it’s okay. It’s actually pretty easy once you get it and now, you’ll get it.

class Time
{
public:
    Time() : hour(3), minute(33), second(13)
    {}
    ~Time()
    {}
    friend ostream& operator<<(ostream& os, const Time& obj);
    friend istream& operator>>(istream& is, Time& obj);
private:
    int hour;
    int minute;
    int second;
};

istream& operator>>(istream& is, Time& obj)
{
    is >> obj.hour >> obj.minute >> obj.second;
    return is;
}

ostream& operator<<(ostream& os, const Time& obj)
{
    os << obj.hour << ':' << obj.minute << ':' << obj.second << endl;
    return os;
}

First things first, there’s a keyword, friend why do we need it? Otherwise we get an error from the compiler.

‘std::ostream& Time::operator<<(std::ostream&, const Time&)’ must take exactly one argument

To overcome this, we declare it as a friend and define it outside of the class. This way compiler won’t complain and we’ll be able to put as many arguments as we want to.

Now, we know why do we need friend and how to use it, we can keep analysing the code. Let’s start with ostream which is used for outputting the object in a way that we want to.

After overloading both ostream and istream we will be able to do such stuff.

int main()
{
    Time test;
    cin >> test;
    cout << test;

    return 0;
}

Which pretty much impossible without overloadings. Alright, now, ostream.
Let’s check this single bit of line.

ostream& operator<<(ostream& os, const Time& obj)

We have ostream& which is the return type, operator<< which is the way how C++ handles operator overloading, (ostream& os, which will be used instead of cout.

cout << obj.hour << ':' << obj.minute << ':' << obj.second << endl; // unless members are public, it's illegal.
os << obj.hour << ':' << obj.minute << ':' << obj.second << endl; // this way we can access private members, thanks to the second argument.

const Time& obj) as the last part of the line. Which is calling the current object over obj and allows us to access Time class thanks to const Time&.

You may be asking why do we need const there? It’s there just to make sure that we don’t modify any class members. Remember, ostream is only for outputting the members in a format that we want to.  So, basically it’s there to protect the code from us.

Now let’s look at the function definition again. Remember that I’ve said function because even overloaded operators are functions. I’ll explain it at the end.

ostream& operator<<(ostream& os, Time& obj)
{
    os << obj.hour << ':' << obj.minute << ':' << obj.second << endl;
    return os;
}

Here it is. Now we know how the first line of the code, let’s check the second. I’ve explained it a bit up in the post. It’s exact same how “cout <<” works. You just type whatever you’ve written in ostream& os part. Let’s say that you have written it like ostream& kaan so that I’ll print the code as;

kaan << obj.hour << ':' << obj.minute << ':' << obj.second << endl;

You’re free to name os part with anything you’d like to. It’ll be the exact same for is too. Anyway, let’s keep going on. There are things like obj.hourobj.minuteobj.second and such. Why don’t we just type hour? Well… we can’t. We’ll get the following error.

Symbol ‘hour’ could not be resolved

That’s exactly why we needed const Time& obj part of the code. Thanks to it now we can access class members with no issues over obj. Now we’re at the last part of the code.

return oswhy did we return something and why it is os, you may ask. It’s because the object has a return type of ostream& (which we have written at the very beginning.)

ostream& operator<< ...

This one to be exact. So that the function is expecting a return type of ostream and we look at the first argument, it says ostream& os here it is! ostream typed variable which we can return. That’s why we’ve written return os. Are we good? Perfect.


Now time for the istream, I won’t be explaining everything about it since it’s pretty much same with ostream with two minor difference.

istream& operator>>(istream& is, Time& obj)
{
    is >> obj.hour >> obj.minute >> obj.second;
    return is;
}

As you can see we’ve changed every single (os)tream with (is)tream and removed the const from Time& obj part. Why did we remove const this time? Because we want to change the value of the variable instead of protecting it from the changes. Remember how “cin >>” works? You write something inside of a variable. This is the same, we’re going to write in our hour, minute and second into the variables of the object that we’ve created.

There’s no other difference. Now let’s go back to main() function.

int main()
{
    Time test;
    cin >> test;
    cout << test;

    return 0;
}

We’ve created the object test and then we’ve called our very own operator>> function and operator<< function. After we run the code, console will wait for our input. Here’s an example input and output of the code that’ve just built.

14 05 17
14:5:17

Now, do you remember that I’ve said that they are actually functions? You may be asking, where is the function part of this?

We could’ve done it this way with no operator overloadings.

class Time
{
public:
    Time() : hour(0), minute(0), second(0)
    {}
    ~Time()
    {}
    void set(int h, int m, int s)
    {
        hour = h;
        minute = m;
        second = s;
    }
    void print()
    {
        cout << hour << ':' << minute << ':' << second << endl;
    }
private:
    int hour;
    int minute;
    int second;
};

int main()
{
    Time test;
    test.set(3,2,5);
    test.print();

    return 0;
}

You may be saying now there are function inside the main but previously there was none. There was. What we actually have done is:

int main()
    Time test;
    test.operator<<(...);
    test.operator>>(...);

    return 0;
}

To prevent calling them as functions, we’ve made it so when we type << program knows that it should call test.operator<<(…) thanks to this we’ve simplified our main and made it more readable, maintainable also more functional. Our life is easier now.

Next post will be about operator overloading too, but we’re going to overload some other operators such as + – * / over a Rational class to make sure that we better understand everything. Also, I’ll introduce copy constructor. Which is used for copying contents of an object into another object.

I decided to upload it to DumanDOCS which you can access via the the button on the top of the post. If you’ve any questions regarding to code you can either ask here or follow the directions provided in the Contact Options of the document.

Good luck & have fun!

PS: If you have any questions about the topic, please do ask in the comments section so that I can help or learn from you. Have a nice day.

Categories: C++CODE

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts

C++

What’s up with `virtual` keyword? (C++)

Press on this button to view the code on DumanDOCS! Where you can find code examples to support the understanding. Let’s say that we have 2 classes like shown below. Which triangle inherited it’s area Read more…

CODE

Get a 100/100 PageSpeed Score!

As you can see, currently my blog is getting a whopping 100/100! Also it looks nice, well, that’s in my opinion. But, still… First things first, you need to enable gzip. You can either use a Read more…