Hour 8. Creating Basic Classes

What Is a Type?

One of the things that distinguishes humans is our ability to categorize. We don’t see hundreds of shapes in nature; we see animals, rocks, insects, and trees. We don’t just see animals; we see bears, foxes, raccoons, sasquatches, and so forth. We divide things into various classes that tell us what type of thing they are.

A sasquatch is a type of mammal. A mammal is a type of animal. An animal is a type of living thing.

In C++, a type is an object with data and a set of abilities. You’ve worked with built-in types such as int, long, and float numbers. You also can create your own types, as you discover this hour.

Computer programs are written to solve real-world problems, such as keeping track of employee paychecks or scheduling the games in a children’s soccer league. One of the best ways to write a program to accomplish large, complex tasks is to create representations of the objects that work together to perform the task.

So, if you’re creating a league schedule, you could have objects to represent each team in the league, each day that games can be played and each game on the schedule. The closer these objects correspond to reality, the easier it is to write the program.

Creating New Types

As you work with built-in types in C++, each variable’s type tells you quite a bit about it. For example, if you write a program with height and width declared as unsigned short integers, you know that each variable one can hold a number between 0 and 65,535.

The type also tells you capabilities of the variable. Short integers can be added together, so by declaring height and width as that type, you know they can be added together.

The type of a variable tells you several things:

• Its size in memory

• The information it can hold

• The actions that can be performed on it

In C++ you define your own types to model a problem you are trying to solve. The mechanism for declaring a new type is to create a class. A class is a definition of a new type.

Classes and Members

A C++ class is a template used to create objects. Once you define a class, objects created from that class can be put to use like any other data type.

A class is a collection of related variables and functions bundled together. The variables can be of any other type, including other classes.

Variables make up the data in the class, and functions perform tasks using that data. Bundling these together is called encapsulation.

This will make more sense in relation to a real object, such as the red tricycle my parents left behind during a move out of Wichita Falls, Texas, when I was 4 years old. (The U-Haul ran out of room. This is a touchy subject for me.)

One way to think about a trike is that it’s a collection of objects connected together—wheels, a seat, handlebars, and pedals. Another way is in terms of what it can do: move, accelerate, stop, and impress 4-year-old girls.

Combining these together—the physical aspects and performance—is encapsulating the object.

Encapsulation of a class makes it possible for other programs to use the class without knowing how it works. Users of your class only need to know what it does, not how it does it.

The variables of the class are called its member variables. A Tricycle class might have member variables representing the wheel size, top speed, and whether a baseball card has been embedded in the spokes.

Member variables, also known as data members or instance variables, are part of your class, just like the wheel and brake are part of a trike.

The functions in the class use and modify the member variables. They are called the member functions (or methods) of the class. Member functions of the Tricycle class might include pedal() and brake().

Member functions are as much a part of your class as member variables. They determine what the objects of your class can do.

Declaring a Class

To declare a class, use the class keyword followed by information about the member variables and member functions of the class. An opening brace and closing brace enclose the class definition. Here’s an example for a Tricycle class:

class Tricycle
{
public:
    unsigned int speed;
    unsigned int wheelSize;
    pedal();
    brake();
};

This code creates a class called Tricycle with two member variables, speed and wheelSize, and two member functions, pedal() and brake(). All four can be used by other classes because the public keyword precedes them in the class definition. You learn more about this keyword later in the hour.

Declaring this class does not allocate memory for a Tricycle. It just tells the compiler what the Tricycle class is—what data it contains (speed and wheelSize) and what it can do (pedal() and brake()).

It also tells the compiler how much room the compiler must set aside for each of the Tricycle objects that you create. In this example, if an integer is 4 bytes, Tricycle is only 8 bytes big: speed is 4 bytes and wheelSize is another 4. The two functions take up no room because no storage space is set aside for member functions.

Defining an Object

An object is created from a class by specifying its class and a variable name, just as you’ve done with built-in types in the preceding 7 hours. For example:

Tricycle wichita;

This statement creates a Tricycle object named wichita. The Tricycle class is used as a template for the object. The object will have all member variables and member functions defined for the class.

C++ differentiates between the class Tricycle, which is the concept of a tricycle, and each individual Tricycle object.

An object is just an individual instance of a class. When you create an object, you are said to “instantiate” it from the class.


By the Way

Because C++ is case sensitive, all class names should follow the same convention to minimize errors. Instead of having to remember whether a class is called Tricycle, tricycle, or TRICYCLE, if you always capitalize the first letter of a class name you’ll know it is Tricycle. Some programmers prefix every class name with a particular lowercase letter (for example, cTricycle or cSkateboard). The convention used in this book is initial capitalization, as in Tricycle and Sasquatch.

Member variables and functions also should follow the same naming rules. This book begins both with lowercase letters, as in speed and pedal().


Accessing Class Members

After you create an object, you use the dot operator (.) to access the member functions and variables of that object. As you might recall, the Tricycle class has a member variable called speed. To set this variable, use the dot operator:

Tricycle wichita;
wichita.speed = 6;

After the member function pedal() function has been defined, the dot operator is used to call it:

wichita.pedal();

Private Versus Public Access

The Tricycle class has two public member variables and two public member functions. The public keyword makes these parts of the class available to the public—in other words, other classes and programs that use Tricycle objects.

All member variables and functions are private by default. Private members can be accessed only within functions of the class itself. Public members can be accessed everywhere else. Here’s a modified definition of Tricycle:

class Tricycle
{
    unsigned int speed;
    unsigned int wheelSize;
    pedal();
    brake();
};

When the public keyword appears in a class definition, all member variables and functions after the keyword are public:

class Tricycle
{
    int model = 110;
public:
    unsigned int speed;
    unsigned int wheelSize;
    pedal();
    brake();
};

The preceding code declares everything in the Tricycle class public except for the model member variable.

There’s also a private keyword to make all subsequent member variables and functions private.

Each use of public or private changes access control from that point on to the end of the class or until the next access control keyword.

Keeping member data private limits access and controls how their values can be changed.

Although member variables can be public, it’s a good idea to keep them all private and make them available only via functions.

A function used to set or get the value of a private member variable is called an accessor. Other classes must call the accessor instead of working directly with the variable.

Accessors enable you to separate the details of how the data is stored from how it is used. If you later change how the data is stored, you don’t need to rewrite functions that use the data.

You create accessors in the next section.

Implementing Member Functions

Every class member function that you declare also must be defined.

A member function definition begins with the name of the class followed by the scope resolution operator (::) and the name of the function. Here’s an example:

void Tricycle::pedal()
{
    std::cout << "Pedaling trike ";
}

Class functions have the same capabilities as functions; they can have parameters and return a value.

The Tricycle program in Listing 8.1 defines a Tricycle class and takes it for a test drive.

Listing 8.1 The Full Text of Tricycle.cpp


 1: #include <iostream>
 2:
 3: class Tricycle
 4: {
 5: public:
 6:     int getSpeed();
 7:     void setSpeed(int speed);
 8:     void pedal();
 9:     void brake();
10: private:
11:     int speed;
12: };
13:
14: // get the trike's speed
15: int Tricycle::getSpeed()
16: {
17:     return speed;
18: }
19:
20: // set the trike's speed
21: void Tricycle::setSpeed(int newSpeed)
22: {
23:     if (newSpeed >= 0)
24:     {
25:         speed = newSpeed;
26:     }
27: }
28:
29: // pedal the trike
30: void Tricycle::pedal()
31: {
32:     setSpeed(speed + 1);
33:     std::cout << " Pedaling; tricycle speed " << speed << " mph ";
34: }
35:
36: // apply the brake on the trike
37: void Tricycle::brake()
38: {
39:     setSpeed(speed - 1);
40:     std::cout << " Braking; tricycle speed " << speed << " mph ";
41: }
42:
43: // create a trike and ride it
44: int main()
45: {
46:     Tricycle wichita;
47:     wichita.setSpeed(0);
48:     wichita.pedal();
49:     wichita.pedal();
50:     wichita.brake();
51:     wichita.brake();
52:     wichita.brake();
53:     return 0;
54: }


The Tricycle program creates a Tricycle object, sets its initial speed to 0 and calls the pedal() and brake() member functions several times. These functions increase and decrease the speed, respectively. Here’s the output:

Pedaling; tricycle speed 1 mph

Pedaling; tricycle speed 2 mph

Braking; tricycle speed 1 mph

Braking; tricycle speed 0 mph

Braking; tricycle speed 0 mph

Lines 3–12 contain the definition of the Tricycle class. Line 5 contains the keyword public, which tells the compiler that what follows is a set of public members. Line 6 has the declaration of the public accessor getSpeed(), which provides access to the private member variable speed declared on line 11. Line 7 has the public accessor setSpeed(), which takes an integer as an parameter and sets speed to the value of that parameter.

Line 10 begins the private section, which includes only the declaration of the private member variable speed.

Lines 15–18 contain the definition of the member function getSpeed(). This function takes no parameters; it returns an integer. Note that class member functions include the class name followed by two colons and the function’s name. This syntax tells the compiler that the getSpeed() function you are defining here is the one that you declared in the Tricycle class. With the exception of this header line, the getSpeed() function is created like any function.

The getSpeed() function is only one statement, which returns the value in the member variable speed. The program’s main() function cannot access speed because it is private in the Tricycle class. The main() function has access to the public function getSpeed(). Because getSpeed() is a function of the class, it has full access to its speed variable. This access enables the function to return the value of speed to main().

Lines 21–27 contain the definition of the setSpeed() function. It takes an integer parameter and sets the value of speed to the value of that parameter, but only if the parameter is greater than or equal to 0. By using an accessor and making speed private, the class controls how the variable is set. This restriction against negative speeds is an example of that.

Line 30 begins the pedal() function. This function increases the speed of the trike by 1 by calling setSpeed() and displays the current speed after acceleration.

Line 37 begins the brake() function, which decreases the speed by 1 with a call to setSpeed() and displays the current speed. The attempt to decrease the speed fails if speed equals 0, because 0 miles per hour is the slowest the trike can travel.

Line 44 begins the body of the program with the main() function. A Tricycle object named wichita is created and given an initial speed of 0. The Tricycle object’s pedal() and brake() function are called to change the rate of speed.

The last call to brake() in line 52 shows that the speed won’t go below 0. The trike already had stopped as of line 51, as the output illustrates.

Creating and Deleting Objects

There are two ways to define built-in types such as integers. One way is to define the variable and then assign a value to it later in the program:

int weight;
weight = 7;

Alternatively, you can define the integer and immediately initialize it:

int weight = 7;

Initialization combines the definition of the variable with its initial assignment. Nothing stops you from changing that value later, but initialization ensures that the variable always has a value.

Classes have a special member function called a constructor that is called when an object of the class is instantiated. The job of the constructor is to create a valid object of the class, which often includes initializing its member data. The constructor is a function with the same name as the class but no return value. Constructors may or may not have parameters, just like any other function of the class.

Here’s a constructor for the Tricycle class:

Tricycle::Tricycle(int initialSpeed)
{
    setSpeed(initialSpeed);
}

This constructor sets the initial value of the speed member variable using a parameter.

When you declare a constructor, you also should declare a destructor. Just as constructors create and initialize objects of your class, destructors clean up after objects and free any memory that was allocated for them. A destructor always has the name of the class preceded by a tilde (~). Destructors take no parameters and have no return value.

Here’s a Tricycle destructor:

Tricycle::~Tricycle()
{
    // do nothing
}

The destructor for the class requires no special actions to free up memory, so it just includes a comment.

Default Constructors

There are several ways to call constructors when setting up an object.

One is to specify one or more parameters in parentheses:

Tricycle wichita(5);

The parameter (or parameters) is sent to the constructor. In this example, it sets the initial speed of the trike.

You also can set an object up without specifying parameters:

Tricycle wichita;

This calls the default constructor of the class, which is a constructor with no parameters.

Constructors Provided by the Compiler

If you declare no constructors, as you did in the Tricycle program in Listing 8.1, the compiler creates a default constructor for you.

The default constructor the compiler provides takes no action; it is as if you declared a constructor with no parameters whose body was empty.

There are two important points to note:

• The default constructor is any constructor that takes no parameters. You can define it yourself or get it as a default from the compiler.

• If you define any constructor (with or without parameters), the compiler does not provide a default constructor for you. In that case, if you want a default constructor, you must define it yourself.

If you fail to define a destructor, the compiler also provides one of those, which also has an empty body and does nothing.

If you define a constructor, be sure to define a destructor even if your destructor does nothing. Although it is true that the default destructor would work correctly, it doesn’t hurt to define your own.

The NewTricycle program in Listing 8.2 rewrites the Tricycle class to use a constructor to initialize the object, setting its speed to an initial value. It also demonstrates where the destructor is called.

Listing 8.2 The Full Text of NewTricycle.cpp


 1: #include <iostream>
 2:
 3: class Tricycle
 4: {
 5: public:
 6:     Tricycle(int initialAge);
 7:     ~Tricycle();
 8:     int getSpeed();
 9:     void setSpeed(int speed);
10:     void pedal();
11:     void brake();
12: private:
13:     int speed;
14: };
15:
16: // constructor for the object
17: Tricycle::Tricycle(int initialSpeed)
18: {
19:     setSpeed(initialSpeed);
20: }
21:
22: // destructor for the object
23: Tricycle::~Tricycle()
24: {
25:     // do nothing
26: }
27:
28: // get the trike's speed
29: int Tricycle::getSpeed()
30: {
31:     return speed;
32: }
33:
34: // set the trike's speed
35: void Tricycle::setSpeed(int newSpeed)
36: {
37:     if (newSpeed >= 0)
38:     {
39:         speed = newSpeed;
40:     }
41: }
42:
43: // pedal the trike
44: void Tricycle::pedal()
45: {
46:     setSpeed(speed + 1);
47:     std::cout << " Pedaling; tricycle speed " << getSpeed() << " mph ";
48: }
49:
50: // apply the brake on the trike
51: void Tricycle::brake()
52: {
53:     setSpeed(speed - 1);
54:     std::cout << " Braking; tricycle speed " << getSpeed() << " mph ";
55: }
56:
57: // create a trike and ride it
58: int main()
59: {
60:     Tricycle wichita(5);
61:     wichita.pedal();
62:     wichita.pedal();
63:     wichita.brake();
64:     wichita.brake();
65:     wichita.brake();
66:     return 0;
67: }


