Tuesday, January 18, 2011

Overloading typecasts

In the lesson on type conversion and casting, you learned that C++ allows you to convert one data type to another. The following example shows an int being converted into a double:
1int nValue = 5;
2double dValue = nValue; // int implicitly cast to a double
C++ already knows how to convert between the built-in data types. However, it does not know how to convert any of our user-defined classes. That’s where overloading the typecast operators comes into play.
Overloading the typecast operators allows us to convert our class into another data type. Take a look at the following class:
01class Cents
02{
03private:
04    int m_nCents;
05public:
06    Cents(int nCents=0)
07    {
08        m_nCents = nCents;
09    }
10 
11    int GetCents() { return m_nCents; }
12    void SetCents(int nCents) { m_nCents = nCents; }
13};
This class is pretty simple: it holds some number of cents as an integer, and provides access functions to get and set the number of cents. It also provides a constructor for converting an int into a Cents.
If we can convert an int into a Cents, then doesn’t it also make sense for us to be able to convert a Cents back into an int? In the following example, we have to use GetCents() to convert our Cents variable back into an integer so we can print it using PrintInt():
01void PrintInt(int nValue)
02{
03    cout << nValue;
04}
05 
06int main()
07{
08    Cents cCents(7);
09    PrintInt(cCents.GetCents()); // print 7
10 
11    return 0;
12}
If we have already written a lot of functions that take integers as parameters, our code will be littered with calls to GetCents(), which makes it more messy than it needs to be.
To make things easier, we’ll overload the int cast, which will allow us to cast our Cents class into an int. The following example shows how this is done:
01class Cents
02{
03private:
04    int m_nCents;
05public:
06    Cents(int nCents=0)
07    {
08        m_nCents = nCents;
09    }
10 
11    // Overloaded int cast
12    operator int() { return m_nCents; }
13 
14    int GetCents() { return m_nCents; }
15    void SetCents(int nCents) { m_nCents = nCents; }
16};
There are two things to note:
1) To overload the function that casts our class to an int, we write a new function in our class called operator int(). Note that there is a space between the word operator and the type we are casting to.
2) Casting operators do not have a return type. C++ assumes you will be returning the correct type.
Now in our example, we call PrintInt() like this:
1int main()
2{
3    Cents cCents(7);
4    PrintInt(cCents); // print 7
5 
6    return 0;
7}
The compiler will first note that PrintInt takes an integer parameter. Then it will note that cCents is not an int. Finally, it will look to see if we’ve provided a way to convert a Cents into an int. Since we have, it will call our operator int() function, which returns an int, and the returned int will be passed to PrintInt().
We can now also explicitly cast our Cents variable to an int:
1Cents cCents(7);
2int nCents = static_cast<int>(cCents);
You can overload cast operators for any data type you wish, including your own user-defined data types!
Here’s a new class called Dollars that provides an overloaded Cents cast operator:
01class Dollars
02{
03private:
04    int m_nDollars;
05public:
06    Dollars(int nDollars=0)
07    {
08        m_nDollars = nDollars;
09    }
10 
11     // Allow us to convert Dollars into Cents
12     operator Cents() { return Cents(m_nDollars * 100); }
13};
This allows us to convert a Dollars object directly into a Cents object! This allows you to do something like this:
01void PrintCents(Cents cCents)
02{
03    cout << cCents.GetCents();
04}
05 
06int main()
07{
08    Dollars cDollars(9);
09    PrintCents(cDollars); // cDollars will be cast to a Cents
10 
11    return 0;
12}

No comments: