11.x — Chapter 11 comprehensive quiz


Inheritance allows us to model an is-a relationship between two objects. The object being inherited from is called the parent class, base class, or superclass. The object doing the inheriting is called the child class, derived class, or subclass.

When a derived class inherits from a base class, the derived class acquires all of the members of the base class.

When a derived class is constructed, the base portion of the class is constructed first, and then the derived portion is constructed. In more detail:

  1. Memory for the derived class is set aside (enough for both the base and derived portions).
  2. The appropriate derived class constructor is called.
  3. The base class object is constructed first using the appropriate base class constructor. If no base class constructor is specified, the default constructor will be used.
  4. The initialization list of the derived class initializes members of the derived class.
  5. The body of the derived class constructor executes.
  6. Control is returned to the caller.

Destruction happens in the opposite order, from most-derived to most-base class.

C++ has 3 access specifiers: public, private, and protected. The protected access specifier allows the class the member belongs to, friends, and derived classes to access the protected member, but not the public.

Classes can inherit from another class publicly, privately, or protectedly. Classes almost always inherit publicly.

Here’s a table of all of the access specifier and inheritance types combinations:

Access specifier in base class Access specifier when inherited publicly Access specifier when inherited privately Access specifier when inherited protectedly
Public Public Private Protected
Private Inaccessible Inaccessible Inaccessible
Protected Protected Private Protected

Derived classes can add new functions, change the way functions that exist in the base class work in the derived class, change an inherited member’s access level, or hide functionality.

Multiple inheritance enables a derived class to inherit members from more than one parent. You should avoid multiple inheritance as much as possible.

Quiz Time

1) For each of the following programs, determine what they output, or if they would not compile, indicate why. This exercise is meant to be done by inspection, so do not compile these (otherwise the answers are trivial).


Show Solution

1b) Hint: Local variables are destroyed in the opposite order of definition.

Show Solution


Show Solution


Show Solution


Show Solution

2a) Write an Apple class and a Banana class that are derived from a common Fruit class. Fruit should have two members: a name, and a color.

The following program should run:

And produce the result:

My apple is red.
My banana is yellow.

Show Solution

2b) Add a new class to the previous program called GrannySmith that inherits from Apple.

The following program should run:

And produce the result:

My apple is red.
My banana is yellow.
My granny smith apple is green.

Show Solution

3) Challenge time! The following quiz question is more difficult and lengthy. We're going to write a simple game where you fight monsters. The goal of the game is to collect as much gold as you can before you die or get to level 20.

Our program is going to consist of 3 classes: A Creature class, a Player class, and a Monster class. Player and Monster both inherit from Creature.

3a) First create the Creature class. Creatures have 5 attributes: A name (std::string), a symbol (a char), an amount of health (int), the amount of damage they do per attack (int), and the amount of gold they are carrying (int). Implement these as class members. Write a full set of getters (a get function for each member). Add three other functions: void reduceHealth(int) reduces the Creature's health by an integer amount. bool isDead() returns true when the Creature's health is 0 or less. void addGold(int) adds gold to the Creature.

The following program should run:

And produce the result:

The orc has 3 health and is carrying 15 gold.

Show Solution

3b) Now we're going to create the Player class. The Player class inherits from Creature. Player has one additional member, the player's level, which starts at 1. The player has a custom name (entered by the user), uses symbol '@', has 10 health, does 1 damage to start, and has no gold. Write a function called levelUp() that increases the player's level and damage by 1. Also write a getter for the level member. Finally, write a function called hasWon() that returns true if the player has reached level 20.

Write a new main() function that asks the user for their name and produces the output as follows:

Enter your name: Alex
Welcome, Alex.
You have 10 health and are carrying 0 gold.

Show Solution

3c) Next up is the Monster class. Monster also inherits from Creature. Monsters have no non-inherited member variables.

First, write an empty Monster class inheriting from Creature, and then add an enum inside the Monster class named Type that contains enumerators for the 3 monsters that we'll have in this game: DRAGON, ORC, and SLIME (you'll also want a MAX_TYPES enumerator, as that will come in handy in a bit).

Show Solution

3d) Each Monster type will have a different name, symbol, starting health, gold, and damage. Here is a table of stats for each monster Type:

Type Name Symbol Health Damage Gold
DRAGON dragon D 20 4 100
ORC orc o 4 2 25
SLIME slime s 1 1 10

Next step is to write a Monster constructor, so we can create monsters. The Monster constructor should take a Type enum as a parameter, and then create a Monster with the appropriate stats for that kind of monster.

There are a number of different ways to implement this (some better, some worse). However in this case, because all of our monster attributes are predefined (not random), we'll use a lookup table. A lookup table is an array that holds all of the predefined attributes. We can use the lookup table to look up the attributes for a given monster as needed.

So how do we implement this lookup table? It's not hard. We just need two things. First, we need an array that contains an element for each monster Type. Each array element will contain a struct that contains all of the predefined attribute values for that Type of Monster.

Since all the properties of monsters are known at compile-time, we can declare make the lookup a static constexpr member of Monster. The definition of the lookup table is as follows:

A reminder

If you get an error in the declaration of monsterData, make sure your compiler is C++17 capable by trying to compiling the example in lesson 0.12 -- Configuring your compiler: Choosing a language standard.

Now we can index this array to lookup any values we need! For example, to get a Dragon's gold, we can access monsterData[Type::DRAGON].gold.

Use this lookup table to implement your constructor:

The following program should compile:

and print:

A orc (o) was created.

Show Solution

3e) Finally, add a static function to Monster named getRandomMonster(). This function should pick a random number from 0 to MAX_TYPES-1 and return a monster (by value) with that Type (you'll need to static_cast the int to a Type to pass it to the Monster constructor).

Lesson 5.9 -- Random number generation contains code you can use to pick a random number.

The following main function should run:

The results of this program should be randomized.

Show Solution

3f) We're finally set to write our game logic!

Here are the rules for the game:

  • The player encounters one randomly generated monster at a time.
  • For each monster, the player has two choices: (R)un or (F)ight.
  • If the player decides to Run, they have a 50% chance of escaping.
  • If the player escapes, they move to the next encounter with no ill effects.
  • If the player does not escape, the monster gets a free attack, and the player chooses their next action.
  • If the player chooses to fight, the player attacks first. The monster's health is reduced by the player's damage.
  • If the monster dies, the player takes any gold the monster is carrying. The player also levels up, increasing their level and damage by 1.
  • If the monster does not die, the monster attacks the player back. The player's health is reduced by the monster's damage.
  • The game ends when the player has died (loss) or reached level 20 (win)
  • If the player dies, the game should tell the player what level they were and how much gold they had.
  • If the player wins, the game should tell the player they won, and how much gold they had

Here's a sample game session:

Enter your name: Alex
Welcome, Alex
You have encountered a slime (s).
(R)un or (F)ight: f
You hit the slime for 1 damage.
You killed the slime.
You are now level 2.
You found 10 gold.
You have encountered a dragon (D).
(R)un or (F)ight: r
You failed to flee.
The dragon hit you for 4 damage.
(R)un or (F)ight: r
You successfully fled.
You have encountered a orc (o).
(R)un or (F)ight: f
You hit the orc for 2 damage.
The orc hit you for 2 damage.
(R)un or (F)ight: f
You hit the orc for 2 damage.
You killed the orc.
You are now level 3.
You found 25 gold.
You have encountered a dragon (D).
(R)un or (F)ight: r
You failed to flee.
The dragon hit you for 4 damage.
You died at level 3 and with 35 gold.
Too bad you can't take it with you!

Hint: Create 4 functions:

  1. The main() function should handle game setup (creating the Player) and the main game loop.
  2. fightMonster() handles the fight between the Player and a single Monster, including asking the player what they want to do, handling the run or fight cases.
  3. attackMonster() handles the player attacking the monster, including leveling up.
  4. attackPlayer() handles the monster attacking the player.

Show Solution

12.1 -- Pointers and references to the base class of derived objects
11.7 -- Multiple inheritance

