9.x — Chapter 9 comprehensive quiz

In this chapter, we explored topics related to operator overloading, as well as overloaded typecasts, and topics related to the copy constructor.


Operator overloading is a variant of function overloading that lets you overload operators for your classes. When operators are overloaded, the intent of the operators should be kept as close to the original intent of operators are possible. If the meaning of an operator when applied to a custom class is not clear and intuitive, use a named function instead.

Operators can be overloaded as a normal function, a friend function, or a member function. The following rules of thumb can help you determine which form is best for a given situation:

  • If you’re overloading assignment (=), subscript ([]), function call (()), or member selection (->), do so as a member function.
  • If you’re overloading a unary operator, do so as a member function.
  • If you’re overloading a binary operator that modifies its left operand (e.g. operator+=), do so as a member function if you can.
  • If you’re overloading a binary operator that does not modify its left operand (e.g. operator+), do so as a normal function or friend function.

Typecasts can be overloaded to provide conversion functions, which can be used to explicitly or implicitly convert your class into another type.

A copy constructor is a special type of constructor used to initialize an object from another object of the same type. Copy constructors are used for direct/uniform initialization from an object of the same type, copy initialization (Fraction f = Fraction(5,3)), and when passing or returning a parameter by value.

If you do not supply a copy constructor, the compiler will create one for you. Compiler-provided copy constructors will use memberwise initialization, meaning each member of the copy is initialized from the original member. The copy constructor may be elided for optimization purposes, even if it has side-effects, so do not rely on your copy constructor actually executing.

Constructors are considered converting constructors by default, meaning that the compiler will use them to implicitly convert objects of other types into objects of your class. You can avoid this by using the explicit keyword in front of your constructor. You can also delete functions within your class, including the copy constructor and overloaded assignment operator if desired. This will cause a compiler error if a deleted function would be called.

The assignment operator can be overloaded to allow assignment to your class. If you do not provide an overloaded assignment operator, the compiler will create one for you. Overloaded assignment operators should always include a self-assignment check.

New programmers often mix up when the assignment operator vs copy constructor are used, but it’s fairly straightforward:

  • If a new object has to be created before the copying can occur, the copy constructor is used (note: this includes passing or returning objects by value).
  • If a new object does not have to be created before the copying can occur, the assignment operator is used.

By default, the copy constructor and assignment operators provided by the compiler do a memberwise initialization or assignment, which is a shallow copy. If your class dynamically allocates memory, this will likely lead to problems, as multiple objects will end up pointing to the same allocated memory. In this case, you’ll need to explicitly define these in order to do a deep copy. Even better, avoid doing your own memory management if you can and use classes from the standard library.

Quiz Time

1) Assuming Point is a class and point is an instance of that class, should you use a normal/friend or member function overload for the following operators?

1a) point + point
1b) -point
1c) std::cout << point
1d) point = 5;

Show Solution

2) Write a class named Average that will keep track of the average of all integers passed to it. Use two members: The first one should be type int32_t, and used to keep track of the sum of all the numbers you’ve seen so far. The second should be of type int8_t, and used to keep track of how many numbers you’ve seen so far. You can divide them to find your average.

2a) Write all of the functions necessary for the following program to run:

int main()
	Average avg;
	avg += 4;
	std::cout << avg << '\n'; // 4 / 1 = 4
	avg += 8;
	std::cout << avg << '\n'; // (4 + 8) / 2 = 6

	avg += 24;
	std::cout << avg << '\n'; // (4 + 8 + 24) / 3 = 12

	avg += -10;
	std::cout << avg << '\n'; // (4 + 8 + 24 - 10) / 4 = 6.5

	(avg += 6) += 10; // 2 calls chained together
	std::cout << avg << '\n'; // (4 + 8 + 24 - 10 + 6 + 10) / 6 = 7

	Average copy = avg;
	std::cout << copy << '\n';

	return 0;

and produce the result:


Hint: Remember that int8_t is usually typedef'd as a char, so std::cout treats it accordingly.

Show Solution

2b) Does this class need an explicit copy constructor or assignment operator?

Show Solution

3) Write your own integer array class named IntArray from scratch (do not use std::array or std::vector). Users should pass in the size of the array when it is created, and the array should be dynamically allocated. Use assert statements to guard against bad data. Create any constructors or overloaded operators needed to make the following program operate correctly:

This programs should print:

5 8 2 3 6
5 8 2 3 6

Show Solution

4) Extra credit: This one is a little more tricky. A floating point number is a number with a decimal where the number of digits after the decimal can be variable. A fixed point number is a number with a fractional component where the number of digits in the fractional portion is fixed.

In this quiz, we're going to write a class to implement a fixed point number with two fractional digits (e.g. 12.34, 3.00, or 1278.99). Assume that the range of the class should be -32768.99 to 32767.99, that the fractional component should hold any two digits, that we don't want precision errors, and that we want to conserve space.

4a) What type of member variable(s) do you think we should use to implement our fixed point number with 2 digits after the decimal? (Make sure you read the answer before proceeding with the next questions)

Show Solution

4b) Write a class named FixedPoint2 that implements the recommended solution from the previous question. Provide the overloaded operators and constructors required for the following program to run:

And produce the result:


Hint: Although it may initially seem like more work initially, it's helpful to store both the non-fractional and fractional parts of the number with the same sign (e.g. both positive if the number is positive, and both negative if the number is negative). This makes doing math much easier later.
Hint: Remember that int8_t is usually typedef'd as a char, so std::cout treats it accordingly.
Hint: You can get the part of a double before the decimal by static casting the double to an integer
Hint: You can move a digit from the right of the decimal to the left of the decimal by multiplying by 10.
Hint: You can round a number (on the left of the decimal) by using the round() function (included in header cmath)

Show Solution

4c) Overload operators >>, - (unary), + (binary) and the cast to double.

The following program should run:

And produce the output:

Enter a number: 5.678
You entered: 5.68

