240 Structures and Classes
to tell what a member function is a member of. However, the scope resolution operator ::
is used with a class name, whereas the dot operator is used with objects (that is, with class
variables). The scope resolution operator consists of two colons with no space between
them. The class name that precedes the scope resolution operator is often called a type
qualifier, because it specializes (“qualifies”) the function name to one particular type.
Look at the definition of the member function
DayOfYear::output given in Display
6.3. Notice that in the function definition of
DayOfYear::output, we used the member
names
month and day by themselves without first giving the object and dot operator. That
is not as strange as it may at first appear. At this point we are simply defining the member
function
output. This definition of output will apply to all objects of type DayOfYear, but
at this point we do not know the names of the objects of type
DayOfYear that we will use,
so we cannot give their names. When the member function is called, as in
today.output( );
all the member names in the function definition are specialized to the name of the call-
ing object. So, the above function call is equivalent to the following:
{
switch (today.month)
{
case 1:
.
.
.
}
cout << today.day;
}
type qualifier
member
variables in
function
definitions
M
EMBER
F
UNCTION
D
EFINITION
A member function is defined similar to any other function except that the
Class_Name
and the
scope resolution operator,
::, are given in the function heading.
S
YNTAX
Returned_Type
Class_Name
::
Function_Name
(
Parameter_List
)
{
Function_Body_Statements
}
E
XAMPLE
See Display 6.3. Note that the member variables (month and day) are not preceded by an object
name and dot when they occur in a member function definition.
06_CH06.fm Page 240 Wednesday, August 13, 2003 12:54 PM
Classes 241
Self-Test Exercises
In the function definition for a member function, you can use the names of all mem-
bers of that class (both the data members and the function members) without using the
dot operator.
9. Below we have redefined the class DayOfYear from Display 6.3 so that it now has one
additional member function called
input. Write an appropriate definition for the member
function
input.
class DayOfYear
{
public:
T
HE
D
OT
O
PERATOR
AND
THE
S
COPE
R
ESOLUTION
O
PERATOR
Both the dot operator and the scope resolution operator are used with member names to specify
of what thing they are a member. For example, suppose you have declared a class called
DayOf-
Year
and you declare an object called today as follows:
DayOfYear today;
You use the dot operator to specify a member of the object today. For example, output is a
member function for the class
DayOfYear (defined in Display 6.3), and the following function
call will output the data values stored in the object
today:
today.output( );
You use the scope resolution operator, ::, to specify the class name when giving the function
definition for a member function. For example, the heading of the function definition for the
member function
output would be as follows:
void DayOfYear::output( )
Remember, the scope resolution operator, ::, is used with a class name, whereas the dot operator
is used with an object of that class.
A C
LASS
I
S
A
F
ULL
-F
LEDGED
T
YPE
A class is a type just like the types int and double. You can have variables of a class type, you
can have parameters of a class type, a function can return a value of a class type, and more gen-
erally, you can use a class type like any other type.
06_CH06.fm Page 241 Wednesday, August 13, 2003 12:54 PM
242 Structures and Classes
void input( );
void output( );
int month;
int day;
};
10. Given the following class definition, write an appropriate definition for the member func-
tion
set.
class Temperature
{
public:
void set(double newDegrees, char newScale);
//Sets the member variables to the values given as
//arguments.
double degrees;
char scale; //’F’ for Fahrenheit or ’C’ for Celsius.
};
11. Carefully distinguish between the meaning and use of the dot operator and the scope reso-
lution operator,
::.
■
ENCAPSULATION
A data type, such as the type int, has certain specified values, such as 0, 1, −1, 2, and so
forth. You tend to think of the data type as being these values, but the operations on
these values are just as important as the values. Without the operations, you could do
nothing of interest with the values. The operations for the type
int consist of +, −, *, /,
%, and a few other operators and predefined library functions. You should not think of
a data type as being simply a collection of values. A data type consists of a collection of
values together with a set of basic operations defined on these values. A data type is
called an abstract data type (abbreviated ADT) if the programmers who use the type
do not have access to the details of how the values and operations are implemented.
The predefined types, such as
int, are abstract data types (ADTs). You do not know
how the operations, such as
+ and *, are implemented for the type int. Even if you did
know, you could not use this information in any C++ program. Classes, which are
programmer-defined types, should also be ADTs; that is, the details of how the “opera-
tions” are implemented should be hidden from, or at least irrelevant to, any program-
mer who uses the class. The operations of a class are the (public) member functions of
the class. A programmer who uses a class should not need to even look at the defini-
tions of the member functions. The member function declarations, given in the class
definition, and a few comments should be all the programmer needs in order to use the
class.
data types
and abstract
data types
06_CH06.fm Page 242 Wednesday, August 13, 2003 12:54 PM
Classes 243
A programmer who uses a class also should not need to know how the data of the
class is implemented. The implementation of the data should be as hidden as the imple-
mentation of the member functions. In fact, it is close to impossible to distinguish
between hiding the implementation of the member functions and the implementation
of the data. To a programmer, the class
DayOfYear (Display 6.3) has dates as data, not
numbers. The programmer should not know or care whether the month March is
implemented as the
int value 3, the quoted string "March", or in some other way.
Defining a class so that the implementation of the member functions and the imple-
mentation of the data in objects are not known, or is at least irrelevant, to the program-
mer who uses the class is known by a number of different terms. The most common
terms used are information hiding, data abstraction, and encapsulation, each of
which means that the details of the implementation of a class are hidden from the pro-
grammer who uses the class. This principle is one of the main tenets of object-oriented
programming (OOP). When discussing OOP, the term that is used most frequently is
encapsulation. One of the ways to apply this principle of encapsulation to your class
definitions is to make all member variables private, which is what we discuss in the next
subsection.
■
PUBLIC AND PRIVATE MEMBERS
Look back at the definition of the type DayOfYear given in Display 6.3. In order to use
that class, you need to know that there are two member variables of type
int that are
named
month and day. This violates the principle of encapsulation (information hiding)
that we discussed in the previous subsection. Display 6.4 is a rewritten version of the
class
DayOfYear that better conforms to this encapsulation principle.
Notice the words
private: and public: in Display 6.4. All the items that follow
the word
private: (in this case the member variables month and day) are said to be
private, which means that they cannot be referenced by name anyplace except within
the definitions of the member functions of the class
DayOfYear. For example, with this
changed definition of the class
DayOfYear, the following two assignments and other
indicated code are no longer permitted in the
main function of the program and are
not permitted in any other function definition, except for member functions of the
class
DayOfYear:
DayOfYear today; //This line is OK.
today.month = 12;//ILLEGAL
today.day = 25;//ILLEGAL
cout << today.month;//ILLEGAL
cout << today.day;//ILLEGAL
if (today.month
== 1) //ILLEGAL
cout << "January";
Once you make a member variable a private member variable, there is no way to
change its value (or to reference the member variable in any other way) except by using
one of the member functions. That means that the compiler will enforce the hiding of
encapsu-
lation
private:
private
member
variable
06_CH06.fm Page 243 Wednesday, August 13, 2003 12:54 PM
244 Structures and Classes
Display 6.4 Class with Private Members
(part 1 of 3)
1 #include <iostream>
2 #include <cstdlib>
3 using namespace std;
4 class DayOfYear
5 {
6 public:
7 void input(
);
8 void output(
);
9 void set(int newMonth, int newDay);
10 //Precondition: newMonth and newDay form a possible date.
11 void set(int newMonth);
12 //Precondition: 1 <= newMonth <= 12
13 //Postcondition: The date is set to the first day of the given month.
14 int getMonthNumber(
); //Returns 1 for January, 2 for February, etc.
15 int getDay(
);
16 private:
17 int month;
18 int day;
19 };
20 int main(
)
21 {
22 DayOfYear today, bachBirthday;
23 cout << "Enter today’s date:\n";
24 today.input(
);
25 cout << "Today’s date is ";
26 today.output(
);
27 cout << endl;
28 bachBirthday.set(3, 21);
29 cout << "J. S. Bach’s birthday is ";
30 bachBirthday.output(
);
31 cout << endl;
32 if ( today.getMonthNumber(
) == bachBirthday.getMonthNumber( ) &&
33 today.getDay(
) == bachBirthday.getDay( ) )
34 cout << "Happy Birthday Johann Sebastian!\n";
35 else
36 cout << "Happy Unbirthday Johann Sebastian!\n";
37
38 return 0;
39 }
40 //Uses iostream and cstdlib:
41 void DayOfYear::set(int newMonth, int newDay)
Private members
This is an improved version
of the class
DayOfYear that we gave
in Display 6.3.
Note that the function name set is
overloaded. You can overload a
member function just like you can
overload any other function.
06_CH06.fm Page 244 Wednesday, August 13, 2003 12:54 PM
Classes 245
Display 6.4 Class with Private Members
(part 2 of 3)
42 {
43 if ((newMonth >= 1) && (newMonth <= 12))
44 month = newMonth;
45 else
46 {
47 cout << "Illegal month value! Program aborted.\n";
48 exit(1);
49 }
50 if ((newDay >= 1) && (newDay <= 31))
51 day = newDay;
52 else
53 {
54 cout << "Illegal day value! Program aborted.\n";
55 exit(1);
56 }
57 }
58 //Uses iostream and cstdlib:
59 void DayOfYear::set(int newMonth)
60 {
61 if ((newMonth >= 1) && (newMonth <= 12))
62 month = newMonth;
63 else
64 {
65 cout << "Illegal month value! Program aborted.\n";
66 exit(1);
67 }
68 day = 1;
69 }
70
71 int DayOfYear::getMonthNumber(
)
72 {
73 return month;
74 }
75 int DayOfYear::getDay(
)
76 {
77 return day;
78 }
79 //Uses iostream and cstdlib:
80 void DayOfYear::input(
)
81 {
82 cout << "Enter the month as a number: ";
83 cin >> month;
84 cout << "Enter the day of the month: ";
85 cin >> day;
Mutator functions
Accessor functions
Private members may
be used in member
function definitions
(but not elsewhere).
06_CH06.fm Page 245 Wednesday, August 13, 2003 12:54 PM
246 Structures and Classes
the implementation of the data for the class DayOfYear. If you look carefully at the pro-
gram in Display 6.4, you will see that the only place the member variable names
month
and day are used is in the definitions of the member functions. There is no reference to
today.month, today.day, bachBirthday.month, or bachBirthday.day anyplace outside
the definitions of member functions.
All the items that follow the word
public: (in this case the member functions) are
said to be public, which means that they can be referenced by name anyplace. There
are no restrictions on the use of public members.
Any member variables can be either public or private. Any member functions can be
public or private. However, normal good programming practices require that all mem-
ber variables be private and that typically most member functions be public.
You can have any number of occurrences of
public and private access specifiers in
a class definition. Every time you insert the label
public:
the list of members changes from private to public. Every time you insert the label
private:
the list of members changes back to being private members. You need not have just one
public and one private group of members. However, it is common to have just one
public section and one private section.
Display 6.4 Class with Private Members
(part 3 of 3)
86 if ((month < 1) || (month > 12) || (day < 1) || (day > 31))
87 {
88 cout << "Illegal date! Program aborted.\n";
89 exit(1);
90 }
91 }
92 void DayOfYear::output(
)
93
<
The rest of the definition of DayOfYear::output is given in Display 6.3.
>
S
AMPLE
D
IALOGUE
Enter today’s date:
Enter the month as a number: 3
Enter the day of the month: 21
Today’s date is March 21
J. S. Bach’s birthday is March 21
Happy Birthday Johann Sebastian!
public:
public
member
variable
06_CH06.fm Page 246 Wednesday, August 13, 2003 12:54 PM
Classes 247
There is no universal agreement about whether the public members should be listed
first or the private members should be listed first. The majority seem to prefer listing
the public members first. This allows for easy viewing of the portions programmers
using the class actually get to use. You can make your own decision on what you wish
to place first, but the examples in the book will go along with the majority and list the
public members before the private members.
In one sense C++ seems to favor placing the private members first. If the first group
of members has neither the
public: nor the private: specifier, then members of that
group will automatically be private. You will see this default behavior used in code and
should be familiar with it. However, we will not use it in this book.
■
ACCESSOR AND MUTATOR FUNCTIONS
You should always make all member variables in a class private. You may sometimes
need to do something with the data in a class object, however. The member functions
will allow you to do many things with the data in an object, but sooner or later you will
want or need to do something with the data for which there is no member function.
How can you do anything new with the data in an object? The answer is that you can do
anything you might reasonably want, provided you equip your classes with suitable
accessor and mutator functions. These are member functions that allow you to access
and change the data in an object in a very general way. Accessor functions allow you to
read the data. In Display 6.4, the member functions
getMonthNumber and getDay are
accessor functions. The accessor functions need not literally return the values of each
member variable, but they must return something equivalent to those values. For exam-
ple, for a class like
DayOfYear, you might have an accessor function return the name of
the month as some sort of string value, rather than return the month as a number.
Mutator functions allow you to change the data. In Display 6.4, the two functions
named
set are mutator functions. It is traditional to use names that include the word
get for accessor functions and names that include the word set for mutator functions.
(The functions
input and output in Display 6.4 are really mutator and accessor func-
tions, respectively, but I/O is such a special case that they are usually just called I/O
functions rather than accessor or mutator functions.)
Your class definitions should always provide an adequate collection of accessor and
mutator functions.
It may seem that accessor and mutator functions defeat the purpose of making mem-
ber variables private, but that is not so. Notice the mutator function
set in Display 6.4.
It will not allow you to set the
month member variable to 13 or to any number that does
not represent a month. Similarly, it will not allow you to set the
day member variable to
any number that is not in the range
1 to 31 (inclusive). If the variables were public you
could set the data to values that do not make sense for a date. (As it is, you can still set
the data to values that do not represent a real date, such as February 31, but it would be
easy to exclude these dates as well. We did not exclude these dates to keep the example
simple.) With mutator functions, you can control and filter changes to the data.
accessor
function
mutator
function
06_CH06.fm Page 247 Wednesday, August 13, 2003 12:54 PM
248 Structures and Classes
Tip
Self-Test Exercises
12. Suppose your program contains the following class definition,
class Automobile
{
public:
void setPrice(double newPrice);
void setProfit(double newProfit);
double getPrice(
);
private:
double price;
double profit;
double getProfit(
);
};
and suppose the main function of your program contains the following declaration and that
the program somehow sets the values of all the member variables to some values:
Automobile hyundai, jaguar;
Which of the following statements are then allowed in the main function of your program?
hyundai.price = 4999.99;
jaguar.setPrice(30000.97);
double aPrice, aProfit;
aPrice = jaguar.getPrice(
);
aProfit = jaguar.getProfit(
);
aProfit = hyundai.getProfit(
);
hyundai = jaguar;
13. Suppose you change Self-Test Exercise 12 so that in the definition of the class Automobile
all member variables are public instead of private. How would this change your answer to
the question in Self-Test Exercise 12?
14. Explain what
public: and private: mean in a class definition.
15. a. How many
public: sections are required in a class for the class to be useful?
b. How many
private: sections are required in a class?
S
EPARATE
I
NTERFACE
AND
I
MPLEMENTATION
The principle of encapsulation says that you should define classes so that a programmer who uses
the class need not be concerned with the details of how the class is implemented. The programmer
who uses the class need only know the rules for how to use the class. The rules for how to use the
class are known as the ii
ii
nn
nn
tt
tt
ee
ee
rr
rr
ff
ff
aa
aa
cc
cc
ee
ee
or AA
AA
PP
PP
II
II
. There is some disagreement on exactly what the initials API
stand for, but it is generally agreed that they stand for something like
application programmer
interface
API
06_CH06.fm Page 248 Wednesday, August 13, 2003 12:54 PM
Classes 249
Tip
interface
or
abstract programming interface
or something similar. In this book we will call these
rules the
interface
for the class. It is important to keep in mind a clear distinction between the
interface and the implementation of a class. If your class is well designed, then any programmer
who uses the class need only know the interface for the class and need not know any details of the
implementation of the class. A class whose interface and implementation are separated in this
way is sometimes called an
abstract data type (ADT)
or a nicely encapsulated class. In Chapter 11
we will show you how to separate the interface and implementation by placing them in different
files, but the important thing is to keep them conceptually separated.
For a C++ class, the ii
ii
nn
nn
tt
tt
ee
ee
rr
rr
ff
ff
aa
aa
cc
cc
ee
ee
consists of two sorts of things: the comments, usually at the begin-
ning of the class definition, that tell what the data of the object is supposed to represent, such as
a date or bank account or state of a simulated car wash; and the public member functions of the
class along with the comments that tell how to use these public member functions. In a well-
designed class, the interface of the class should be all you need to know in order to use the class
in your program.
The ii
ii
mm
mm
pp
pp
ll
ll
ee
ee
mm
mm
ee
ee
nn
nn
tt
tt
aa
aa
tt
tt
ii
ii
oo
oo
nn
nn
of a class tells how the class interface is realized as C++ code. The implemen-
tation consists of the private members of the class and the definitions of both the public and pri-
vate member functions. Although you need the implementation in order to run a program that
uses the class, you should not need to know anything about the implementation in order to write
the rest of a program that uses the class; that is, you should not need to know anything about the
implementation in order to write the
main function of the program and to write any nonmember
functions or other classes used by the
main function.
The most obvious benefit you derive from cleanly separating the interface and implementation of
your classes is that you can change the implementation without having to change the other parts
of your program. On large programming projects this division between interface and implemen-
tation will facilitate dividing the work among different programmers. If you have a well-designed
interface, then one programmer can write the implementation for the class while other program-
mers write the code that uses the class. Even if you are the only programmer working on a project,
you have divided one larger task into two smaller tasks, which makes your program easier to
design and to debug.
A T
EST
FOR
E
NCAPSULATION
If your class definition produces an ADT (that is, if it properly separates the interface and the
implementation), then you can change the implementation of the class (that is, change the data
representation and/or change the implementation of some member functions) without needing
to change any (other) code for any program that uses the class definition. This is a sure test for
whether you have defined an ADT or just some class that is not properly encapsulated.
For example, you can change the implementation of the class
DayOfYear in Display 6.4 to the
following and no program that uses this class definition would need any changes:
class DayOfYear
{
implemen-
tation
06_CH06.fm Page 249 Wednesday, August 13, 2003 12:54 PM
250 Structures and Classes
public:
void input(
);
void output(
);
void set(int newMonth, int newDay);
//Precondition: newMonth and newDay form a possible date.
//Postcondition: The date is reset according to the arguments.
void set(int newMonth);
//Precondition: 1 <= newMonth <= 12
//Postcondition: The date is set to first day of the month.
int getMonthNumber(
);
//Returns 1 for January, 2 for February, etc.
int getDay(
);
private:
char firstLetter;//of month
char secondLetter;//of month
char thirdLetter;//of month
int day;
};
In this version, a month is represented by the first three letters in its name, such as ’J’, ’a’, and
’n’ for January. The member functions should also be rewritten, of course, but they can be
rewritten to behave
exactly
as they did before. For example, the definition of the function get-
MonthNumber
might start as follows:
int DayOfYear::getMonthNumber( )
{
if (firstLetter == ’J’ && secondLetter == ’a’
&& thirdLetter == ’n’)
return 1;
if (firstLetter == ’F’ && secondLetter == ’e’
&& thirdLetter == ’b’)
return 2;
. . .
This would be rather tedious, but not difficult.
■
STRUCTURES VERSUS CLASSES
Structures are normally used with all member variables public and with no member
functions. However, in C++ a structure can have private member variables and both
public and private member functions. Aside from some notational differences, a C++
structure can do anything a class can do. Having said this and satisfied the “truth in adver-
tising” requirement, we advocate that you forget this technical detail about structures. If
06_CH06.fm Page 250 Wednesday, August 13, 2003 12:54 PM
Classes 251
C
LASSES
AND
O
BJECTS
A class is a type whose variables can have both member variables and member functions. The
syntax for a class definition is given below.
S
YNTAX
class
Class_Name
{
.
public:
Member_SpecificationN+1
Member_SpecificationN+2
.
.
.
private:
Member_Specification_1
Member_Specification_2
.
.
.
Member_SpecificationN
};
Each
Member_Specification_i
is either a member variable declaration or a member function
declaration (prototype).
Additional public: and private: sections are permitted. If the first group of members does
not have either a
public: or a private: label, then it is the same as if there were a private:
before the first group.
E
XAMPLE
class Bicycle
{
public:
char getColor( );
int numberOfSpeeds( );
void set(int theSpeeds, char theColor);
private:
int speeds;
char color;
};
Once a class is defined, an object variable (variable of the class type) can be declared in the same
way as variables of any other type. For example, the following declares two object variables of
type
Bicycle:
Bicycle myBike, yourBike;
Public members
Private members
Do not forget this semicolon.
06_CH06.fm Page 251 Wednesday, August 13, 2003 12:54 PM
252 Structures and Classes
Self-Test Exercises
Tip
you take this technical detail seriously and use structures in the same way that you use
classes, then you will have two names (with different syntax rules) for the same con-
cept. On the other hand, if you use structures as we described them, then you will have
a meaningful difference between structures (as you use them) and classes; and your
usage will be the same as that of most other programmers.
One difference between a structure and a class is that they differ in how they treat an
initial group of members that has neither a public nor a private access specifier. If the
first group of members in a definition is not labeled with either
public: or private:,
then a structure assumes the group is public, whereas a class would assume the group is
private.
T
HINKING
O
BJECTS
If you have not programmed with classes before, it can take a little while to get the feel of pro-
gramming with them. When you program with classes, data rather than algorithms takes center
stage. It is not that there are no algorithms. However, the algorithms are made to fit the data, as
opposed to designing the data to fit the algorithms. It’s a difference in point of view. In the
extreme case, which is considered by many to be the best style, you have no global functions at
all, only classes with member functions. In this case, you define objects and how the objects inter-
act, rather than algorithms that operate on data. We will discuss the details of how you accom-
plish this throughout this book. Of course, you can ignore classes completely or relegate them to a
minor role, but then you are really programming in C, not C++.
16. When you define a C++ class, should you make the member variables public or private?
Should you make the member functions public or private?
17. When you define a C++ class, what items are considered part of the interface? What items
are considered part of the implementation?
■ A structure can be used to combine data of different types into a single (compound)
data value.
■ A class can be used to combine data and functions into a single (compound) object.
■ A member variable or a member function for a class can be either public or private.
If it is public, it can be used outside the class. If it is private, it can be used only in
the definition of a member function.
Chapter Summary
06_CH06.fm Page 252 Wednesday, August 13, 2003 12:54 PM
Answers to Self-Test Exercises 253
■ A function can have formal parameters of a class or structure type. A function can
return values of a class or structure type.
■ A member function for a class can be overloaded in the same way as ordinary func-
tions are overloaded.
■ When defining a C++ class, you should separate the interface and implementation
so that any programmer who uses the class need only know the interface and need
not even look at the implementation. This is the principle of encapsulation.
ANSWERS TO SELF-TEST EXERCISES
1. a. double
b. double
c. illegal—cannot use a structure tag instead of a structure variable
d.
char
e. CDAccountV2
2. A $9.99
A $1.11
3. A semicolon is missing from the end of the definition of Stuff.
4.
A x = {1,2};
5. a. Too few initializers; not a syntax error. After initialization, month==12, day==21, and
year==0. Member variables not provided an initializer are initialized to a zero of the
appropriate type.
b. Correct after initialization.
12==month, 21==day, and 1995==year.
c. Error: too many initializers.
6.
struct EmployeeRecord
{
double wageRate;
int vacation;
char status;
};
7. void readShoeRecord(ShoeType& newShoe)
{
cout << "Enter shoe style (one letter): ";
cin >> newShoe.style;
cout << "Enter shoe price $";
cin >> newShoe.price;
}
06_CH06.fm Page 253 Wednesday, August 13, 2003 12:54 PM
254 Structures and Classes
8. ShoeType discount(ShoeType oldRecord)
{
ShoeType temp;
temp.style = oldRecord.style;
temp.price = 0.90*oldRecord.price;
return temp;
}
9. void DayOfYear::input( )
{
cout << "Enter month as a number: ";
cin >> month;
cout << "Enter the day of the month: ";
cin >> day;
}
10. void Temperature::set(double newDegrees, char newScale)
{
degrees = newDegrees;
scale = newScale;
}
11. Both the dot operator and the scope resolution operator are used with member names to
specify of what class or structure the member name is a member. If
class DayOfYear is as
defined in Display 6.3 and
today is an object of the class DayOfYear, then the member
month may be accessed with the dot operator: today.month. When we give the definition
of a member function, the scope resolution operator is used to tell the compiler that this
function is the one declared in the class.
12.
hyundai.price = 4999.99; //ILLEGAL. price is private.
jaguar.setPrice(30000.97); //LEGAL
double aPrice, aProfit;//LEGAL
aPrice = jaguar.getPrice(
);//LEGAL
aProfit = jaguar.getProfit(
);//ILLEGAL. getProfit is
//private.
aProfit = hyundai.getProfit(
);//ILLEGAL. getProfit is
// private.
hyundai = jaguar;//LEGAL
13. After the change, they would all be legal.
14. All members (member variables and member functions) that are marked
private: can
only be accessed by name in the definitions of member functions (both public and private)
of the same class. Members marked
public: have no restrictions on where they can be
used.
06_CH06.fm Page 254 Wednesday, August 13, 2003 12:54 PM
Programming Projects 255
15. a. Only one. The compiler warns if you have no public: members in a class (or struct,
for that matter).
b. None, but we normally expect to find at least one
private: section in a class.
16. The member variables should all be private. The member functions that are part of the
interface should be public. You may also have auxiliary (helping) functions that are only
used in the definitions of other member functions. These auxiliary functions should be
private.
17. All the declarations of private member variables are part of the implementation. (There
should be no public member variables.) All the declarations for public member functions
of the class (which are listed in the class definitions), as well as the explanatory comments
for these declarations, are parts of the interface. All the declarations for private member
functions are parts of the implementation. All member function definitions (whether the
function is public or private) are parts of the implementation.
PROGRAMMING PROJECTS
1. Write a grading program for a class with the following grading policies.
a. There are two quizzes, each graded on the basis of 10 points.
b. There is one midterm exam and one final exam, each graded on the basis of 100 points.
c. The final exam counts for 50% of the grade, the midterm counts for 25%, and the two
quizzes together count for a total of 25%. (Do not forget to normalize the quiz scores. They
should be converted to a percentage before they are averaged in.)
Any grade of 90 or more is an A, any grade of 80 or more (but less than 90) is a B, any
grade of 70 or more (but less than 80) is a C, any grade of 60 or more (but less than 70) is a
D, and any grade below 60 is an F. The program will read in the student’s scores and out-
put the student’s record, which consists of two quiz and two exam scores as well as the stu-
dent’s average numeric score for the entire course and final letter grade. Define and use a
structure for the student record.
2. Define a class for a type called
CounterType. An object of this type is used to count things,
so it records a count that is a nonnegative whole number. Include a mutator function that
sets the counter to a count given as an argument. Include member functions to increase the
count by one and to decrease the count by one. Be sure that no member function allows the
value of the counter to become negative. Also, include a member function that returns the
current count value and one that outputs the count. Embed your class definition in a test
program.
3. The type
Point is a fairly simple data type, but under another name (the template class
pair) this data type is defined and used in the C++ Standard Template Library, although
you need not know anything about the Standard template Library to do this exercise. Write
a definition of a class named
Point that might be used to store and manipulate the location
06_CH06.fm Page 255 Wednesday, August 13, 2003 12:54 PM
256 Structures and Classes
of a point in the plane. You will need to declare and implement the following member
functions:
a. a member function
set that sets the private data after an object of this class is created.
b. a member function to move the point by an amount along the vertical and horizontal
directions specified by the first and second arguments.
c. a member function to rotate the point by 90 degrees clockwise around the origin.
d. two
const inspector functions to retrieve the current coordinates of the point.
Document these functions with appropriate comments. Embed your class in a test program
that requests data for several points from the user, creates the points, then exercises the
member functions.
4. Write the definition for a class named
GasPump to be used to model a pump at an automo-
bile service station. Before you go further with this programming exercise, write down the
behavior you expect from a gas pump from the point of view of the purchaser.
Below are listed things a gas pump might be expected to do. If your list differs, and you
think your list is as good or better than these, then consult your instructor. You and your
instructor should jointly decide what behavior you are to implement. Then implement and
test the agreed upon design for a gas pump class.
a. A display of the amount dispensed,
b. A display of the amount charged for the amount dispensed
d. A display of the cost per gallon, liter, or other unit of volume that is used where you reside.
e. Before use, the gas pump must reset the amount dispensed and amount charged to zero.
f. Actual behavior of the gas pump is, once started, it dispenses as long as you hold the nozzle
lever. Peculiarities of console I/O make it difficult to continue to dispense while waiting for
signal to stop. One solution is to model this behavior by having the user repeatedly press
the return (enter) key, dispensing a quantum of fuel and recomputing the amount charged,
say 0.1 gallons at each press.
g. A stop dispensing control of some kind is needed.
Implement the behavior of the gas pump as declarations of member functions of the gas
pump class, then write implementations of these member functions. You will have to
decide if there is data the gas pump has to keep track of that the user of the pump should
not have access to. If so, make these private member variables.
06_CH06.fm Page 256 Wednesday, August 13, 2003 12:54 PM
2.5
For additional online
Programming
Projects, click the
CodeMate icons
below.
1.7
7
Constructors and Other Tools
7.1 CONSTRUCTORS 258
Constructor Definitions 258
Pitfall: Constructors with No Arguments 263
Explicit Constructor Calls 265
Tip: Always Include a Default Constructor 265
Example:
BankAccount
Class 268
Class Type Member Variables 274
7.2 MORE TOOLS 277
The
const
Parameter Modifier 277
Pitfall: Inconsistent Use of
const
279
Inline Functions 284
Static Members 286
Nested and Local Class Definitions 289
7.3 VECTORS—A PREVIEW OF THE STANDARD
TEMPLATE LIBRARY 290
Vector Basics 290
Pitfall: Using Square Brackets beyond the Vector Size 293
Tip: Vector Assignment Is Well Behaved 294
Efficiency Issues 294
CHAPTER SUMMARY 296
ANSWERS TO SELF-TEST EXERCISES 296
PROGRAMMING PROJECTS 298
07_CH07.fm Page 257 Wednesday, August 13, 2003 12:58 PM
7
Constructors and Other Tools
Give us the tools and, and we will finish the job.
Winston Churchill
, Radio broadcast (February 9, 1941)
INTRODUCTION
This chapter presents a number of important tools to use when programming
with classes. The most important of these tools are class constructors, a kind of
function used to initialize objects of the class.
Section 7.3 introduces
vectors
as an example of classes and as a preview of
the Standard Template Library (STL). Vectors are similar to arrays but can
grow and shrink in size. The STL is an extensive library of predefined classes.
Section 7.3 may be covered now or later. The material in Chapters 8 through
18 does not require the material in Section 7.3, so you may postpone covering
vectors (Section 7.3) if you wish.
Sections 7.1 and 7.2 do not use the material in Chapter 5 but do use the
material in Chapter 6. Section 7.3 requires Chapters 1 through 6 as well as
Section 7.1.
Constructors
Well begun is half done.
Proverb
Often you want to initialize some or all the member variables for an object
when you declare the object. As we will see later in this book, there are other
initializing actions you might also want to take, but initializing member vari-
ables is the most common sort of initialization. C++ includes special provi-
sions for such initializations. When you define a class you can define a special
kind of member function known as a
constructor
.
A constructor is a member
function that is automatically called when an object of that class is declared. A
constructor is used to initialize the values of some or all member variables and
to do any other sort of initialization that may be needed.
■
CONSTRUCTOR DEFINITIONS
You define a constructor the same way that you define any other member
function, except for two points:
7.1
constructor
07_CH07.fm Page 258 Wednesday, August 13, 2003 12:58 PM
Constructors 259
1. A constructor must have the same name as the class. For example, if the class is named
BankAccount
, then any constructor for this class must be named
BankAccount
.
2. A constructor definition cannot return a value. Moreover, no type, not even
void
,
can be given at the start of the function declaration or in the function header.
For example, suppose we wanted to add a constructor for initializing the month and
day for objects of type
DayOfYear
, which we gave in Display 6.4 and redefine in what
follows so it includes a constructor. (We have omitted some of the comments to save
space, but they should be included in an actual program.)
class DayOfYear
{
public:
DayOfYear(int monthValue, int dayValue);
//Initializes the month and day to arguments.
void input(
);
void output(
);
void set(int newMonth, int newDay);
void set(int newMonth);
int getMonthNumber(
);
int getDay(
);
private:
int month;
int day;
};
Notice that the constructor is named
DayOfYear
, which is the name of the class.
Also notice that the declaration (prototype) for the constructor
DayOfYear
does not
start with
void
or any other type name. Finally, notice that the constructor is placed in
the public section of the class definition. Normally, you should make your constructors
public member functions. If you were to make all your constructors private members,
then you would not be able to declare any objects of that class type, which would make
the class completely useless.
With the redefined class
DayOfYear
, two objects of type
DayOfYear
can be declared
and initialized as follows:
DayOfYear date1(7, 4), date2(5, 5);
Assuming that the definition of the constructor performs the initializing action that we
promised, the above declaration will declare the object
date1
, set the value of
date1.month
to
7
, and set the value of
date1.day
to
4
. Thus, the object
date1
is initial-
ized so that it represents the date July 4. Similarly,
date2
is initialized so that it repre-
sents the date May 5. What happens is that the object
date1
is declared, and then the
constructor
DayOfYear
is called with the two arguments
7
and
4
. Similarly,
date2
is
declared, and then the constructor
DayOfYear
is called with the arguments
5
and
5
. The
Constructor
07_CH07.fm Page 259 Wednesday, August 13, 2003 12:58 PM
260 Constructors and Other Tools
result is conceptually equivalent to the following (although you cannot write it this way
in C++):
DayOfYear date1, date2; //PROBLEMS BUT FIXABLE
date1.DayOfYear(7, 4); //VERY ILLEGAL
date2.DayOfYear(5, 5); //VERY ILLEGAL
As the comments indicate, you cannot place the above three lines in your program. The
first line can be made to be acceptable, but the two calls to the constructor
DayOfYear
are illegal. A constructor cannot be called in the same way as an ordinary member func-
tion is called. Still, it is clear what we want to happen when we write the above three
lines, and that happens automatically when you declare the objects
date1
and
date2
as
follows:
DayOfYear date1(7, 4), date2(5, 5);
The definition of a constructor is given in the same way as any other member func-
tion. For example, if you revise the definition of the class
DayOfYear
by adding the con-
structor just described, you need to also add a definition of the constructor, which
might be as follows:
DayOfYear::DayOfYear(int monthValue, int dayValue)
{
month = monthValue;
day = dayValue;
}
Since the class and the constructor function have the same name, the name
DayOfYear
occurs twice in the function heading; the
DayOfYear
before the scope resolution opera-
tor
::
is the name of the class, and the
DayOfYear
after the scope resolution operator is
the name of the constructor function. Also notice that no return type is specified in the
heading of the constructor definition, not even the type
void
. Aside from these points,
a constructor can be defined in the same way as an ordinary member function.
As we just illustrated, a constructor can be defined just like any other member func-
tion. However, there is an alternative way of defining constructors that is preferable to
use. The previous definition of the constructor
DayOfYear
is completely equivalent to
the following version:
C
ONSTRUCTOR
A cc
cc
oo
oo
nn
nn
ss
ss
tt
tt
rr
rr
uu
uu
cc
cc
tt
tt
oo
oo
rr
rr
is a member function of a class that has the same name as the class. A constructor is
called automatically when an object of the class is declared. Constructors are used to initialize
objects. A constructor must have the same name as the class of which it is a member.
07_CH07.fm Page 260 Wednesday, August 13, 2003 12:58 PM
Constructors 261
DayOfYear::DayOfYear(int monthValue, int dayValue)
: month(monthValue), day(dayValue)
{/*Body intentionally empty*/}
The new element shown on the second line of the constructor definition is called the
initialization section
. As this example shows, the initialization section goes after the
parenthesis that ends the parameter list and before the opening brace of the function
body. The initialization section consists of a colon followed by a list of some or all the
member variables separated by commas. Each member variable is followed by its ini-
tializing value in parentheses. Notice that the initializing values can be given in terms of
the constructor parameters.
The function body in a constructor definition with an initialization section need not
be empty as in the above example. For example, the following improved version of the
constructor definition checks to see that the arguments are appropriate:
DayOfYear::DayOfYear(int monthValue, int dayValue)
: month(monthValue), day(dayValue)
{
if ((month < 1) || (month > 12))
{
cout << "Illegal month value!\n";
exit(1);
}
if ((day < 1) || (day > 31))
{
cout << "Illegal day value!\n";
exit(1);
}
}
You can overload a constructor name like
DayOfYear::DayOfYear
, just as you can
overload any other member function name. In fact, constructors usually are overloaded
so that objects can be initialized in more than one way. For example, in Display 7.1 we
have redefined the class
DayOfYear
so that it has three versions of its constructor. This
redefinition overloads the constructor name
DayOfYear
so that it can have two argu-
ments (as we just discussed), one argument, or no arguments.
Notice that in Display 7.1, two constructors call the member function
testDate to
check that their initialized values are appropriate. The member function
testDate is
private since it is only intended to be used by other member functions and so is part of
the hidden implementation details.
We have omitted the member function
set from this revised class definition of
DayOfYear. Once you have a good set of constructor definitions, there is no need for
any other member functions to set the member variables of the class. You can use the
constructor
DayOfYear in Display 7.1 for the same purposes that you would use the
initialization
section
07_CH07.fm Page 261 Wednesday, August 13, 2003 12:58 PM
262 Constructors and Other Tools
Display 7.1 Class with Constructors
(part 1 of 2)
1 #include <iostream>
2 #include <cstdlib> //for exit
3 using namespace std;
4 class DayOfYear
5 {
6 public:
7 DayOfYear(int monthValue, int dayValue);
8 //Initializes the month and day to arguments.
9 DayOfYear(int monthValue);
10 //Initializes the date to the first of the given month.
11 DayOfYear( );
12 //Initializes the date to January 1.
13 void input(
);
14 void output(
);
15 int getMonthNumber(
);
16 //Returns 1 for January, 2 for February, etc.
17 int getDay(
);
18 private:
19 int month;
20 int day;
21 void testDate( );
22 };
23 int main(
)
24 {
25 DayOfYear date1(2, 21), date2(5), date3;
26 cout << "Initialized dates:\n";
27 date1.output( ); cout << endl;
28 date2.output( ); cout << endl;
29 date3.output( ); cout << endl;
30 date1 = DayOfYear(10, 31);
31 cout << "date1 reset to the following:\n";
32 date1.output( ); cout << endl;
33 return 0;
34 }
35
36 DayOfYear::DayOfYear(int monthValue, int dayValue)
37 : month(monthValue), day(dayValue)
38 {
39 testDate( );
40 }
This definition of DayOfYear is an improved version
of the class
DayOfYear given in Display 6.4.
default constructor
This causes a call to the default
constructor. Notice that there are
no parentheses.
an explicit call to the constructor
DayOfYear::DayOfYear
07_CH07.fm Page 262 Wednesday, August 13, 2003 12:58 PM
Constructors 263
Pitfall
member function set (which we included in the old version of the class shown in
Display 6.4).
C
ONSTRUCTORS
WITH
N
O
A
RGUMENTS
It is important to remember not to use any parentheses when you declare a class variable and
want the constructor invoked with no arguments. For example, consider the following line from
Display 7.1:
DayOfYear date1(2, 21), date2(5), date3;
Display 7.1 Class with Constructors
(part 2 of 2)
41 DayOfYear::DayOfYear(int monthValue) : month(monthValue), day(1)
42 {
43 testDate( );
44 }
45 DayOfYear::DayOfYear( ) : month(1), day(1)
46 {/*Body intentionally empty.*/}
47 //uses iostream and cstdlib:
48 void DayOfYear::testDate( )
49 {
50 if ((month < 1) || (month > 12))
51 {
52 cout << "Illegal month value!\n";
53 exit(1);
54 }
55 if ((day < 1) || (day > 31))
56 {
57 cout << "Illegal day value!\n";
58 exit(1);
59 }
60 }
S
AMPLE
D
IALOGUE
Initialized dates:
February 21
May 1
January 1
date1 reset to the following:
October 31
<
Definitions of the other member
functions are the same as in Display 6.4.
>
07_CH07.fm Page 263 Wednesday, August 13, 2003 12:58 PM
264 Constructors and Other Tools
The object date1 is initialized by the constructor that takes two arguments, the object date2 is
initialized by the constructor that takes one argument, and the object
date3 is initialized by the
constructor that takes no arguments.
It is tempting to think that empty parentheses should be used when declaring a variable for which
you want the constructor with no arguments invoked, but there is a reason why this is not done.
Consider the following, which seems like it should declare the variable
date3 and invoke the con-
structor with no arguments:
DayOfYear date3( );//PROBLEM! Not what you might think it is.
The problem with this is that although you may mean it as a declaration and constructor invoca-
tion, the compiler sees it as a declaration (prototype) of a function named
date3 that has no
parameters and that returns a value of type
DayOfYear. Since a function named date3 that has
no parameters and that returns a value of type
DayOfYear is perfectly legal, this notation always
has that meaning. A different notation (without parentheses) is used when you want to invoke a
constructor with no arguments.
C
ALLING
A
C
ONSTRUCTOR
A constructor is called automatically when an object is declared, but you must give the argu-
ments for the constructor when you declare the object. A constructor can also be called explicitly,
but the syntax is different from what is used for ordinary member functions.
S
YNTAX
FOR
AN
O
BJECT
D
ECLARATION
W
HEN
Y
OU
H
AVE
C
ONSTRUCTORS
Class_Name
Variable_Name(Arguments_for_Constructor);
E
XAMPLE
DayOfYear holiday(7, 4);
S
YNTAX
FOR
AN
E
XPLICIT
C
ONSTRUCTOR
C
ALL
Variable
=
Constructor_Name
(
Arguments_For_Constructor
);
E
XAMPLE
holiday = DayOfyear(10, 31);
A constructor must have the same name as the class of which it is a member. Thus, in the above
syntax descriptions,
Class_Name
and
Constructor_Name
are the same identifier.
07_CH07.fm Page 264 Wednesday, August 13, 2003 12:58 PM