CPP Cards II Page 1
- Part I - Refactor Basic Class
Refactor Basic Class
Now we are going to take off where we left with our previous C++ Visual Studio project Basic Class. In it we had the Card Class and Main all in the same page. Lets recreate this project and separte the Card class into its own .h and .cpp.
- Create a new C++ Windows Console Application project in Visual Studio nand pick a directory to save it in. Call the project
ExtendingVSCardClassthen press the Create Projects button.
- We will take what we have done previously in Basic Class project and move it over. So in your new ExtendingVSCardClass project and press Project | Add Class and add a .h and .cpp called
Card. Press the OK button:
- VS should stub in an empty class.h and class.cpp. You .h should look like this:
- Now go and open BasicClass.cpp and cut and paste the Card class declaration and paste it into Card.h like so:
- Now copy and paste all the class definitions to the Card.cpp file. Leave the Main function to put in the project main cpp.
- Now copy Main.cpp content to ExtendingVSCardClass.cpp.
- Compile and run and it should look EXACTLY like the Basic Class project did when we left off.
Add a Namespace
Now it is always a good idea when creating a class to add its own namespace. Namespace is a method for preventing conflicts in large projects. UE4 is a large project and there are thousands of classes and names to contend with. The chances of reusing a name they have already used is great.
- Lets add a Namespace to the project. Why use a namespace on a new class in such a small project? This class is generic enough that I might want to reuse it on multiple projects. Cards is a fairly generic name, and it is quite possible I might try and use it where there is another class called Cards. By giving it a namespace it is less likely that I will have a collision (use the same name of a class and member where the compiler will pick one of the two (or not compile).
Lets wrarpthe entire .h with the namespace
Deck. Now compile and we break the entire .cpp as it is lo longer in the same global namespace.
- Open Card.cpp and add
Deck::in front of
Card. The compiler now finds the card class as it recognizes the namespace.
- Now be careful when we have a class in a namespace the operator that you overloaded needs to be placed in the namespace and not the class. So you will add
Deck::in front of
- Now compile and fix any errors. Run the project and you should see what we had at the end of the previous project. We have refactored teh Card class into its own proper .cpp and .h file.
Structs and Classes
C++ has another data structure called a struct. This is very similar to a class except that it’s members are public by default. Lets take a look to see what I mean. Lets first look at what a class defaults to.
- Now a member in a class with no access specifiers (public, private or friend), defaults to private. Go to the Deck.h and add a member called
int fooand add it to the top of the header with no access specifier.
- Now go to the min() function and try and access the variable. You get a compile error.
- We also have struct that are very much like classes. The major difference is that it defaults to its members being public where a class defaults to private. Before the main() function add a Struct called
Pointand add two members called
y. Now in Main create an instance of this struct and try and access one of its members. Press compile and all should be fine.
- But we can still declare the struct member as private. If we do so and press compile, then we get a compile error stating that the members cannot be accessed.
- When do we use a struct and when do we use a class? We typically use a struct when there are no invarients with the structure. An invarient is when something must be true at a given point to describe a set of values of an object. In the Card class we do have an invarient. The card numbers are limited and the card suit is limited. In a 2-d point in a game it could be any valid float and there is no rule that limits what a Point struct can be. It is often use for simple data strcutures in games.
Static Members of a Class
Now lets look at what a static member of a class.
- Lets look at a static member. Sometimes we have a single isntance of a variable (or function) that we want to be accessible to the entire class and does not instantiate with each instance of the class that is created. A common use would be to count up how many cards exist in the current running game. It is declared with
structin front of the type. Here we add a variable called
static int NumberOfCardsInPlay.
- Open the CPP and the first thing you should define are the static members. It is done on its own and in our case is
int Deck::Card::NumberOfCardsInPlay = 0;Then you need to imcrement this static member in each constructor. It shouldn’t matter how we call the class, we should always increment the number of cards in play. Add this incremt in EACH constructor.
- Now we can’t access this member as it is private. We need to create a getter for it so lets create a public function called
GetNumCardsInPlay()and return an integer.
- Go to main() and instantiate four cards. Then we call the **GetNumCardsInPlay() function to get the number of cards. Now we should also add a
constto this function as the integer returned is not meant to be changed.
- Compile and fix all errors then run the program. You shold see that this variable wazs called each time a class was created and it is correct with 4 cards in play.
Equal & Not Equal Operators
Now we have overlooked a very important issue with this class. What is we want to compare two cards and find out if they are the same suit & number? This class does not know what its members are and what makes one card the same as the other. For example we could have two cards with different designs on the back, but they have the same number and suit. It is up to us to determine what makes a Card same or different.
- We will start by ensuring that we have two classes that are the same.
Now lets make a copy. There is a default copy constructor for a class. Sometimes we need to create a custom copy constructor especially if there are pointer members in the class. We wil not worry about it. But what happens when we check to see if two variables are the same and we find out that it won’t compile as
==is not found for the Card class.
- Go to Card.h and add another declaration for the
operator ==and make it a friend so the operator can access this private member. Remember a friend class allows another type the ability to read your members set to friend.
- Now in the definition we are looking to see if both the Number and the Suit are the same. We we check both values and return whether they are both the same.
- Comnpile and fix all the errors. Run the game and you will see that the comparison operator works.
- Now we need to declare the
!=operator as well. Lets declare it in Card.h.
- We define it in Card.cpp and all we do is call the
==operator and invert the boolean with a
- Now lets alter the main() function and test the
!=symbol and make sure it works.
- Compile and run the game to test it out. Seems to work fine.