Hint: Adding two m_decimal together could overflow an int8_t. Make sure your operator+ accounts for this (don't try to assign the sum of two m_decimal to an int8_t variable).
Hint: For operator>>, use your double constructor to create an anonymous object of type FixedPoint2, and assign it to your input object

Show Solution

10.1 -- Object relationships
9.15 -- Shallow vs. deep copying

43 comments to 9.x — Chapter 9 comprehensive quiz

  • Yaboi

    In the solutions of question 2 you never declared a type for static_cast, is this a feature of certained compilers to automatically know the right type? (I couldn’t find anything online and visual studio 13 doesn’t seem to support it).

    In this line:

    Wouldnt it be more efficient to call the move constructor/assignment or is the copy constructor just as fast/justifiable?

    Also, in 2c when overloading the >> operator for cin, when i type in a small value like 5.01, it automatically floors to 5.00. Does this have something to do with precision errors/roundings? All other values i have tested seem to work correctly.

    Lastly if I don’t put const in front of some of the arguments (for example the copy constructor) the compiler completly ignores the constructor and seems to create his own. Is this just because the compiler demands the copying to not modify the original object?

    Another thing: The code in the solutions isn’t formated in a very readable way (html/css) like the other code in your other tutorials. I’m not trying to bash these tutorials, because I find them extremely helpful, far more friendly for people new to the language and they have helped me a lot with learning the language, just trying to give my feedback 🙂

    • Alex

      Some of the quiz questions had a typo that was causing the code to be treated as HTML rather than C++. This is why the type of the static cast got hidden, as well as the formatting being messed up. Both should be fixed now, thanks for pointing that out.

      The code in the quiz question is pretty inefficient -- it’s there more to ensure you’ve learned certain concepts than to be a model for how to write great code. If I were writing that code to be efficient, I’d have main pass in an IntArray by reference and have the function fill it out, thus avoiding any copies.

      The problem with the value 5.01 is that that particular value is being stored as 5.0099999…, so it’s getting truncated. Precision errors strike again! I’ll have to find a better solution for this question.

      If you don’t put a const in front of a reference parameter, then that parameter won’t match any literals or anonymous objects. The return value from fillArray() probably qualifies.

  • hachiroku

    I ended up with a simple solution for operator+() in quiz 2c by using the overloaded double typecast.

    You’ll need to return m_decimal as negative in operator-() and handle this correctly in operator<<() for the program to work properly.

    However, using this code in operator+() forces you to make the FixedPoint2 parameters non-const, which I don’t understand since you’re still not changing their values.

    Is it possible to make the overloaded double typecast handle const parameters? And is there any other flaw with using this solution?

  • Anddo

    Typo in the solution of 2c)

    One notice, the output of solution of 2c) was, specifically,


    While they should be (by calculation, I’m sure of the second not the first)


    When I tried to debug to understand why this result comes out, I saw that int8_t handled as char and couldn’t show the actual number. Anyway, I used int16_t for decimal and all worked as expected. If you have explanation for this, I really would like to hear it from you since I did NOT fully understood what went wrong (from math calculation point of view) when int8_t is used.

    Edit: After success of trying int16_t for the decimal part, I tried back int8_t and guess what !? I got the correct results


    There is something I don’t get here !

    • Alex

      I’m not sure I understand what your question was.

      But you’re right, the results of the quiz were wrong. I changed the requirements from truncate to round (otherwise dealing with precision issues is a nightmare).

      That said, I wouldn’t be surprised if there was an x.5 floating point value that was represented internally as x.49999 and gets rounded down instead of up.

      A better idea is probably to disallow use of double input altogether and only allow the user to input strings.

      • Anddo

        Sorry I made it not clear.

        "That said, I wouldn’t be surprised if there was an x.5 floating point value that was represented internally as x.49999 and gets rounded down instead of up."

        Seems that what happened. The results you presented at first were the same output I got using your solution !! on Visual Studio 2015 and on XCode. However after using int16_t instead of int8_t, the results got out differently (correct though). After using int8_t again as in the original solution you presented, the output stayed correct unlike the first time I used int8_t as in the solution. My question if you can help me with explanation for this. And you’re right, x.5 floating point value represented internally as x.49999 could cause such result. Thank you for your solution about input string, it appears it is the best really.

        Kinda question out of the subject, there are many calculation applications dealing with such numbers, do you think it’s the best approach to handle floating numbers as strings or integers (like in this quiz by making numbers after the dot integers) ? Or there are better mmmmmm techniques ?

        Again thank you 🙂

  • Matthew senko

    I couldn’t get through either question by myself, I had to look at the solution. I understand the concepts I just don’t know how to utilize them. What do you recommend I do? Should I continue on with the proceeding chapters?

    • Alex

      A couple of thoughts:
      1) These exercises aren’t easy. They’re designed to make you think and experiment a little bit. Even if you didn’t get the right answer yourself, make sure you understand how the programs work.
      2) You can practice by creating some exercises for yourself. Think up a use case where it would be useful to implement overloaded operators and write a simple program that uses them.
      3) You should continue onward. Often concepts will get reinforced later, which will give you additional context to understand them.

      That said, I’d love some feedback on where you got stuck in both cases. Maybe some additional hints would help future readers.

  • Matthew senko

    Where is array.m_length coming from?

    • Alex

      This is a copy constructor, so we’re going to make a copy of an IntArray from an existing IntArray. That existing IntArray is being passed in as parameter array. Because array is an IntArray, it has a m_length and an m_array member. We can access them directly since the constructor is a member of IntArray.

      I’m not sure I ever mentioned that last part in the Copy Constructor lesson. I’ll add it.

  • Sharjeel Safdar

    Hi, Alex!

    I think there is some problem with your code for the overloaded operator+ in Quiz 2c.

    I have written the following code for overloaded opertor+:

    I’m very bad at comments. 🙁

    I wrote the following test code for this function to test all the control paths:

    This test code gave me the results as expected:

    After this I saw your code in the solution to quiz:

    I tested your code with my test function which gave me the results:


    It seems that your code couldn’t handle the cases when both FixedPoint2 objects are negative and when the first object is negative and the second one is positive. I hope you will take a look at my code. I know that my code contains a lot of redundant code; so I hope you will also improve mine in that aspect.

    Also, the constructor in your code:

    Here, the 7th line should be

    Because without the abs() function the m_decimal part of a negative fixed number will also be negative (e.g. for -5.892: m_base = -5 and m_decimal = -89)

    Still, we love your tutorials and your magnificent efforts.

    (I use Visual Studio 2015 Community IDE.)

    • Alex

      You are indeed correct. I didn’t adequately test my code in all cases.

      So, a few changes:
      1) I’ve fixed the code per your suggestions.
      2) This program has gotten complicated enough that I’ve moved it from question #2 to question #4 -- it is now extra credit. I’ll create a new #2 as soon as I think of something good.
      3) I hope you don’t mind, but I integrated your test function into the quiz question and answer. I like how it shows a way to test your code and goes through all the various permutations. Well done!

      • Sharjeel Safdar

        Thank you, Alex. 🙂
        I have learnt all the things (I know) from your website.

        • Alex

          I realized today that this program can be simplified if we let the fractional component have the same sign as the non-fractional component. I’ve updated the example. Check out how much more straightforward the operator+ is now.

          • Sharjeel Safdar

            You are right.

            • Hey, this thing again. To solve this I had to flag for overflows with different sign values. The solution you present on the view solution yields


              I solved it thus:

              I admit it’s clunky., but it does single out the cases where it didn’t work before(and neither does the solution) - overflow with different signs - and fixes them.

              If your solution works for you then I wonder why it doesn’t for me.

              Thank you very much for this website. It’s been quite a ride through C++. I’m going into lesson 10 now!

              • Alex

                I just recompile the solution presented in the lesson and I got all trues. That’s interesting that you didn’t -- perhaps I did something I shouldn’t have (that just happens to work in Visual Studio)?

                With the reference solution, you should never get overflow if the two numbers have opposite signs. Consider: In the reference implementation, the decimal has the same sign as the main number, so if the two numbers have opposite signs, the decimal will have opposite signs. For the positive number, the decimal will be between 0 and 99. For the negative number, the decimal will be between -99 and 0. If you add the two together, you can never get a number less than -99 or greater than 99. Thus, no overflow possible.

                I did realize that I’d made a small mistake in the test cases (that didn’t matter for my reference solution, but may matter for other solutions), so I updated the bottom 4 cases. But that should be irrelevant for the reference solution and this discussion.

                • Thanks for the reply.

                  I just copied your solution and got all trues. Then I copied just your solution for the operator+ function (which was what I did before), thinking there was something wrong elsewhere and… got all trues.

                  I can’t really explain it. I’m sorry to have put you out. The code works and is much simpler than mine, which is byzantine. I was getting to a headspace of frustration and so I did that tailor-made solution for my problem. I think if I’d stopped and returned later with fresh eyes, I’d have come up with a solution close to yours.

                  I hope I would anyway.

                  Thanks a bunch.

      • Nivash

        Hi Alex,

        Since there is double cast support, would you advise below code for operator+ implementation? I feel this looks cleaner and less error prone.

  • sigil

    First of all, thank you very much for your quite comprehensive tutorials. I’m renewing my memories of C++ proper after a long detour into C++/CLI, and your site really helps. A few comments on this particular part, if I may:

    1. (2c) does not require an overloaded binary operator+. The


    expressions work okay by converting the arguments to doubles. Just comment the operator+ out; output will not change. Further still, we can use doubles for math to simplify this operator greatly if we decide to keep it.

    2. In (3), the const qualifier in the

    line seems to be redundant.

    3. In (3) again, wouldn’t it be more natural to use an unsigned int for array indices? Would save us the negative value checks, even if in the debug version only.

    • Alex

      A few thoughts:
      1) You’re right, it’s not required. But writing one is good practice, and it’s probably more efficient as well. If we rely on the double conversion then we have to convert two FixedPoint2 into anonymous doubles, and then convert them back to a FixedPoint2 to do a single addition. With an overloaded operator+, we can avoid the extraneous conversions and just deal with a temporary FixedPoint2 to return the result.
      2) It’s not redundant. It helps ensure we don’t accidentally change the value of index.
      3) No. If you use unsigned integers and someone passes in a negative number like -1, C++ will implicitly convert it to a very large integer, and you’ll end up walking off the end of your array, and the OS will probably shut down your program. With signed integers, we can detect if someone tries to do this and handle it. I talk a little bit about this in lesson 2.4a.

  • sigil

    1) Okay, I see your point. Depending on the implementation of both conversion and operator+, there may be cases where your solution is more efficient.
    2) Still not sure what you mean? We are passing the index by value, it’s a copy. Would not be able to change the original even if we wanted to.
    3) Thanks for the reminder not to expect others to have static analysis tools. *smile* You are correct here. It’s a C relic compilers would let slip.

    • Alex

      For #2, it’s true you can’t change the value of the argument, but you could inadvertently change the value of the parameter. In this case, making the parameter const disallows changing the parameter, so we can guarantee that whatever our function does, the parameter will always be equal to the value of the argument, not inadvertently changed to some other value.

      It’s just a minor tool to help us not make mistakes.

  • jered

    in question 2, why does the output yield massive numbers if you leave the member variables uninitialized?

    int32_t m_sum;
    int8_t m_count;

    as opposed to:
    int32_t m_sum=0;
    int8_t m_count=0;

    • Alex

      C++ doesn’t do initialization of fundamental types if you don’t assign an initializer. Therefore, when an uninitialized variable is assigned memory, that memory will still have whatever garbage value was in there previously. If you print this to the console, then you’ll print this garbage value (as an integer).

      • jered

        Hi Alex,

        But doesn’t the class use a constructor that utilizes memberwise initialization?

        Oddly, it is only when I provide a constructor that uses memberwise initialization that I am able to get the values to print desired results (while using uninitialized member variables).

  • Alex

    I see where your confusion is. You should probably re-review lesson 8.5b -- Non-static member initialization.

    Classes can initialize members in one of two ways: either by using non-static member initialization in the member definition, or using a member initialization list in the constructor.

    If you look at the Average class, it uses non-static member initialization to initialize its members. The default constructor doesn’t do any additional initialization of its own.

    Therefore, if you remove the non-static member initializers and then instantiate an object, m_sum and m_count never get initialized (because the constructor isn’t doing it).

    If you add a member initialization list to the Average constructor, then it will initialize the members.

  • Matt

    In your solution for quiz# 3, in your friend function, I think "std:cout" should be "out".

    Also, this is the first time I noticed that you defined a friend function within the class that it’s declared. Was that a mistake, or is it acceptable to do it that way?

    Also, within the same solution, in the constructor, I noticed that you used the assert function differently than had been taught earlier(to my recollection at least). It’s not difficut to figure it out, but I still think a comment in the code would be helpful too.

    • Alex

      1) You’re correct, I’ve fixed the example.
      2) I did it that way for conciseness, you’re better off putting your functions in a .cpp file. I updated the lesson on overloading operators as friend functions to note that you can do this.
      3) That’s because I made a mistake. I’ve updated the example. I’ll update the lesson on assert to explain this as well, because it can be useful.

  • Christos

    Hi Alex,

       I added a few lines of code inside quiz 3, as live annotation to show the steps in the order executed.
       I would like to ask about the execution of "return" command of the fillArray function. When executed the "return a;" command inside the fillArray, this calls the copy constructor to construct and initialize "a" object of the main function. Is there any intermediate copy step through the fillArray() caller?
       I would like to understand the background steps from the point after the "return a;" has been executed, until the complete of  the command line "IntArray a = fillArray();".

    Thank you,

    • Alex

      > When executed the “return a;” command inside the fillArray, this calls the copy constructor to construct and initialize “a” object of the main function. Is there any intermediate copy step through the fillArray() caller?

      This _may_ call the copy constructor. If it does, main::a is the primary object, and fillArray::a is the copy constructor parameter. The copy constructor handles doing the copy, and that’s all that happens (there’s no other steps).

      However, the copy may also be elided, which is what I see in Visual Studio 2015. That may or may not be the case for your compiler.

  • Tomas

    Heey Alex!
    These exercises are great impressive job!

    I have a question.
    Since we put our fraction part as an int8_t it is still possible for a value to be more than 99 and less than -99 maybe it would be a good idea to iplement this code?

    • Tomas

      This is what i meant in the 2nd part

    • Tomas

      Oh my bad I saw that it was used in 4c 🙂

      • Alex

        That was only for adding two FixedPoint2 together (when you could run into this situation normally). Without addressing the issue in the constructor, you could still create an invalid FixedPoint2 in the first place.

    • Alex

      You’re probably right, this could happen, even though it’s a misuse of the class. I’ve added a comment to the code indicating that we should handle those cases in the constructor.

      [Edited to remove misleading comment]

      • Tomas

        But if we are using int8_t isnt the range -127/128?

        • James

          Dear both,

          Alex’s code now passes all of Sharjeel Safdar’s tests and his own tests. Remarkably, none of these tests handles the case where the sum of the decimal parts overflows an 8-bit integer, e.g.,

          which, by chance, was the first test I ran, and is certainly not a misuse of the class. This passes all tests:

          I guess it works because my compiler (gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4)) doesn’t know of any

          and does an implicit conversion from int8_t to int somewhere.

          Now I’ve got this far, I realise this may the point Tomas was making 🙂


          • Alex

            Yes, you (or Tomas) found a flaw in the original solution -- adding two m_decimal and assigning the result back to an int8_t variable could result in overflow, and the test cases didn’t uncover this possibility.

            Your solution is better, as it avoids overflow by leveraging the fact that adding two int8_t together results in integral promotion to an integer and adjusting back down into range before creating a new decimal.

            I was going to use your code for the updated solution, but I realized all three of your cases could be collapsed into two statements with no branching. Check it the updated quiz solution, you’ll probably find it interesting.

            • James

              Ah… I was trying to come up with something that used the sign of the sum, before I came up with the above. All of my attempts were ugly (and didn’t work). Thanks for sharing.

        • Alex

          Yes, of course. Not sure what I was thinking yesterday.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter