Search

8.x — Chapter 8 comprehensive quiz

In this chapter, we explored the meat of C++ -- object-oriented programming! This is the most important chapter in the tutorial.

Chapter summary

Classes allow you to create your own data types that bundle both data and functions that work on that data. Data and functions inside the class are called members. Members of the class are selected by using the . operator (or -> if you’re accessing the member through a pointer).

Access specifiers allow you to specify who can access the members of a class. Public members can be accessed directly by anybody. Private members can only be accessed by other members of the class. We’ll cover protected members later, when we get to inheritance. By default, all members of a class are private and all members of a struct are public.

Encapsulation is the process of making all of your member data private, so it can not be accessed directly. This helps protect your class from misuse.

Constructors are a special type of member function that allow you to initialize objects of your class. A constructor that takes no parameters (or has all default parameters) is called a default constructor. The default constructor is used if no initialization values are provided by the user. You should always provide at least one constructor for your classes.

Member initializer lists allows you to initialize your member variables from within a constructor (rather than assigning the member variables values).

In C++11, non-static member initialization allows you to directly specify default values for member variables when they are declared.

Prior to C++11, constructors should not call other constructors (it will compile, but will not work as you expect). In C++11, constructors are allowed to call other constructors (called delegating constructors, or constructor chaining).

Destructors are another type of special member function that allow your class to clean up after itself. Any kind of deallocation or shutdown routines should be executed from here.

All member functions have a hidden *this pointer that points at the class object being modified. Most of the time you will not need to access this pointer directly. But you can if you need to.

It is good programming style to put your class declarations in a header file of the same name as the class, and define your class functions in a .cpp file of the same name as the class. This also helps avoid circular dependencies.

Member functions can (and should) be made const if they do not modify the state of the class. Const class objects can only call const member functions.

Static member variables are shared among all objects of the class. Although they can be accessed from a class object, they can also be accessed directly via the scope resolution operator.

Similarly, static member functions are member functions that have no *this pointer. They can only access static member variables.

Friend functions are functions that are treated like member functions of the class (and thus can access a class’s private data directly). Friend classes are classes where all members of the class are considered friend functions.

Finally, it’s possible to create anonymous class objects for the purpose of evaluation in an expression, or passing or returning a value.

Quiz time

1a) Write a class named Point2d. Point2d should contain two member variables of type double: m_x, and m_y, both defaulted to 0.0. Provide a constructor and a print function.

The following program should run:

This should print:

Point2d(0, 0);
Point2d(3, 4);

Show Solution

1b) Now add a member function named distanceTo that takes another Point2d as a parameter, and calculates the distance between them. Given two points (x1, y1) and (x2, y2), the distance between them can be calculated as sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)). The sqrt function lives in header cmath.

The following program should run:

This should print:

Point2d(0, 0);
Point2d(3, 4);
Distance between two points: 5

Show Solution

1c) Change function distanceTo from a member function to a non-member friend function that takes two Points as parameters. Also rename it “distanceFrom”.

The following program should run:

This should print:

Point2d(0, 0);
Point2d(3, 4);
Distance between two points: 5

Show Solution

2) Write a destructor for this class:

Show Solution

3) Let’s create a random monster generator. This one should be fun.

3a) First, let’s create an enumeration of monster types named MonsterType. Include the following monster types: Dragon, Goblin, Ogre, Orc, Skeleton, Troll, Vampire, and Zombie. Add an additional MAX_MONSTER_TYPES enum so we can count how many enumerators there are.

Show Solution

3b) Now, let’s create our Monster class. Our Monster will have 4 attributes (member variables): a type (MonsterType), a name (std::string), a roar (std::string), and the number of hit points (int). Create a Monster class that has these 4 member variables.

Show Solution

3c) enum MonsterType is specific to Monster, so move the enum inside the class as a public declaration.

Show Solution

3d) Create a constructor that allows you to initialize all of the member variables.

The following program should compile:

Show Solution

3e) Now we want to be able to print our monster so we can validate it’s correct. To do that, we’re going to need to write a function that converts a MonsterType into a std::string. Write that function (called getTypeString()), as well as a print() member function.

The following program should compile:

and print:

Bones the skeleton has 4 hit points and says *rattle*

Show Solution

3f) Now we can create a random monster generator. Let’s consider how our MonsterGenerator class will work. Ideally, we’ll ask it to give us a Monster, and it will create a random one for us. We don’t need more than one MonsterGenerator. This is a good candidate for a static class (one in which all functions are static). Create an empty MonsterGenerator class. Create a static function named generateMonster(). This should return a Monster. For now, make it return anonymous Monster(Monster::Skeleton, “Bones”, “*rattle*”, 4);

The following program should compile:

and print:

Bones the skeleton has 4 hit points and says *rattle*

Show Solution

3g) Now, MonsterGenerator needs to generate some random attributes. To do that, we’ll need to make use of this handy function:

However, because MonsterGenerator relies directly on this function, let’s put it inside the class, as a static function.

Show Solution

3h) Now edit function generateMonster() to generate a random MonsterType (between 0 and Monster::MAX_MONSTER_TYPES-1) and a random hit points (between 1 and 100). This should be fairly straightforward. Once you’ve done that, define two static fixed arrays of size 6 inside the function (named s_names and s_roars) and initialize them with 6 names and 6 sounds of your choice. Pick a random name from these arrays.

The following program should compile:

Show Solution

3i) Why did we declare variables s_names and s_roars as static?

Show Solution

4) Okay, time for that game face again. This one is going to be a challenge. Let’s rewrite the Blackjack games we wrote in chapter 6 using classes! Here’s the full code without classes:

Holy moly! Where do we even begin? Don’t worry, we can do this, but we’ll need a strategy here. This Blackjack program is really composed of four parts: the logic that deals with cards, the logic that deals with the deck of cards, the logic that deals with dealing cards from the deck, and the game logic. Our strategy will be to work on each of these pieces individually, testing each part with a small test program as we go. That way, instead of trying to convert the entire program in one go, we can do it in 4 testable parts.

Start by copying the original program into your IDE, and then commenting out everything except the #include lines.

4a) Let’s start by making Card a class instead of a struct. The good news is that the Card class is pretty similar to the Monster class from the previous quiz question. First, move the enums for CardSuit, CardRank inside the card class as public definitions (they’re intrinsically related to Card, so it makes more sense for them to be inside the class, not outside). Second, create private members to hold the CardRank and CardSuit (name them m_rank and m_suit accordingly). Third, create a public constructor for the Card class so we can initialize Cards. Forth, make sure to assign default values to the parameters so this can be used as a default constructor (pick any values you like). Finally, move the printCard() and getCardValue() functions inside the class as public members (remember to make them const!).

The following test program should compile:

Show Solution

4b) Okay, now let’s work on a Deck class. The deck needs to hold 52 cards, so use a private std::array member to create a fixed array of 52 cards named m_deck. Second, create a constructor that takes no parameters and initializes m_deck with one of each card (modify the code from the original main() function). Inside the initialization loop, create an anonymous Card object and assign it to your deck element. Third, move printDeck into the Deck class as a public member. Fourth, move getRandomNumber() and swapCard() into the Deck class as a private static members (they’re just helper functions, so they don’t need access to *this). Fifth, move shuffleDeck into the class as a public member.

Hint: The trickiest part of this step is initializing the deck using the modified code from the original main() function. The following line shows how to do that.

The following test program should compile:

Show Solution

4c) Now we need a way to keep track of which card is next to be dealt (in the original program, this is what cardptr was for). First, add a int member named m_cardIndex and initialize it to 0. Create a public member function named dealCard(), which should return a const reference to the current card and advance the index. shuffleDeck() should also be updated to reset m_cardIndex (since if you shuffle the deck, you’ll start dealing from the top of the deck again).

The following test program should compile:

Show Solution

4d) Almost there! Now, just fix up the remaining program to use the classes you wrote above. Since most of the initialization routines has been moved into the classes, you can jettison them.

Show Solution

9.1 -- Introduction to operator overloading
Index
8.14 -- Anonymous variables and objects

81 comments to 8.x — Chapter 8 comprehensive quiz

  • Alex

    Was quiz question 4 too hard?

    • Jammy

      I managed to do it after a while! 🙂 Thank you for these tutorials! I don’t know how I would be able to learn without these. Just started SDL2 tutorials, and there’s a lot to process on each one and no way to test my knowledge. Much easier learning here!!

    • ozdmc

      It’s about right for a novice, but a bit too  guided for users who know another programming language (only 15 mins).  You could possibly add a question before Q4a which asks a user to identify which functions would be good inside a deck class, which in the card class and which should stay in the primary program.

      This would also be a good exercise to split into multiple files - I tried that after completing Q4 and discovered a whole bunch of interesting new rules!  Now those took me 4hrs to figure out …

      Otherwise, great tutorials and thanks for providing them!

    • oh c'mon

      I have been looking forward to the comprehensive quiz just because the questions just like the 4th one and you ask if it was hard?? it is as hard as it is supposed to be.

      • Alex

        The quizzes are supposed to be challenging but not impossible. If too many readers aren’t able to complete them, then I probably haven’t explained something well enough.

    • epsilonv

      Personally, I find most instructional texts take it too easy on the student. I want to come away with skills that will allow me to eventually perform production level programming or at least have some feet to walk-on before reading other texts and code that will provide additional knowledge after I complete the information on this site. I have programmed with various languages over the years. Many years ago I attempted to learn C++ but didn’t have the time and and mostly patience to dig into it and learn all the detail you’ve kindly laid out here. I appreciated the complexity of question 4. It reminded me of the first assignment of cs193p "Matchismo" on iTunes U "Developing iOS 7.0 Apps for the iPhone and iPad". Which, upon my first review of that assignment seemed both too simple and complex all at the same time. I felt the 3rd assignment with the static MonsterGenerator class confusing however, mostly since It does not seem extendable with the static class and I don’t really understand why anyone would use a static class in that instance.  I stopped using rand() for random number generation ever since you described using mersenne and have modified the

      function to use mersenne instead. Globally initializing the random device and a static mersenne member seemed wrong but the compiler wouldn’t let me initialize it inside main like it does for:

      However, had it been a non-static class I would have initialized those in the constructor.

      Honestly, as a mudder,  I would have liked to have been challenged with a fuller functioning mini-mud on question 3 with rooms, random monster’s and a user interface that would let me walk around the rooms but then I guess we’d need to know how to hook into a database like sqlite or text files to get the room descriptions, etc.  I was surprised there was no mention of the model-view-controller concept during chapter 8 but seeing how these objects work together is good stuff. Thanks for putting all this together. It’s been very educational.

    • Kattencrack Kledge

      Question 4 was fun to do 😀

  • Jorge

    AWESOOOOOOME tutorials. You just make the best programming tutorials. Keep up the fantastic work and i hope you can update and make comprehension quizes for the missing chapters soon.

  • Milica

    Hey Alex,
    I believe that we don’t want the expression starting at line 9 in the question 1a there.
    Cheers,

  • Kevs

    I loved question 4, even though it wasn’t easy. I don’t have a ton of programming experience and I actively avoided OOP until now, so while it may be obvious to some people, I was impressed by how smoothly the old code could be "translated".

    One question: Right now newDeal() is never called. Would it only have to be used to play another game with the same deck object or is there any other purpose for the function that I’m not seeing?

    • Alex

      When I wrote the program, I thought we’d need it, but it turns out the main program doesn’t have a loop, so it was never used, and I forgot to take it out.

      Upon reflection, with a deck of cards, you’ll almost never redeal the cards without shuffling. So I’ve updated the example to get rid of newDeal(), and instead moved resetting the current card index to 0 inside of shuffleDeck(). That way, whenever we shuffle the deck, we’ll start dealing cards from the start of the deck again. That makes more sense intuitively anyway.

  • Irene

    Could you include the solution to these problems using header files?

  • Ace

    Alex, when I run the solution for the quizzes ‘1a’/’1b’/’1c’, I’m getting the following output:

    Point2d(0 , 0)
    Point2d(3 , 4)

    instead of:

    Point2d(0.0, 0.0)
    Point2d(3.0, 4.0)

    Do we have to do anything extra for it to display the ‘double’ dataype numbers in the decimal point format?

  • Ace

    Alex, in quiz ‘2’, this line (for C++11):

    isn’t getting compiled. It says "error: invalid conversion from ‘const char*’ to ‘char’ [-fpermissive]". What’s to be done?

    • Ace

      It works fine with this though:

      • SJ

        I was going to comment on this also. And cannot we allocate 13 characters instead of 14? There are 13 including the null terminator.

        Also I get the warning ” depreciated conversion from string to constant ‘char*’ ” when using

        but no warning when I do

        • Alex

          14 is the correct length for the array. There are 6 characters in “Hello,”, 1 space, 6 characters in “world!”, and 1 null terminator. That adds up to 14.

          is assigning a pointer to a string literal, so your data type here really should be “const char”.

          allocated a fixed array of size 14 and initializes it with a string literal.

          This is covered in lesson 6.8b -- C-style string symbolic constants.

          • Ace

            Umm… just clarifying (not a big deal), a size of 13 can also be used as there’s no comma after "Hello" in "Hello World!".

          • SJ

            Ahhh that’s where it is. Sorry about that Alex I was checking out the C-style string sections again to see if I had missed anything and I didn’t check 6.8b. Oops.

            Also "Hello World!" has 13 total characters with the null terminator but "Hello, World!" has 14. So you probably want to change the question/solutions to "Hello, World!"

      • Alex

        Interesting! It looks like initializing a char array this way with a string literal was something they addressed in C++14, not C++11. I’ll update the example.

        • Ace

          Oh ok… Pls update the same in the solution code as well (just for anyone trying to use the solution straightaway).

            • Ace

              Alex, now I tried that

              on C++14. But still the same error: "invalid conversion from ‘const char*’ to ‘char’ [-fpermissive]".

              Do you see any syntax issue or something?

              P.S. The C++14 compiler option (-std=c++14) is working fine per se.

              • Alex

                I’m not sure, your code looks fine and compiles on Visual Studio 2015. Based on the documentation I’m looking at, this should be compiling on all C++14 compilers. So that means one (or more) of the following:
                * The documentation is wrong (and Visual Studio is being permissive)
                * Your compiler doesn’t have full support for C++14 (try upgrading to a newer version)
                * You aren’t passing the right flag to your compiler (enabling c++14 functionality for gcc could be either -std=c++14 or -std=c++1y, depending on gcc version)

  • Irene

    In 1c, m_x and m_y are private so how come you are able to use them in the distanceTo function?

    • SJ

      Because distanceTo() was declared as a friend within the Point2d class, so it has access to that class’s private members.

    • Alex

      distanceTo was declared as a friend function, and friend functions are able to access private member data as if they were a member themselves. Please review the lesson on friend functions.

  • Eyad

    well, i dont know why this happens to me… but it happens, alot
    previously i had my version of blackjack so i thought it will be good to change my version to classes (it doesn’t differ so much anyway), but i get a weird error when i use my version, but this error doesn’t happen when i copy your code and use it so idk what has gone wrong here..

    error: no operator"=" matches these operands , operand types are std::array<Card,52U> = Card

    and i failed to tell the difference between your and my code, so here is mine.

  • Photons

    Nice this is a challenging Quiz from chapter 0.

    • AWESOOOOOOME

      Hey, Alex
      I  wonder why put the if statement in this function?
      THANKS!!!

      • Alex

        The if statement is there to prevent overflowing the array if you try and deal cards off the end of the deck. It’s somewhat non-sensical to return the last card twice, but at least the result is predictable.

        I’ll update the example to use an assert instead, as it probably makes more sense to abort the program in this case.

  • weyoui

    Is there a reason getRandomNumber and swapCard fucntions are static ?

    • Alex

      They’re static because they don’t rely on having an object from the class they are part of to function (they don’t need a *this pointer). This allows you to use them by prefixing them with the class name (e.g. Deck::swapCard()) rather than having to instantiate a Deck to use them.

      • Darren

        Specifically in this context having them static is not required. In fact, if you haven’t instantiated a Deck, then there isn’t a m_deck array to shuffle() (where you call both swap() and getRandomNumber()), and in order to shuffle() you have to instantiate a Deck, making the static keyword here somewhat redundant.

        • Alex

          There are a couple of advantages to having them static:
          1) It makes it clear that they do not rely on the state of the class they are associated with in any way
          2) You can call them directly without an instance of the class available. Although we don’t actually do that in this particular example, you could if you had a good reason to.

  • George

    Hi Alex, first of all, thanks a lot for this tutorials!!

    I´m having trouble on 4B. My complier says: "Assigning to ‘value type’ (aka ‘int’) from incompatible type Card"; The error is at m_deck[card] = ……….

    I´ve done it and re-done it, i´ve copied and pasted your code and it does not work. Can you help me please.

    [code]
    Deck()
        {
            int card = 0;
            for (int suit = 0; suit < Card::MAX_SUITS; ++suit)
                for (int rank = 0; rank < Card::MAX_RANKS; ++rank)
                {
                    m_deck[card] = Card(static_cast<Card::CardRank>(rank), static_cast<Card::CardSuit>(suit));
                    ++card;
                }
        }
    [\code]

    • Alex

      I’m not sure. How did you declare m_deck?

      • George

        I declared it as a non-constant private array, I didn´t forget the #include<array>.
        Its weird because Ive checked the whole script like ten times, maybe it is the compiler.

        • Alex

          Can you paste in the declartion line for m_deck so I can see exactly how you declared it?

          • George

            • Alex

              And there is your problem.

              Should be:

              You want a deck of 52 Cards, not a deck of 52 ints.

  • Ola Sh

    Hi Alex,

    The quiz questions were interesting, especially quiz 4. I enjoyed them. I saw the benefits of encapsulation and object-oriented programming in the Blackjack game. Thanks for your good work.

  • T

    Wow, awesome tutorial! Will have to take another look through the code to grasp everything completely, but real fun! Many many thanks!

  • Shiva

    That was fun! Quiz #4 was a bit challenging, but rewarding as well. Don’t worry Alex. 😀

    Anyway this chapter could benefit from some corrections:
    > In C++, non-static member initialization allows you to directly specify default values for member variables when they are declared. - Did you mean In C++11?
    > Quiz 1a) solution: #include <iostream> is missing
    > Now we want to be able to print out (our?) monster out so we can validate it’s correct.
    > Quiz #4 solutions (except the solution to 4a)): In class Card, the parameterised constructor doesn’t have default parameters, and the added empty default constructor is pointless (as non-static member initialisation is absent).

    And some suggestions:
    > Quiz 1b): I believe math.h is deprecated, and we are supposed to use cmath instead.
    > In quiz 1c), the name distanceTo is no longer appropriate for the friend function (better change it to distanceBetween or something)
    > In quiz #2 solution, inside the destructor, set m_data to null pointer after the delete statement.
    > In class Deck, set m_cardIndex to 0 inside the constructor too, to be on the safe side.

    Great quiz, enjoying the tutorial, thanks once again for this awesome site. 🙂

    • Alex

      Thanks for all the great suggestions. All implemented, except the last two:
      1) Setting a deleted pointer to null isn’t really necessary in a destructor, since the object is going to die immediately afterward anyway.
      2) There’s no point in using non-static member initialization if you’re going to always initialize it in the constructor as well!

  • Shiva

    1) Ah. I didn’t consider that.
    2) Looks like I hadn’t quite understood non-static member initialisation. I’ve reviewed the chapter on the topic, and understood your point. Thank you!

    Good job updating the chapter, but you somehow missed #3 (it’s still "print out monster out").

  • ktm

    All your main() function from question 1 to 3 should return an int. You missed all of them so I think you did it on purpose.

  • Hannah

    In the solution to question 1, why give the member variables a default initialization value, when we provide default values in the constructor as well? Won’t the ones in the constructor always take precedence?

  • Hannah

    Starting code for question 4: The player does not bust if he’s got 22 points from his first two cards. Is that intentional because he is bound to have aces?

    • Alex

      You’re right, the program doesn’t handle the case where the user is dealt 2 aces very well -- but that’s in part because doesn’t handle aces very well in general (since they can be worth 1 or 11). The extra credit question does deal with this, and implementing that would resolve this issue as well.

  • I notice this is the last of the quizzes - are there more on the way? Also, it would be nice maybe to have a ‘where next?’ page; if I can answer all the quizzes, and understand the information, how close am I to being ready to take some sort of qualification, and what should my next steps be? I can probably find these questions elsewhere on the net, but I’ve learnt programming from scratch here and it seems a logical way to round off such a great tutorial.

    • Nyap

      Once you’ve finished, you’ll probably want to learn things like the preproccessor and STL which this tutorial didn’t cover in detail. After that, you can (if you want to) learn libraries:
      GTK (used to make windows and things like that)
      OpenGL (graphical library - mostly used for games)
      Vulkan (basically OpenGL++, made by the same ppl who made opengl. I don’t think there’s a good tutorial out there yet though as it’s fairly new)
      ALSA (sound library)

  • Darren

    With the Card class as prescribed above with an inclusion of a setSuit() and setRank() member functions, here’s my design of the Deck class making use of the <random>, <chrono>, and <utility> headers:
    Deck.h

    Deck.cpp

    In this case we assert only once that we are using a maximum of 52 cards in the body of the Deck constructor. I reset the iterator to the beginning of the array after a shuffle as I’m not certain my iterator will still point to the beginning of the array after the swaps. Notice that both the random number generator engine and distribution are owned by the deck and it seeded by the high resolution system clock when a Deck gets created.

    • Darren

      For the rest of my solution, including an object orientated approach to players and the dealer and the game itself, check out my repository on GitHub https://github.com/DJWalker42/blackjack

      It uses a couple of concepts yet to be covered but have a look at it, mess about with it, and see what you think. Suggestions welcome.

  • Pyrorai

    Amazing tutorials, I’ve been meaning to learn C++ for a while and this is exactly what I needed, well explained and well sectioned! 🙂 I still haven’t quite gotten used to const, static, constexpr, extern, and the like but hopefully with time they’ll come a lot easier. I loved the last question on this and the blackjack question from chapter 6!

  • Anddo

    Hey Alex,

    From solution of 1a, about this part

    Why did you initialize the member variables twice ? Once objected is created, constructor called and the initializing on the constructor initialization list OR directly should be enough, shouldn’t it ?

  • Anddo

    OK I thought about something differently. When an object created of Card class, why not initializing it immediately instead of doing so in the Deck class. Here is the modification

    Of course the constructor Deck() content is commented and I left it empty. What do you think alex, as a logic, is this acceptable ?

    • Alex

      Personally, I don’t like it, because it adds complexity that isn’t needed at the Card level. Creating a bunch of sequential cards should be the role of a Deck. Cards should just be a single card, and contain just enough logic to fulfill that role.

  • Matthieu B.

    The title of this section should be 8.x in order to be consistent with the titles of the previous quiz sections.

  • Chris

    Alex, i have a question

    At quiz number 3d, Why enum in class can be accessed by scope resolution operator? I think we must create the object first so we can access the enum by member selection because the enum not static.

    And for a note, I think codeblock users must to discard the first random value because if I (codeblock user) not discard it, I always get same value for the first random value which is the type variable.

    Thank you.

    • Alex

      enum MonsterType is public, so it can be accessed directly. You do have to create an object of the class to access the enumerated member (m_type), but the enumerators themselves (Dragon, Goblin, etc…) are just type declarations so they can be accessed directly.

  • Rob G.

    Hi Alex shouldn’t the print fx() come before the destructor so that it will be destroyed when the destructor is called after it?

    to:

  • Rob G.

    Alex this was really an odd exercise for me: I had to code the private after the public to avoid a compiler error. Say what? Is there any forward declaration I can insert before the class to avoid this, assuming that is the problem?

    If you physically put private before public content I get this error:
    ..srcmain.cpp:9:2: error: ‘MonsterType’ does not name a type

    • Alex

      This happens because you have to define Monstertype before you can use it (this is true with all types).

      There’s no problem putting a public: before a private:. In fact, many people believe it is better to put your public interface first and your private data last since as a user of the class you use the public interface, not the private data.

  • Christos

    Hi Alex,

    Seven text lines before ‘Quiz Time’, "Static member variables are shared among all members of the class.".

    I think that you want to write "…all objects of the class."

  • Matt

    Alex,

    I’ve finished updating my blackjack program using classes but since my program is much different than yours, I have a couple of questions.

    1) I decided to put the call to srand() inside the constructor of my Deck class, just to keep it out of main(). Does this make sense, or is there a downside to this?

    2) I decided to create a Blackjack class. I’m not sure whether this was a good idea or not, and would like your opinion on it. It’s private member variables/functions are:
            int player_wins
            int dealer_wins
            Deck play_deck
            enum Over             //to enumerate the 7 different ways the dealer/player can win

            void tallyScore()     //to update the score of the player/dealer
            void endGame(Over)    //to print out one of 7 win/lose messages, and update player_wins or dealer_wins

    It’s public functions are "menu()" and "play()". And I created a Blackjack object(blackjack) at the end.

    This is what’s in main():

       while(blackjack.menu())
           blackjack.play();
       return 0;

    I like how main() is so clean, but I’m not sure if it’s proper programming style to implement the blackjack game within a class, rather than keeping it in main.

  • Damien

    Hey Alex,

    Great tutorial, I love it! Keep it up! 🙂

    I’m running into some issues with the MonsterGenerator class. Considering what you said on enumerations, I thought it would be better to use an enum class to implement the MonsterType. My code compiles just fine and seems to be working but after a few tests, it seems that I always end up with the same Monster Type. Maybe the fact it is an enum class is related to that problem, that is just my guess. Did I do anything wrong?

    Moreover, in that particular case, using an enum class seems to add a little bit more work as you need to prefix the monster’s type with "Monster::MonsterType::". This is just as well annoying as you need to use a static_cast to explicitly use it as an int. Considering that enum classes are useful when it comes to limit the risks of name duplication, I guess you used a simple enum because the scope is already limited to the Monster class, am I right? Should we consider that enum classes should always be used as stand-alone, whereas enum within classes should just be enums?

    Anyway, here is a snippet of my code, thank you in advance for your answers:

Leave a Comment

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