This program produces the following output, which reflects an initial trike speed of 5 mph:

Pedaling; tricycle speed 6 mph

Pedaling; tricycle speed 7 mph

Braking; tricycle speed 6 mph

Braking; tricycle speed 5 mph

Braking; tricycle speed 4 mph

The Tricycle class definition in Listing 8.2 has two new additions: a declaration for a constructor that takes an integer parameter and a declaration for a constructor.

Lines 17–20 show the implementation of the constructor, which is similar to the implementation of the SetAge() accessor function. There is no return value.

Lines 23–26 show the implementation of the destructor ~Tricycle().

A Tricycle object is created in Line 60 and given an initial value of 5 with a parameter to the constructor.

Summary

Over the history of computer programming there have been several popular methodologies for creating programs. The one introduced in this hour is called object-oriented programming (OOP) because of how it conceives of programs.

In OOP, a program consists of one or more objects, each of which has its own data in the form of member data and functions in the form of functions. The objects are separate from each other and specialize in a specific and narrow purpose.

By designing objects to be independent of each other, you create code that’s more easily reused elsewhere. If you created a Printer class in a program to print documents, that class can be used by other programs you write if they need printing capabilities.

You learn more about OOP in the next hour as you delve deeper into classes.

Q&A

Q. How big is a class object?

A. A class object’s size in memory is determined by the sum of the sizes of its member variables. Class functions don’t take up room as part of the memory set aside for the object.

Some compilers align variables in memory in such a way that 2-byte variables actually consume somewhat more than 2 bytes.

Q. Why shouldn’t I make all the member data public?

A. Making member data private enables the client of the class to use the data without worrying about how it is stored or computed. For example, if the Tricycle class has a member function getSpeed(), clients of the Tricycle class can ask for the trike’s speed without knowing if the trike stores its speed in a member variable or computes it on-the-fly. Public data is like global data—any code that uses the object can access the data. So if it becomes changed, there’s often a difficult time figuring out where it happened.

Q. Why do lawn gnomes protect our yards instead of lawn elves, lawn dwarves, lawn halflings, lawn half-elves, or lawn half-orcs?

A. Lawn gnomes date back to 19th century Germany, where in the village of Thuringia the ceramic artisan Phillip Griebel created the first yard protectors in honor of local myths about how gnomes protected gardens at night.

The gnomes proved popular enough to spread all over Germany, then over to England, and finally the world. They’re typically bearded males with a red hat who smoke pipes.

A popular prank in recent years is “gnoming,” which is stealing someone’s lawn gnome and having him photographed at remote locations, perhaps even on a foreign vacation. In France in the late 1990s, a group calling itself the Garden Gnome Liberation Front stole more than 150 in a bid to give them their freedom.

Workshop

Now that you’ve gotten to see classes and objects, you can answer a few questions and complete a couple of exercises to firm up your knowledge and understanding.

Quiz

1. Which of the following does not take up computer memory?

A. Class

B. Object

C. Both

2. What keyword prevents some member data and functions from being used outside of the class?

A. public

B. private

C. Neither

3. Why did the author’s parents leave his tricycle behind when he was 4?

A. Cruel indifference

B. A moving truck ran out of room

C. Because adversity builds character

Answers

1. A. A class occupies no memory because it is just a definition of how an object would be created. An object is the implementation of that class.

2. B. Private data and functions can be accessed only within the class itself. Public data and functions can be accessed outside of the class. You generally want to keep all your class data items private and the functions public (so they can be called).

3. B. The U-Haul van they were renting ran out of room. I’ve been told I received a new tricycle shortly after we arrived in Dallas, but I don’t remember it.

Activities

1. Modify the Tricycle application to add a second trike. Give it an initial value and try the pedal() and brake() member functions on it.

2. Modify the NewTricycle application to add a member variable called wheelSize that must be at least 4 in value when set with an accessor.

To see solutions to these activities, visit this book’s website at http://cplusplus.cadenhead.org.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.188.27