298 comments to 11.x — Chapter 11 comprehensive quiz

  • Addict

    The game giveth, the game taketh away.

  • Hi Alex,

    My that one stretched my mind a bit.

    I tried to put the isDead() calls in a while statement:

    but that just created a never ending recursive loop.

  • for 3a I have the following solution:

    I had to replace the void in the two function calls to reduceHealth() and addGold() with int as otherwise it wouldn't compile and produced error described in comments.

  • Hi Alex,

    The fruit one (2a and 2b) was similar to one of the earlier examples.  I have it thus:

  • Silviu

    // If the player is dead, we can't attack the monster

    -isDead function return true if m_health<=0
    the player always starts with 10 health.
    so it won't go in the "return".It will go on the next lines. ok
    But when health is 0 , then is true , goes into the condition of the line 2 and what returns ? (line 2, does it return 0 ?)

  • Nitin

    Typo: always inherit publically --> publicly.

  • gabriel

    Hi Alex,
    in the game quiz, when writing the get random monster function, why i get a compiler error when i put the get random number function inside the monster class?

  • papaplatte

    Quiz time 2b: Why can't GrannySmith call the Fruit constructor?

  • Nguyễn Anh Tuấn

    I don't understand line 19 in solution 3a.

    const std::string& getName() { return m_name; }

    Why use "const" and "std::string&"?
    Thank you so much!
    (Sorry! I speak English very bad. :( )

    • Hi there!

      @m_name is returned by reference, because returning by value would create a copy of the string, which is slow.
      It's returned by const reference, because the caller of @getName should not be allowed to modify @m_name.

      Lesson 7.4a - Returning values by value, reference, and address

  • Donlod

    Because we are using the getRandomNumber() function in two .cpp files I extracted it into a separate utils.h files. This files is #included in main.cpp and monster.cpp. The program wont compile if the function is not marked static, because at linking stage there would be two functions with the same name.
    Is it right to fix it this way? To me marking the function as static feels like a quick hack.

    • utils.h should only contain the function declaration, not the definition. The definition goes into utils.cpp.

      • Donlod

        Well thats true, youre right.

        Is making a function static for this reason bad? I also saw code that marked some functions as inline and the others were implemented in a separate .cpp file.

        What about variables? Like pi etc in a math header. They need to be static in this case.

        • > Is making a function static for this reason bad?

          > What about variables?
          If they're constants (like pi) you can define them in the header as static constexpr.
          If they're variable, declare them extern and define them in a source file.

  • Jack

    Final solution for the game is missing a

    at the end

  • Jack

    For the lookup table, I decided to use std::array rather than the C Style array. I used:

    Inside the class, and:

    outside of the class. This resulted in an error saying 'too many initialisers for 'std::array''. A bit of Googling showed that I needed:

    But I cannot figure out why. Presumably it's something to do with the fact that (similar to how, in the IntArray container (lesson 10.6)) std::array is built on-top of the the traditional C-style array, but why does it require extra {} at the start and the end?

    • nascardriver

      Hi Jack!

      @std::array doesn't have a constructor for list initialization, so you have to initialize it's members directly. That member is a C-Style array, which requires another set of curly braces to be initialized.
      In you code, you have (and need) 3 sets of curly braces:
      1. Uniform initializer braces for @std::array.
      2. List initializer braces for the C-style array inside @std::array.
      3. Uniform initializer braces for your monsters.

      I don't know why @std::array doesn't have a constructor for list initialization, it would make it's use a lot more intuitive.

  • DecSco

    Question 2b) I tried to give default values to the protected constructor in the Apple class. However, then the compiler complained about the call

    as being ambiguous.
    Given that main() cannot access that constructor, why would that be the desired behaviour for the compiler?

    • nascardriver

      Hi DecSco!

      The compiler tries to find a matching function _before_ resolving access modifiers.
      I'd like it better the other way around, but that's the way it is.

  • David

    Do you think its better practice to encapsulate the random number generation for the monster class? Here's what I did:

    • Alex

      Personally, I don't think so, because the act of picking which monsters should be generated is separate from how monsters are represented. Putting them together in one class adds complexity.

  • johnsmith29a

    Damn, this game is addictive! But with initial player HP set to 10 it's just too difficult. 20 works much better.

  • Saumitra Kulkarni

    This is a bit irrelevant doubt, I was just curious how the default copy constructor would work.

    If we were to do something like this in main()

    And our default copy constructor would be something like this

    Now in our getRandomMonster() function copy constructor would get called while returning by value,
    So how does the copy constructor know which type of Creature we are dealing with ?

    • Alex

      The parameter for Creature(...) in your example should be m. This will cause the Monster copy constructor to call the Creature copy constructor on the Creature portion of the m object.

  • Mireska

    I wrote this  as

    Slightly more simplistic, but made me wonder if there is a specific reason you didn't do it like that; like for clarity's sake, for convention or because the random function doesn't play nice with randoming 0? Just throwing out possibilities.

    I had a lot of fun with this! It really made me appreciate classes and how they allow you to put the important but intricate stuff 'behind the scenes', improving clarity tenfold!

    • Alex

      I did it this way just because most of us are familiar with the concept of rolling dice to resolve "random events" from childhood board games. In this case, I roll a 2-sided dice, and if it comes up as a 1, the user is able to flee.

      Your approach of picking a random number 0 or 1 is just as valid, and may be more efficient.

  • Ran

    This is my version of this game. Welcome to play and suggestions.


  • Ran

    I was struck by using std::array to declare monsterData. I thought it
    was better to use std::array instead of using the c-style array.

    My compiler(default MS2017 on Win7) just gave this:

    Severity    Code    Description    Project    File    Line    Suppression State
    Error (active)    E0147    declaration is incompatible with
    "std::array<Monster::MonsterData, 3U> Monster::monsterData" (declared
    at line 99)    

    This is where I was confused.

    Why std::array not work?

    To me, there is no difference between the c-style array:

    • nascardriver

      Hi Ran!

      Looks like you have a forward declaration of @monsterData that's different from it's definition. If that's not the case make sure @MonsterData and @Monster are defined before the definition of the array and that you

      If you're still having trouble please share your full code or use a C-style array for now and I'll replace it with an std::array in your submission.

  • Ran

    Could someone explain why Alex defined member variables of the class in
    the Creature class using protected attribute in the Question 11.x.3.b?

    I have tried the way (using protected), but I was not very comfortable
    using this kind of declaration. In fact, I tend to use "private" in the
    creature class. To access the private member from the derived class, I
    just added a public function within the Creature class:


    To access the m_attackDamage, in the Player class I used:

    What are the weaknesses of doing so? What are the advantages to use
    protect member variables in the creature class?

    • nascardriver

      Hi Ran!

      > To access the private member from the derived class, I just added a public function within the Creature class
      Well then that function should be protected, because the outside isn't supposed to be accessing this variable. Is some cases this might work, but what if a child wants to increase @m_attackDamage by 2?

      Declaring the variables protected allows every child to perform completely unrestricted access to those variables so they can be modified in any imaginable way. If one uses your solution this is not possible (Unless you have a function that grants direct access to private variables, in that case you might as well not declare the variable private).

  • Tin

    I have some troubles with my code:

    There are somethings wrong about it but i can't find it out, help!
    This is a link to the error list.

    • nascardriver

      Hi Tin!

      > error: ‘Monster’ has not been declared
      Add a forward declaration for @Monster, pass the @Monster and @Player to the attack functions by reference. Define @attackMonster after the declaration of @Monster.

      > undefined reference to `Monster::Monster()'
      Define Monster::Monster

      > error: no matching function for call to ‘Creature::Creature()’
      Define Creature::Creature

      Don't place semicolons after function definitions.

      The code compiles. It should really be split into multiple files.

  • Jeffery

    The solution for 3a has this for the get functions:

            const std::string& getName() { return m_name; }
        char getSymbol() { return m_symbol; }
        int getHealth() { return m_health; }
        int getDamage() { return m_damage; }
        int getGold() { return m_gold; }

    Why is the only const reference the string/getName()? Also why aren't the rest of the get functions const i.e: int getGold() const { return m_gold; }

    • nascardriver

      Hi Jeffery!
      getName returns a const reference to a string, if it wasn't const we'd be able to modify the value of m_name directly using the return value of getName.

      The other functions don't need to return const types, because they aren't references. getName is a reference, because passing a string by value is slow.

    • Alex

      Hey Jeffery,

      The functions really should be const functions as they are used in a read-only capacity.

      getName() returns a const reference because std::string is a class and we generally don't want to pass classes by value (because making a copy is expensive). For fundamental tpes (int, char), this isn't an issue, so we can just return by value.

  • Ioan

    Hello, Alex,

    i've got here a problem, it is not from your website, that I can not solve. It sounds like this:

    Define a Class named Components that contain a pointer to a string called name.
    From this class derive two classes, Processor, with frequency as int, and Screen with diagonal also as int.
    Each of the two derived classes contains a name and frequency display function for Processor and a name and diagonal for Screen. Then define a Computer class that contains as
    member data a Processor object and a Screen object and a display function of the contained objects. Define
    required constructors and display functions and built into the main function () a Computer object with
    Dual Core processor and 17-inch Samsung monitor.
    Display the data for this object using the display function defined in the Computer class.

    This is my code. The major problem is at Computer class:

    • Alex

      Well, your Computer constructor is defined as needing two parameters (freq and diag) but you're not passing in values for those in main().

      I also note that your Computer constructor calls Processor and Screen but don't pass in a name (presumably these can just be string literals).

      So fix those problems (and the various spelling errors) and it should at least compile.

      • Ioan

        I changed the Computer class, because it was(is) probably a strong source of my problems.

        Does it look better now?
        I also replaced the old "void print()" functions from the whole program, with overloaded operator<<.
        Also I do not know how to call "name" corectly in the other classes, like Screen and Processor.
        Thank you very much for the prompt response you gave me earlyer! And for this really complex and detailed tutorial.

        • Alex

          You've moved from an inheritance model to a composition model, which I think is good. A computer _has_ a processor and a screen, so composition is a better fit than inheritance.

          If your intention is to allow the user to pass in the Processor and Screen, then this seems fine.

          For your overloaded operator <<, you should be able to std::cout << c.m_name (because Computer is publicly inherited from Component, so you can access protected member m_name directly).

  • Mike

    Hi Alex,

    First, thanks for this tutorial. My friends ask me why I'm learning C++ instead of whatever coding boot camp language they're learning, and I tell them it's because I found a really good tutorial.

    On 2(b), the solution won't compile if the Apple constructors use default parameters, like this:

    Apparently, the default parameters make the function call ambiguous. Why is that?

    • nascardriver

      Hi Mike!

      In your case, when you call

      the compiler cannot know if you want (a) to call constructor 1 or 2.
      It also doesn't know if you want (b) to create a Fruit("green", "red") or a Fruit("Apple", "green").
      Default parameters are useful to an extent. If you use them without care you'll get overlapping functions signatures.

      Here's what happens to the functions at compile time. (Note: Some of these will be optimized away when they aren't used).

    • Alex

      Nascardriver gave a nice, long answer. Here's a short one: A class can only have one default constructor. The above Apple class has two! (as Nascardriver points out, this causes ambiguities when trying to call Apple() or Apple(std::string), as the compiler won't know which one you mean).

  • AMG

    I think the following condition in "attackMonster" is redundant (at least in this version), because "fightMonster" "while" loop has the same condition and it will be executed first.

    Awesome exercise. Thank you sooooo much.

  • hex4d0r

    Why we need const reference return value?

    Is it for just for memory optimization or??


    Monster class is pretty confusing to me.

    We create an enum ... OK!
    We create a struct ... OK!

    Why we defined name as a const char pointer?
    (maybe for dynamic allocation? Because names has different lengths.)


    We defined a static array type of MonsterData and size it to MAX_TYPES, which is 3.

    The lookup table. We defined a static array but we didn't initialize it. We initialized it out of Monster class scope with a confusing syntax.

    Thoose are elements of monsterData array,

    Shouldn't we use paranthesis"(-)" over curly braces"{-}" for seperating elements of this array?

    I don't feel right with this syntax.

    By the way, this is my first comment on here. All I can say this guide, tutorial, book or whatever you name it, It's a treasure.

    Sorry for terrible English.

    • Alex

      1) We return a const reference so we don't make a copy of the std::string every time the function is called.
      2) We define the name as a const char* because the names themselves are defined elsewhere -- we just need to point to them.
      3) Each element of the monsterData array is a struct object. We initialize struct objects using curly braces.

  • Haresh

    Monster::MonsterData Monster::monsterData[Monster::MAX_TYPES]

    Could you explain why we need to have MAX_TYPES inside [] and what is its purpose?


    • Alex

      It tells the compiler how many elements are in the array.

      Technically, it isn't required, as the compiler can infer how many elements should be in the array from the initialization values, but it's useful to have it so the compiler can warn you if you try to provide too many initializers.

  • Sihoo

    Hi Alex,

    I understand this formula, but I am still struggling recalling this formula and also there seems no way I could even come up with such formula on my own although the formula seems rather simple on surface. Should I be worried?

  • Dani

    hello Alex...
    when i try to solve 3d question, i compile my code like this...

    using namespace std ;

    class Creature
        string m_name ;
        char m_symbol ;
        int amount_of_health;
        int damage_per_attack ;
        int amount_of_gold_carrying ;
        Creature(const string &name = "", const char &symbol = ' ',const int &health = 0 , const int &attack = 0 ,const int &gold = 0 )
        :m_name(name) , m_symbol(symbol) , amount_of_health(health) , da