13.11 — Overloading typecasts

In the lesson 4.4 -- 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:

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.

User-defined conversions allow us to convert our class into another data type. Take a look at the following class:

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 some cases, this might not be true, but in this case, it does make sense.

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():

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 can provide a user-defined conversion by overloading the int typecast. This will allow us to cast our Cents class directly into an int. The following example shows how this is done:

There are three 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. User-defined conversions do not take parameters, as there is no way to pass arguments to them.
  3. User-defined conversions do not have a return type. C++ assumes you will be returning the correct type.

Now in our example, we can call printInt() like this:

The compiler will first note that function printInt takes an integer parameter. Then it will note that variable cents 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:

You can provide user-defined conversions 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 conversion:

This allows us to convert a Dollars object directly into a Cents object! This allows you to do something like this:

Consequently, this program will print the value:


which makes sense, since 9 dollars is 900 cents!

13.12 -- The copy constructor
13.10 -- Overloading the parenthesis operator

98 comments to 13.11 — Overloading typecasts

  • Mohammad

    Hi there! You wrote that "There are two things to note "after the fourth snippet but it should be "there are three things to note". Sorry to disturb you but advanced thanks.

  • choofe

    Hi.Are there rules in selecting the implicit operator overload by compiler? I mean the first example we had

    and it is obvious it should cast to int (and int is printable by <<) but in the following:

    Why this implicit will occur at all? Is it because the only thing printable by << is the int() overload?

    I change the int() overload on Cents to short() and it compiled but I assume it overflowed on

    prints : 24464
    I create a << overload in addition to short() and it goes right.
    Changed back short() to int() to see the result.
    I see (through step into), in presence of int() overload and << overload , the << overload called, even though the int() has been defined before << overload.

    prints: 90000

    • nascardriver

      > Hi.Are there rules in selecting the implicit operator overload by compiler?

      > Why this implicit will occur at all? Is it because the only thing printable by << is the int() overload? Yes > I create a << overload in addition to short() Now you're giving the compiler a way of printing your object without any conversions. That's better than having to convert the object, so the compiler uses your operator. The order of definition is irrelevant.

  • Andy

    >We can now also explicitly cast our Cents variable to an int:

    Maybe there's no need...I think this should work:

  • AbraxasKnister

    I tested this

    and it prints "A\n2". Does this mean that we provide casts of other types to our type by implementing a constructor that takes the other type as an input?

  • Ged

    Why are we unable to write it like this?

    • nascardriver

      That will only work with non-const lvalues.
      If you don't modify a reference, make it const. const references can bind to all kinds of values.

  • hellmet

    I wanted to overload the '->' operator. Does it have to return a pointer type? What e is happening here?

    Why doesn't that work? What did I misunderstand here? I think it works like this. a->some_T2_method() should be evaluated as obj.some_T2_method(). I ... am also thinking that -> does nothing but put whatever is the result of its overload behind it and call its -> operator, hence, I need to return a pointer. So, it should actually be

    which leads me to think the second one is correct; and in fact, that is what works! So I guess my second thinking is what actually happens?

    • nascardriver

      Your assumption is correct. `operator->` doesn't _have to_ return a pointer. It has to either return a pointer, or return an object that has an `operator->` that returns a pointer (Or returns an object with `operator->` that returns an object with `operator->` that ...).
      You first example is valid if `T2` has a valid `operator->`.

      • hellmet

        Ahhh yes! It's all making sense! So it recursively calls the operator till method/property is evaluated finally! Damn took me a while to understand it hahah.
        I can't seem to recall this being discussed here?

        Also, took me a while to resolve this issue. This is KEY to remember (8.5A -> Initializer list order)!

        Thank you very much for your help!

        P.S. How do I get a grasp on the more advanced topics of C++? Could you kindly address this in depth at the end of all the lessons?

        • nascardriver

          > I can't seem to recall this being discussed here?
          I don't think it is. Overloading `operator->` is rare.

          > Obj::Obj (... parameters)
          Careful there, `...` has special meanings in C++, you confused me for a moment. `/* ... */` is better.

          > failed to copy over the string properly
          That's odd. Class-type members are default-initialized. In `Obj::Obj`'s body, every string should have been initialized already. The constructor body is the last thing that gets executed during initialization. Default-initialized members and member initializer lists have been processed before that.

          I don't want to be in a situation like the one in the blog entry. But it goes to show how deep one might have to get into the system as a C++ programmer.

          > How do I get a grasp on the more advanced topics of C++?
          What you're doing right now is the best thing I can recommend. You're working with advanced code, you'll inevitably find things you don't understand, then you learn more about them. Also, conference talks (eg. cppcon) are great to get information from someone who spent a lot of time on a topic (You're watching those iirc). It's also good to stay in touch with standard updates. You'll know about features before you can use them. . Also go through the tables of the older standards on that page, you'll find many new things.

          • hellmet

            > Careful there, `...` has special meanings in C++, you confused me for a moment. `/* ... */` is better.
            Hahah yes, my bad!

            > That's odd
            Yeah, I was thinking that too! I dug up my undo history, and I think this reflects the case more closely. Could you edit the comment with this if possible? Thanks!

            Yeah that was spaghetti code. I made classes for no reason. Instead, I made them into regular functions and grouped related ones in namespaces. Now, it's much cleaner!

            Glad to know I'm on the right track! Thank you for the kind words of motivation!

  • Ryan

    Please fix:
    code above forgot the semi colon below the constructors Dollars(int dollars = 0) and Cents(int dollars = 0)

  • R

    Colon seems to be missing in some constructor functions in the lesson -

  • hellmet

    Perhaps it's worth mentioning that

    causes an implicit cast of int (the 5) to Cents via the constructor we have defined for Cents. (realized this thanks to Nascardriver's help with my doubt on Fraction exercise/example a few lessons back!)

    Also, the last thing the last code snippet prints is not a newline :) (I enabled by -pedantic flag)

  • DecSco

    Shouldn't the operator functions always be declared const?

    I came across that in the comprehensive quiz, when trying to convert the FixedPoint2 class to a double inside the operator<< function body.

  • Hi, Alex.

    Then, dollars's data type is changed to Cents forever?
    Or dollars is temporarily denoted Cents and remained Dollars data type?

    • Alex

      Types are never changed.

      In the case where Dollars::operator Cents() is executed, a new Cents object is returned. The original Dollars object is not altered.

  • sekhar

    Hi Alex,

    Good to add another point stating that "These convertion operators cannot take any parameters in the function definition".

  • Ryan

    When debugging this, I noticed "operator int() { return m_penny; }" (in class Penny) is required for the program to work when compiling "printPenny(pound, pound);" Why is the operator int() needed for Penny in this case when I only use the class Pounds for use? ( other than calling for it in "operator Penny() { return Penny(m_pounds * 100); }" )

  • Yiu Chung WONG

    Cents class has an overloaded int() typecast so int(cents) works. But how does the compiler know we want to implicitly cast cents to an int and not some other type? Does the compiler check for overloaded typecast in class definition to see which type to implicitly cast to?


    • Alex

      Operator<< has functions that work with all kinds of different types. First it will try and find a match for Cents. If it can't find that, it will look for a match with any of the other types it supports. If it finds no matches, you'll get an error about not finding a matching function. If it finds multiple matches, you'll get an error about an ambiguous function (which can be resolved via a static_cast). If it finds one match, then it will implicitly do a conversion (unless that function is marked as explicit).

  • Saumitra Kulkarni

    In the following program.

    I am getting the following error

    saumitra@saumitra-VirtualBox:~$ make fehcel
    g++     fehcel.cpp   -o fehcel
    fehcel.cpp: In member function ‘Celsius::operator Fahrenheit()’:
    fehcel.cpp:13:24: error: return type ‘class Fahrenheit’ is incomplete
      operator Fahrenheit() {return Fahrenheit(m_celsius*9/5+32.0);}
    fehcel.cpp:13:61: error: invalid use of incomplete type ‘class Fahrenheit’
      operator Fahrenheit() {return Fahrenheit(m_celsius*9/5+32.0);}
    fehcel.cpp:2:7: note: forward declaration of ‘class Fahrenheit’
    class Fahrenheit;
    <builtin>: recipe for target 'fehcel' failed
    make: *** [fehcel] Error 1

    Even when I have forward declared Fahrenheit class why doesn't the compiler know the return type of the operator function ? Is there any fix ?I tried using header files but wouldn't work either way!

    • Saumitra Kulkarni

      I moved the definitions of the operator member functions outside and now it works!

      • Alex

        This was caused by a circular dependency -- The implementation of some Celsius functions depend on Fahrenheit, and vice versa. Moving the relevant member function definitions below the class definitions allows each class to at least be fully declared by the point of function definition.

  • Pashka2107

    Hi Alex,
    I didn't get one thing here. All examples so far were all about conversion from the given class(e.q. Dollars) to another one(e.q. Cents). Maybe I didn't get something really obvious, but what about conversion from another class (Cents) to the given(Dollars)? Surely, it's possible to implement typecast for such reason in Cents class, but it's probably not the best solution (e.q. we cannot reimplement standart classes like vector, so how to cast vector to smth?). Whether it is possible to convert in such way? Thanks in advance and sorry for typos.

    • Alex

      Generally if you want to convert from another class to your class, you'd do that by providing a constructor that takes the appropriate type by const reference. So, for example, if you wanted to convert another class (Cents) to your class (Dollars), you'd provide a Dollars constructor that took a Cents by const reference. This will allow the compiler to convert a Cents into a Dollars.

      • Pashka2107

        But the main point of using casting in my particular case is implicit casting from one type to another, so constructor won't help here. I checked the fact that C# allows such thing, so somehow expected that C++ also has appropriate syntax. Searched through many resourses, but haven't found anything about it. Maybe you do have some ideas?

        • Alex

          Conversion from another class to the given class: use a constructor
          Conversion from a given class to another class: use an overloaded typecast

          Both of these will work implicitly.

          For example, if you want to be able to cast a vector to smth, then your smth class would have a vector constructor allowing it to convert a vector into a smth. If you want to convert a smth into a vector, then your smth class can have an overloaded typecast.

          I'm not clear on why this won't work for your particular case.

  • Lamont Peterson


    The first example has this in the body of the printInt () function:

    Shouldn’t that be:

  • Brad

    I like how this method, at least for the example given, makes it unnecessary to make overloaded friend functions for operator<<. Very cool!

  • Yash Patel

    In dollars cent example you use printcents() which print 900 why not printint()? Printcents () only find cent object so way is goes for serching int.....

    • Alex

      In this particular case, because Cents has a cast to int, and because printCents() and printInt() do the same thing, you could use printInt() instead and let the compiler implicitly convert your Cents to an Int.

  • Deepak

    Can somebody please tell me how to overload standard datatype like float to user defined datatype. I have function f2my(float f, mttype* m) which converts float to mytype. I want to overload all floats in my code with mytype i.e. 'float a' should be 'mytype a'.

    Thank you.

  • Matt

    In the code snippet above the first Dollar class code example, you wrote:
    "We can now also explicitly cast our Cents variable to an int:
    Cents cents(7);
    int cents = static_cast<int>(cents);"

    How can you have two identifiers of the same name, but of two different types? Did you mean to use a different identifier for the int variable?

  • Christos

    Hi Alex,

    What if we not only have int dollars/cents but also double? For example dollars(9) or dollars(9.3)

    • Alex

      If this is a valid use case, then the Dollars class would need to modified to handle fractional dollars.

      At the end of this chapter, there's a quiz question around implementing fixed point numbers that would be a good way to handle this (it's not quite as easy as it seems).

  • Sourabh S. Rawat

    We have overloade typecast to int here, so cents get converted to int. But , what if we have also overloaded << operator for the Cents class??
    I tried it and it looks like overloaded << was used.

    • Alex

      An overloaded operator<< for class Cents is considered a better match than an implicit conversion to integer, so the overloaded operator<< will be used. Of course, if we'd overloaded operator<<, there wouldn't much point in even having a printCents() function.

  • Peter

    Hi Alex,

    letting you know that there is a typo

    should be

    this happens in the 2nd and 3rd instance of your Cents class code

  • Hunter

    Hi Alex:
    In the last example above,why can't

    pass value by reference like this?

    • Alex

      The implicit conversion from Dollars to Cents creates a temporary (anonymous) Cents object. In the case where the function parameter is passed by value, this anonymous Cents object is copied into the Cents parameter. However, non-const references aren't allowed to be assigned to anonymous objects, so in the case where the function parameter is a reference, the conversion can't happen.

      Since printCents doesn't modify the parameter, a better thing to do would be to make printCents take a const reference (which can be bound to a temporary object). However, our conversion to int() won't work in this case, because it's not flagged as const, so we'd need to modify the overloaded int cast to be const (which we probably should have done anyway).

  • Ola Sh

    Thanks for your help.

  • Ola Sh

    Hi Alex,

    I would like to know if you can overload a typecast operator to convert a Cents object to a std::string object. I tried to overload the operator, but Visual Studio points out that no operator exists for converting int to strings. Can I define or overload an operator to convert from integers to strings? Thanks for your help.

    • Alex

      You can definitely overload a typecast to convert your class to a string. The challenge you're running into here isn't that, but rather figuring out how to convert an integer to a std::string in the first place. Prior to C++11, this isn't easy. But in C++11, you can use the std::to_string() function:

      That said, if your goal is just to print the state of something, you're better off overloading operator>>.

      • sekhar

        Hi Alex,

        operator std::string() { return std::to_string(42); } should be operator std::string() { return std::to_string(m_cents) };, It can even be mentioned that even though the conversion operator does not take any parameters but all the members of the passed in object(in this case cents1) can be referenced in the conversion operator as it would be more descriptive as part of this lesson.

  • Steiner

    Hello Alex,

    I tried to expand your code and it gave me errors that I don’t even understand on how to solve it using the lessons learned on this chapter.

    this gives out a compiler error of:
    #1. "error: expected type-specifier before ‘Meters’
             operator Meters() { return Meters(m_unit * 1000); }"


    #2. "error: could not convert ‘value2’ from ‘Millimeters’ to ‘Meters’

    I thought of solving error #1 would be by doing a forward declaration of "class Meters" (as shown in the commented code).
    After doing that, the compiler showed a new kind of error:
    "error: return type ‘class Meters’ is incomplete
             operator Meters() { return Meters(m_unit * 1000); }"

    which doesn’t seem to mean anything. It might be the compiler doesn't have a complete idea about the "class Meters" for it to be a return type?

    The #2 error is very odd since the call "PrintMillimeters(value1);" worked (didn’t give any compiler errors) which is expected to call in the operator() to do a Meters to Millimeters conversion.

    But the other way around, the call "PrintMeters(value2);" gave a compiler error as written above in #2.

    Thank you again for this tutorials.

    • Alex

      The problem is that you have a circular dependency here. Meters depends on knowing the declaration of Millimeters, and Millimeters depends on knowing the declaration of Meters.

      The best solution is to move each class into its own header file, and move the function implementations into a .cpp file.

      That way each class can see the declaration of the other, and the classes will be fully declared before the function definitions are compiled.

      • Steiner

        Hello Alex,

        Thank you for your time.

        Unfortunately, I'm still having the same compilation problems even after I did your proposed solution and checking online for other solutions :(. I made sure I included the Header Guards, placed the function implementations into their respective .cpp files, and use the #include directive to include the necessary header files in each of the .cpp file. Here's the complete separated code:






        The compilation problem (codeblocks, g++ 4.9.2) still says:
        1. Meters.h|18|error: expected type-specifier before 'Millimeters'
        2. main.cpp|33|error: could not convert 'value1' from 'Meters' to 'Millimeters'

        Just answer this question whenever you can and sorry for taking your time. I'm on 10.4 container classes now and I'm really learning a lot. I'm also making sure to read most if not all the discussions found at the end of the chapters :). So, Thank you for the lessons!

        • Alex

          The problem is that Millimeters.h is including Meters.h, which includes Millimeters.h -- essentially a circular reference. Due to the header guards on Millimeters.h, when Meters.h includes Millimeters.h, the header file doesn't get included, so Meters.h doesn't see the declaration for Millimeters.h.

          Fortunately, in this case there's an easy fix. Instead of having each header #include the other, replace the #includes with forward declarations for the other class. For example, at the top of Millimeters.h, replace #include "Meters.h" with "class Meters;" And do vice-versa for Meters.h.

          That way, the overloaded typecast in the header will know that Meters and Millimeters are types, so it will compile.

          Make sense?

          • Steiner

            I think I get it now. I thought that this is the sequence that the compiler does:

            processing the file Millimeters.h (goes through Millimeters.h to Meters.h then back to Millimeters.h)
            --MILLIMETERS_H gets defined
            --include "Meters.h"
            --goes inside Meters.h file
            --sees #include "Millimeters.h"
            --goes inside Millimeters.h
            --ignores this file since MILLIMETERS_H was already defined and skips this header file (due to #ifndef)
            --goes back to Meters.h file
            --proceeds on the class definition of class Meters

            Which prevents circular reference.

            However I forgot to add in how the compiler processes the other file as well.

            Now when processing the file Meters.h (goes through Meters.h to Millimeters.h then back to Meters.h) and as you said, due to the header guards on Millimeters.h
            --METERS_H was already defined so this file doesn't get processed
            --so Meters.h doesn't see the declaration for Millimeters.h

            Thank you Alex, I did the replacement and made the program run. I learned a lot from you :D.

            • Leo

              Dear, Steiner. Can you give me please show me your code or explain how to make mutual type congestion in this example(I just now have a problem with this).

              • DOG_TRAINER

                pretty easy actually:
                1. copy the above code into their respective files
                2. replace #includes "Meters.h" in Millimeters.h with class Meters
                3. replace #includes "Millimeters.h" in Meters.h with class Millimeters
                4. delete the std::cout<< functions in main.cpp

  • Brooklyn

  • Zafer

    To convert a Dollar object to a Cents object, Dollar class uses Cents class by returning Cents(m_nDollars * 100). Shouldn't we declare the Cents class before Dollar to be able to generate a Cents object?

Leave a Comment

Put all code inside code tags: [code]your code here[/code]