ICT 15
Computer Science - C++
Lesson 15 - Class Design
INTRODUCTION: In Lesson 12, you were introduced to the concept of a class and some of the syntax issues about classes. This lesson will examine the strategies and problem-solving used when designing a class.
The key topics for this lesson are:
A. Designing a Class
B. Example of Class Design - Game Tokens
C. Constructors and Initializer Lists
D. Analyzing the Token Class
E. Const Member Functions
VOCABULARY: ATTRIBUTES BEHAVIORS
NOUNS VERBS
DATA MEMBERS MEMBER FUNCTIONS
ACCESSOR MUTATOR
DISCUSSION: A. Designing a Class
1. One of the advantages of object-oriented design is it allows a programmer to create a new abstract data type, which is reusable in other situations.
2. When designing a new data type, two components must be identified - attributes and behaviors.
3. Consider the icons used in computer operating systems. The attributes that describe the icon are things like a graphic pattern, colors, size, name, and its position on the screen. Some of its behaviors would include renaming and moving its position.
4. The attributes of an object are the nouns which describe that object. These will become the private data members of a class.
5. The behaviors of an object are the verbs which denote the actions of that object or what it does. These will become the member functions of a class.
B. Example of Class Design - Game Tokens
1. Many board games use tokens to keep track of locations. For the sake of discussion, a simple board game will require the use of tokens. Here are the rules of the game.
a. The game consists of 2 tokens, both starting at position 1. The program asks for names of the two tokens.
b. The maximum move for a token will be determined at the start of the game. Each token can move from 1 to N spaces, where N is determined by the user of the game.
c. The game begins with player A moving, then player B. Two tokens can occupy the same space (no bumping back to start).
d. Players alternate moves until the first token gets to a winning position or beyond. This winning position (an integer) is also determined by the user.
2. This game could easily be solved without the use of classes. But by designing a "token" class, we build a data abstraction which could be recycled in another board game simulation.
3. What kind of attributes does a token have? To help us solve this problem, it is helpful to personalize a token, to even think of it as a person. This token will have a name, it will know its current position, and it will know where the finish line is (the winning square).
4. What kind of behaviors do we need to program into this token? We need to create a token, move it, and print its name or position.
See Handout H.A.15.1, A Token Class: token.h and token.cpp, and Handout H.A.15.2, Game.cpp. |
5. What source of data do we use to tell a token how many spaces to move? The client program could determine the number of spaces for a token to move, like a referee rolling the dice, telling each player how many spaces to move. A better choice would be to give each token a dice object, allowing it to determine how many squares it should move. It is better because it encapsulates a behavior inside of the object. This token object will have a private dice object to determine how far it should move. |
C. Constructors and Initializer Lists
1. The token class has one constructor with 4 parameters.
a. When a client program instantiates a token object, the 4 initial values must be provided: a single character name, a starting position, the winning position, and the maximum dice roll allowed for that token.
b. Notice the use of an initializer list. An initializer list begins with a colon (:) followed by each private variable name initialized with the parameters of the constructor. The token constructor has no programming statements between the braces.
2. In most cases, a constructor could be coded without using an initializer list. The private variables would be assigned appropriate values as program statements. But having a dice object as a private variable will require the use of an initializer lists. For example, here is an invalid attempt to use assignment statements in the token constructor.
token::token(char name, int startPos, int winPos, int maxDiceRoll)
// constructor w/o an initializer list
{
myName = name; // this works
myPosition = startPos; // so does this
myWinningPos = winPos; // and this also
myDice(maxDiceRoll); // but not this line
// or
Dice myDice(maxDiceRoll);
// the object now has 2 declarations of myDice
}
a. The line myDice(maxDiceRoll); is illegal because the myDice object was already instantiated. It is a private data member of the token class.
b. The second attempt Dice myDice(maxDiceRoll); is closer to what you need to do - construct the Dice object and tell it how many sides it has. But again, the myDice object is already a private data member of the token class; so this is trying to create a second version of myDice in the same token object.
3. This is a case where the private data member myDice must be constructed and initialized using an initializer list.
D. Analyzing the Token Class
1. We need to establish some terminology to categorize member functions. An accessor member function simply accesses private data members and returns a value. A mutator member function changes the value stored in a private data member.
2. The getPos and getName functions simply return private data values. Both of these functions are accessor member functions.
3. The move function rolls the dice for a token and updates its value of myPosition. Because it changes the value of myPosition, it is called a mutator member function. If the token gets to its winning position or beyond, the function returns true, otherwise false.
4. Notice that the client program does not have direct access to the private data members of the token class.
E. Const Member Functions
1. In general, when const is applied to a variable or a function, it prevents changes to memory.
2. Two of the functions in the token class have been designated as const member functions: getPos and getName. Because both of these member functions are accessor functions, they will not change any state information about a token. An accessor should be declared as a const member function because we plan to make no changes to private data members when such functions are called. The keyword const follows after the function header.
3. In a const member function, no changes can be made to private data members. Making appropriate member functions const is a programming strategy to protect yourself from making a careless mistake. If you correctly make a member function const, and then accidentally code the function to change private data, the compiler will not compile such code.
4. The function move is called a mutator function. It will cause a change to the private data member, myPosition. In this situation it is not appropriate to make it a const member function.
SUMMARY/REVIEW: The concept and syntax of classes in C++ takes some getting used to. The lab exercise will now give you an opportunity to put into practice the design and implementation of a class.
ASSIGNMENT: Lab Exercise, L.A.15.1, Frogs