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

326 comments to 11.x — Chapter 11 comprehensive quiz

  • Parsa

    Why do we need an extra set of curly braces here?

    • nascardriver

      See section "Array of struct" in lesson 6.15

  • choofe

    I have written a function to distribute the chance of appearing an outcome to be customized. It may sounds useless and there may be better such things but I came up with it myself. And want your opinion on that. Because it seems a little inconsistent.I used it instead of getRandomNumber(). My approach to last question is also a bit different.I really can use your comment.

    • nascardriver


      - Name variables descriptively. Abbreviations don't provide enough information to make your code easy to read.
      - Pass/return non-fundamental types by const reference. Copying them is expensive. (`Creature::getName`, `operator<<(std::ostream&, Monster&)`, some more missing `const`) - Line 126: Good comment. For documentations, you can use documentation comments

      Documentation comments allow you to generate a documentation of your code later and can help your IDE with suggestions. - Line 146 and 141 are unreachable. - Use single quotation marks for characters. Strings are more expensive. `monsterDist` and `fleeChance` aren't intuitive to understand. It'd be easier if they had values like { 20, 35, 45 } and { 50, 50 }. If you use a `std::map`, you can very explicitly map a chance to each outcome like so

      In you current approach, you should have use `std::array`, because you know the values at compile-time. Then you could have used `static_assert` to verify 0 and 100 are there. You could even remove 0 and 100, because they have to exist in every distribution. `customDist` can work without them. Smart way of getting a result from generating a single random number though :)

      • choofe

        Thank you so very much for your time.
        >> Line 146 and 141 are unreachable. I didn't get this! because both lines will be executed.

        >> you should have use `std::array`, because you know the values at compile-time. I tried to do so. But don't arrays have to have known size at definition? I wanted the monsterDistribution()-changed the name as you mentioned- to take any distribution of chances. Like 50/50 and a 20,35,45

        >>`monsterDist` and `fleeChance` aren't intuitive to understand. You could even remove 0 and 100, because they have to exist in every distribution. `customDist` can work without them.

        I did this:(thanks to your commenst)

        • nascardriver

          > Line 146 and 141 are unreachable
          I meant 136 and 141, sorry. The `return` stops execution. Nothing after it gets executed.

          > std::array
          I didn't think about `customDistribution`. In that case, if your compiler supports `std::span` from C++20, you can still use `std::array` for `monsterDist` and `fleeChance` and use `std::span` for `customDistribution`.

          `std::span` is a view into an arbitrary container with sequential elements, so it works for `std::vector` and `std::array`. If you don't have access to `std::span`, use `std::map` or `std::vector`.

          More things I didn't notice last time:
          - `customDistribution` accesses the vector without verifying its size. Before you access it, assert that there are at least 2 elements. (In your updated code, the size has to be at least 1).
          - `std::vector::size_type` isn't guaranteed to be `unsigned int`. Because you made this assumption, your code doesn't compile for me. Use `auto` for `customDistribution::s`.
          - Enable compiler warnings, read them, fix them. `customDistrubution` should have a `void` return type.

          • choofe

            Thank you again,
            >>if your compiler supports `std::span` I'm using VS19 and change the standard to latest ... but I think it is not supported!
            so I gave up to vector and const.I wonder if it is another way beside vector so I can use constexpr. I don't know anything about std::map ,is there a lesson covering that?
            >>In your updated code, the size has to be at least 1). It should but it does not mean anything because it returns 100% of the only outcome. So I assert it to be at least 2 and member sum to 100.
            >>Enable compiler warnings, read them, fix them. `customDistrubution` should have a `void` return type. I did so but no warning! and why it should has void return type? All the purpose of this function is to return a random int number to represent the outcome the caller wants to handle.
            I have updated the code with a 10000 calling loop to see the results:

            one result is :
            outcome chance #1 is: 20 and frequency is: 19.63%
            outcome chance #2 is: 25 and frequency is: 24.23%
            outcome chance #3 is: 25 and frequency is: 25.4%
            outcome chance #4 is: 20 and frequency is: 19.96%
            outcome chance #5 is: 10 and frequency is: 10.78%

            • nascardriver

              It'd like to correct my previous recommendation of using `std::array` with `static_assert`. `static_assert` would only verify your 2 existing distributions, but the assertion should be performed on the input of `customDistribution`, so regular `assert` was the better choice.

              > another way beside vector so I can use constexpr
              You can use `std::array` with `gsl::span` from the guidelines support library ( ). It's the predecessor to `std::span` and serves the same purpose.

              > I don't know anything about std::map ,is there a lesson covering that
              No, but `std::map` is fairly straightforward ( ). It maps values of one type to values of another type. Similar to an array, but your indexes aren't integers, but whatever type you like (It has to have an `operator<` (Enum classes have an `operator<`)). > the size has to be at least 1
              1, because you're doing `s - 1` and that would wrap around if `s` is 0. If `s` is exactly 1, your function can still compute meaningful results (Assuming you fixed your compiler warnings, right now it's UB). It will do a bunch of unnecessary computations, but that's better avoided by using an `if`. `assert`s are used to catch mistakes made by a developer. It's valid to have only 1 monster, you program should continue to work.
              I think calling it with 1 element should be legal, but if you say that is never allowed to happen, that's fine too.

              > `customDistrubution` should have a `void` return type
              I can't believe how many oversights I made yesterday. `customDistribution` shouldn't be void, it's returning an int. But, you should add a return-statement to the end. You might not be seeing a warning because you're compiling in debug mode. In debug mode, `assert`s are enable and line 32 (In you most recent snippet) is unreachable. In release mode, the asserts are ignored and line 32 is theoretically reachable (if `s` is 1), resulting in UB. Although the function should never be called with a 1 element list, because you tested in debug mode with asserts, it's better to have well-defined behavior in case it does somehow happen. Even if that behavior doesn't make sense, it's better than undefined behavior.

              • choofe

                WOW. I don't know how to thank you!
                This was very useful for me.
                I have some other questions about the issues here, but it seems it is not very related to subjects of this chapter.
                So I just let it go.
                In 2 months I have written such a simple program from knowing nothing about C++ and almost nothing about programming.
                This is a wonderful journey until here
                Thanks to you and Alex.
                You will see me again in the future lessons comments.

  • ruchika malhotra

    I have a doubt

    If I don't define it as static. It gives error -
    main.cpp:116:62: error: ‘Monster::MonsterData Monster::monsterData [3]’ is not a static data member of ‘class Monster’
      Monster::MonsterData Monster::monsterData[Monster::MAX_TYPES]
    1.Can you explain why it is giving error ?
    2. why we have to use constexpr when we are defining it inside?


  • Lucas Stern

    I know the problem with my code snippet below is because of the scope of my local Player variable on function createPlayer().

    There’s a way I can do this without having this error?

    Another problem i'm facing is with the part:

    After putting a full name, the cin still wait for me to press another enter. But I put this code before getline() so I can handle any case of another cin that may happens before calling createPlayer().
    I definitely forgot something here.

    • nascardriver

      Return the player by value. Don't worry about copies, `return`s use a faster method of copying (Covered later, move), or are removed altogether by the optimizer.

      If there's nothing in the input buffer, ie. you call `createPlayer` without having read any input before, `std::cin.ignore` will prompt for input. You should clean up after reading input, not before.

  • Ged

    Just checking some previous courses and trying not to forget. Why do I get no output when I write the array like this?

    • nascardriver

      If `monsterData` isn't static, it doesn't exist yet when the constructor gets called and you try access it.

      • Ged

        What is the difference if I use the return type 'Type'?

        • nascardriver

          Then you're no longer returning a `Monster`, but only a monster type. If you use the function like so

          the `Monster` get constructed from the type and you won't notice a difference. However, if you don't construct the monster but instead use the return value right away or use `auto`, the code won't work.

  • sito

    hello! could you give an example of how you would build a normal array? for this qui<? I have tried doing it the way you should in the quiz but with a normal array but i can't get it to work. thanks
    Something worth mentioning is that I didn't make the array static and const. In order for this to work in the qquiz does the array need to be const and static?

    • nascardriver

      Change the array definition to

      The rest stays the same.

      • Alan

        I got the same problem, but i don't get what is wrong with the "std::array" version. Is there something in the definition of "std::array" that doesn't allow it or it has something to do with the complier?

        • nascardriver

          There's nothing wrong with `std::array`. I don't know why @site wanted to use a built-in array. Do you have a problem with `std::array`?

  • sito

    Hello! i have some questions for quizz 3 d
    first, why can't you make a normal array like this? something like this MonsterData array[Monster::max_types]{{"dragon", "test"}}; I tried creating an array like that to use instead of the quiz suggestion but I couldn't get it to work. When debugging the program it exited with code 3 and I don't understand why it does that because from what i have found exiting with code 3 is related to memmory Also why do yu have so many brases when you make the array in the quiz suggestion?
    I also wonder why you make the array static? in my opinion there is no need to do it because you are later going to create the monster object and the monster object won't get destroyed until the program is done so why do this?

    • nascardriver

      > why can't you make a normal array like this?
      Normal arrays aren't as convenient as `std::array`. `std::array` has several member functions that make it easier to use and safer than built-in arrays.
      This quiz is totally possible with built-in arrays, you must be doing something else wrong.

      > why do yu have so many brases
      We explain this here

      > why you make the array static?
      If you don't make it static, every instance of the `Monster` class will get its own copy of `monsterData`. That's very wasteful. We only need one `monsterData` in the entire program.

  • kavin

    For quiz 2b) instead of adding extra protected class , i did like this.

    Is it ok to do this or using a protected class with a new constructor is a must ?

    • nascardriver

      You're now allowing the public to choose a name, which is not supposed to happen.

      "My orange is orange"
      But `kavin` is an apple.

      If you're ok with letting the public choose a name, then your solution is alright.

      • kavin

        Thanks for the clarification. I will make it a rule not to depend on the user/public to give correct values.
        And for quiz 3d) its mentioned,

        If we define the array outside the class, how could we access MonsterData since it has private access inside the class?

        • nascardriver

          Define `MonsterData` outside, but still declare it as a member inside.

          It doesn't matter if we defined members inside or outside of the class, they have access to other members.

  • Attila

    Hey Alex and Nascardriver,

    Could you please add in a lesson about circular dependency? I ran into it head-first with a practice project, and I would like to spare my fellow beginners from doing the same.

    • Alex

      It's referenced in several lessons, but I've added a to-do to cover it more explicitly as part of the ongoing site updates. Thanks for the suggestion!

  • Zhang

    Hello! I have a small question that why there is a "continue" in line 174 in the last code 3f?

    • nascardriver

      Without the `continue`, to code would keep running to line 178 and on, but that's not necessary, because that condition can never be true if we reached line 174.

  • Wayseeker


    First, I can't thank you enough for the tutorials you have presented here.  They are generally very complete and clear, especially given that I come to learning C++ with basically NO training in coding or programming except for a tiny bit of self-training in Basic Programming back in the early 90's when I was a teenager.  

    My goal--eventually--is to create my own roguelike game, which I know is a long way down the line, as I have a lot to learn.  Quiz 3d here has given me my first real frustration (other than the usual that comes with learning coding).  It may suggest a possible change that would help your tutorial.

    I wrote my code, then tried to compile it, and I got errors.  After researching through the tutorials and online for awhile, I decided to just look at the solution.  I was immediately struck by "#include <string_view>", which I felt reasonably sure I'd never seen before.  

    Eventually, I was able to resolve the issue by searching for string_view in the comments and finding the comment by arcad on December 30, 2019 at 5:56 pm.  Setting my project on Visual Studio to C++17 standards helped me solve the problem, but I wouldn't have known to do this without referring to this comment.  Also, it appeared to be a discussion among people who are already familiar with std::string vs std::string_view, so, even though the code now compiles without error, I still don't understand why.

    In pursuit of this, I then searched for discussions of std::string_view in your tutorials, and all I found was this reference from lesson 6.8b: "C-style strings are used in a lot of old or low-level code, because they have a very small memory footprint. Modern code should favor the use std::string and std::string_view, as those provide safe and easy access to the string."

    My suggestion would be to either add a note about std::string_view to this quiz point, as you do with some other things here, or add some section prior in which you explain the difference between the two. For myself, at this point, I am still unclear what the difference between the two is, other than the fact that one works and one doesn't.

    All that said, thank you again for the exceptional gift you have provided for so many people here with this work.  It is my hope that this might help a bit to make it even better.



    • nascardriver


      There's a lesson dedicated to `std::string_view`. If you've been around for a while, you might have read the chapter before the lesson was added. Check the overview regularly to see if new lessons were added, you don't need to read the "Updated" ones, their content is mainly the same as before.

      Unless you have a reason to use an old standard, you should always use the latest version (Currently C++17, soon C++20).

      When you're having issues with a standard function or type not working, cppreference is a great reference. When you open up the std::string_view reference, you'll see that it requires C++17 (green text). Until you learn about templates, most of the references will seem cryptic, but you should get the most important information from reading the descriptions. A lesson about using standard references is pending.

      We're aware of the `std::string` vs `std::string_view` issue in this lesson, which is caused by `constexpr`. We'll updated lessons that introduce new types to say whether or not they work with `constexpr` until we have a lesson that covers `constexpr` in detail. I added notes about `std::string_view` to the first example that uses it in this lesson.

      Most of the lessons, including this one, are Alex' work. I only started writing recently.

      Thanks a lot for your feedback! If there's anything else you think could be improved, please say so.

      • Wayseeker

        Thank you so much for the reply!  You are correct.  I've been working through the lessons since early October, so I missed both of the lessons you mentioned above as I went through them prior to the updates.  I will check that regularly as I move forward.  I am very impressed by both how clear and articulate these lessons all are and by how careful the authors are in maintaining it, updating it, and responding to questions and comments.  

        This is fine work.  Bravo!

        Thanks again.

    • Wayseeker

      I received an email letting me know that you replied, but I can't see it here.  Where might I find that?


  • cnoob

    Here is my shot at the quiz, with one last question: Lets say I have class. In said class I have a local variable inside a static function. The variable is also explicitly declared as a static variable. Is the variable supposed to be accessible "globally", or still only if I call the function?
    Since the game is pretty hard,(if you are not lucky enough to catch a wave of slimes and be able the flee everything else on the first couple of levels you have no chance to win) I have added a possibility to play again after the player dies (or wins).

    • nascardriver

      - Member functions that don't modify their object should be `const`.
      - You're using `mersenne` in multiple places. Add a new class for random number generation.
      - Use comments for documentation. What do your return values mean?
      - Avoid recursion.
      - Line 217-220: Add a `reset` member function that calls all these functions. If you want to reset at several points, you'll forget to call something.

      > Is the variable supposed to be accessible "globally", or still only if I call the function?
      The variable is only accessible inside the function and possibly by callers of the function if the function returns the variable.

      • cnoob

        Thanks a lot! Ive applied recursion, because it seems to be the easiest way to handle the 3 possible outcomes of the fightMonster() function inside a while loop. (Ive added the comments for the sake of clarity as you suggested.) I think it is also quite straightforward and safe in this case. Here is the code:

        • nascardriver

          The documentation comments should be placed at the function that they document, not at a call to the function. With your updated code, a reader of `fightMonster` still doesn't know what the return value means until they find a place where you're using the function and wrote a comment.

          You have only 2 returns values, use a `bool` or an `enum`. An `int` might make a reader search for more return values.

          `RandNum::mersenne` should be private, you're not using it outside of the class.

          The recursion may have seemed like an easy solution, but it makes it very hard to follow the control flow of your program, as well as decreasing reusability. Make sure your understand the quiz's solution or someone else's solution that uses loops.

          • cnoob

            All right, I got rid of the recursions. fightMonster() handles the control flow by calling attackPlayer(), or attackMonster(). And indeed, main() is much more comprehensible like this, it almost reads like a normal text.
            I used nested loops though, I hope thats legit.

            • nascardriver

              That's looking a lot better, good job!

              The nested loops can be avoided by adding more functions.
              Line 152-155 and 218-225 and be reduced to 1 line each, that'll save you typing.

  • I keep getting two errors: first at constexpr (error message: "a constexpr must have a literal or const type)
    2nd error at the opening curly brace (error message: "a member of type "const std::array <Monster::MonsterData,3U>" cannot have an in-class initializer.
    Note that this error shows even though I copied the exact code from the lesson.

    • nascardriver

      Did you enable the latest standard in your compiler settings? You need at least C++17.
      Which compiler are you using?

      • cnoob

        Im getting the same error message in VS 2019, with the latest standard enabled. (It works though, if I change constexpr to const.)

        • cnoob

          O.K., I got it! In the solution you are using std::string_view in the MonsterData struct. Ive used std::string, thats why I got the error. Why does it have to be std::string_view btw? (I mean for this specific purpose. Why cant we use an std::string?)

          • Alex

            I was able to compile the example on Visual Studio 2017 and 2019 using both the C++17 and latest standards. So not sure what's going on here.

            A couple of thoughts:
            1) The examples were missing some string and string_view #includes. I've added them. See if that fixes the issue.
            2) In a prior update, nascardriver moved the initialization for monsterData into the class. If you move it back outside the class, do you still get the same error?

            std::string_view is more efficient than std::string when working with string literal data (std::string makes a copy, std::string_view doesn't).

            • cnoob

              I can initialize monsterData outside without any problem, I guess it doesnt even need to be static then.
              I only get the error if I try to initialize it inside the class AND I use std::string instead of std::string_view. I understand that it is not efficient, but why doesnt it work at all?
              At the same time, if I declare the array like this:

              Then it compiles with std::string.

              I suppose the array MUST be static or global because otherwise it doesnt get initialized before the constructor, right?
              It seems that std::string needs the declaration to be inline, while std::string_view needs it to be constexpr. Why is that?

          • nascardriver

            Yes that's right. In C++20 it might work with `std::string`, not sure. Before that, it can't work. `constexpr` is a compile-time value, but `std::string` uses dynamic allocation, a feature that requires the program to be running. `std::string_view` on the other hand is just a view at a string literal, it can be used at compile-time.

            You can initialize `monsterData` outside, because then you're not using `constexpr` anymore. If you were using `constexpr`, you'd have to initialize it inside.
            `static` `constexpr` member variables are `inline` by default, which allows you to initialize the member inside the class. Without `inline`, you're not allowed to initialize `static` members inside the class.

  • HurricaneHarry


    Thanks for the tutorials again!
    But... I've hit a wall again. When I tried to do the third quiz I always get an error message, so I simply copy pasted in your solution. I get the exact same error there.

    Making it not static constexpr compiles but crashes when running at constructing:

    with the debug error:

    So far it only worked if I took the struct and array out of the class in some form.
    Just reread the static, const and container lessons, but still missing the forest for the trees it seems...
    What am I doing wrong?

    • nascardriver

      This looks like you have a user-provided destructor in `MonsterData`. The code in the solution compiles with

      If you need a destructor, you can't use a `constexpr` array. Define `monsterData` outside of the class or mark it `inline`.

      • HurricaneHarry

        Hi nascardriver,

        sorry for answering with such a delay. But a day after writing that comment my machine died. And getting a replacement around christmas and new year... easier said than done, especially if the parcel-service also loses your shipment on the first try...

        I went for the definition outside of the class in the end, as explained in the earlier lessons, and that worked like a charm. But I did actually not write a destructor at all. (I even copy pasted in the provided solution to be shure)
        Is it possible it's a change from c++17? As the version of g++ delivered with Code::Blocks doesn't seem to be fully compatible with the '17 standard. So far I wanted to stay as true to the recommendations listed in the beginning of the tutorials as possible, but maybe it's time to update.

        best regards

        • nascardriver

          The code requires C++17. You should always use the latest standard available.

          • HurricaneHarry

            Finally found the solution.
            It was related to std::string_view.
            What got me in the end, was that there was no "undefined type" (or something like that) error with the string_view line with the (partial/experimental..?) c++17 standard in vanilla CB g++ version.

            Maybe add a line in the lesson, that the (as it seems still latest) build of Code::Blocks doesn't come with a sufficient g++ version for this quiz?
            Or, maybe it was already added in one of the lessons.
            Works with g++ 9.2.

            best regards

            • nascardriver

              Thank you for sharing what your issue was!
              Different versions of CB ship with different compilers which support different standards.
              Because old standard selections/compiler incapabilities have caused many errors since we started updating the lessons, I emphasized that learncpp uses C++17 and I added an example to test the compiler in lesson 0.12. Additionally, I added a note to this lesson, the array snippet in particular, reminding readers to use C++17. This makes it easy to figure out errors that are caused by old compilers or wrong compiler settings before they occur in the quiz.

  • Wilibert

    Hello Alex and nascardriver, first of all, thanks a lot for the tutorial.

    I'm getting a weird issue with quiz 3)d, even if I copy paste the code from the solution. Here's a sample of what I tried: