You are on page 1of 41

13

One Ring to rule them all,


One Ring to nd them,
One Ring to bring them all
and in the darkness bind
them.
John Ronald Reuel Tolkien

The silence often of pure


innocence
Persuades when speaking
fails.

ObjectOriented
Programming:
Polymorphism
OBJECTIVES
In this chapter you will learn:

William Shakespeare

General propositions do not


decide concrete cases.

Oliver Wendell Holmes

A philosopher of imposing
stature doesnt think in a
vacuum. Even his most
abstract ideas are, to some
extent, conditioned by what
is or is not known in the time
when he lives.
Alfred North Whitehead

What polymorphism is, how it makes programming


more convenient, and how it makes systems more
extensible and maintainable.
To declare and use virtual functions to effect
polymorphism.
The distinction between abstract and concrete classes.
To declare pure virtual functions to create abstract
classes.
How to use run-time type information (RTTI) with
downcasting, dynamic_cast, typeid and
type_info.
How C++ implements virtual functions and dynamic
binding under the hood.
How to use virtual destructors to ensure that all
appropriate destructors run on an object.

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Chapter 13 Object-Oriented Programming: Polymorphism

Self-Review Exercises
13.1

Fill in the blanks in each of the following statements:


a) Treating a base-class object as a(n)
can cause errors.
ANS: derived-class object.
b) Polymorphism helps eliminate
logic.
ANS: switch.
c) If a class contains at least one pure virtual function, it is a(n)
class.
ANS: abstract.
classes.
d) Classes from which objects can be instantiated are called
ANS: concrete.
e) Operator
can be used to downcast base-class pointers safely.
ANS: dynamic_cast.
f) Operator typeid returns a reference to a(n)
object.
ANS: type_info.
g)
involves using a base-class pointer or reference to invoke virtual functions
on base-class and derived-class objects.
ANS: Polymorphism.
h) Overridable functions are declared using keyword
.
ANS: virtual.
i) Casting a base-class pointer to a derived-class pointer is called
.
ANS: downcasting.

13.2

State whether each of the following is true or false. If false, explain why.
a) All virtual functions in an abstract base class must be declared as pure virtual functions.
ANS: False. An abstract base class can include virtual functions with implementations.
b) Referring to a derived-class object with a base-class handle is dangerous.
ANS: False. Referring to a base-class object with a derived-class handle is dangerous.
c) A class is made abstract by declaring that class virtual.
ANS: False. Classes are never declared virtual. Rather, a class is made abstract by including
at least one pure virtual function in the class.
d) If a base class declares a pure virtual function, a derived class must implement that
function to become a concrete class.
ANS: True.
e) Polymorphic programming can eliminate the need for switch logic.
ANS: True.

Exercises
13.3 How is it that polymorphism enables you to program in the general rather than in the
specific? Discuss the key advantages of programming in the general.
ANS: Polymorphism enables the programmer to concentrate on the common operations
that are applied to objects of all the classes in a hierarchy. The general processing capabilities can be separated from any code that is specific to each class. Those general
portions of the code can accommodate new classes without modification. In some
polymorphic applications, only the code that creates the objects needs to be modified
to extend the system with new classes.

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises

13.4 Discuss the problems of programming with switch logic. Explain why polymorphism can
be an effective alternative to using switch logic.
ANS: The main problems with programming using switch logic are extensibility and program maintainability. A program containing many switch statements is difficult to
modify. A programmer will need to add or remove cases from many, possibly all,
switch statements in the program as the types of objects in the program change. The
polymorphic approach eliminates these issues, as new types can be added to a program with relative ease. Only the part of the program that creates objects needs to be
aware of the newly added types. [Note: switch logic includes ifelse statements
which are more flexible than the switch statement.]
13.5 Distinguish between inheriting interface and inheriting implementation. How do inheritance hierarchies designed for inheriting interface differ from those designed for inheriting implementation?
ANS: When a class inherits implementation, it inherits previously defined functionality
from another class. When a class inherits interface, it inherits the definition of what
the interface to the new class type should be. The implementation is then provided
by the programmer defining the new class type. Inheritance hierarchies designed for
inheriting implementation are used to reduce the amount of new code that is being
written. Such hierarchies are used to facilitate software reusability. Inheritance hierarchies designed for inheriting interface are used to write programs that perform generic processing of many class types. Such hierarchies are commonly used to facilitate
software extensibility (i.e., new types can be added to the hierarchy without changing
the generic processing capabilities of the program.)
13.6 What are virtual functions? Describe a circumstance in which virtual functions would
be appropriate.
ANS: virtual functions are functions with the same function prototype that are defined
throughout a class hierarchy. At least the base class occurrence of the function is preceded by the keyword virtual. Programmers use virtual function to enable generic
processing of an entire class hierarchy of objects through a base-class pointer. If the
program invokes a virtual function through a base-class pointer to a derived-class
object, the program will choose the correct derived-class function dynamically (i.e.,
at execution time) based on the object typenot the pointer type. For example, in a
shape hierarchy, all shapes can be drawn. If all shapes are derived from a base class
Shape which contains a virtual draw function, then generic processing of the hierarchy can be performed by calling every shapes draw generically through a base class
Shape pointer.
13.7 Distinguish between static binding and dynamic binding. Explain the use of virtual functions and the vtable in dynamic binding.
ANS: Static binding is performed at compile-time when a function is called via a specific
object or via a pointer to an object. Dynamic binding is performed at run-time when
a virtual function is called via a base-class pointer to a derived-class object (the object can be of any derived class). The virtual functions table (vtable) is used at runtime to enable the proper function to be called for the object to which the base-class
pointer points. Each class containing virtual functions has its own vtable that
specifies where the virtual functions for that class are located. Every object of a class
with virtual functions contains a hidden pointer to the classs vtable. When a virtual function is called via a base-class pointer, the hidden pointer is dereferenced to
locate the vtable, then the vtable is searched for the proper function call.

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Chapter 13 Object-Oriented Programming: Polymorphism

13.8

Distinguish between virtual functions and pure virtual functions.

ANS: A virtual function must have a definition in the class in which it is declared. A pure

virtual function does not provide a definition. A pure virtual function is appropriate when it does not make sense to provide an implementation for a function in a
base class (i.e., some additional derived-class-specific data is required to implement
the function in a meaningful manner). Classes derived directly from the abstract class
must provide definitions for the inherited pure virtual functions to become a concrete class; otherwise, the derived class becomes an abstract class as well.

13.9 Suggest one or more levels of abstract base classes for the Shape hierarchy discussed in this
chapter and shown in Fig. 12.3. (The first level is Shape, and the second level consists of the classes
TwoDimensionalShape and ThreeDimensionalShape.)
ANS: In the Shape hierarchy, class Shape could be an abstract base class. In the second level
of the hierarchy, TwoDimensionalShape and ThreeDimensionalShape could also be
abstract base classes, as defining a function such as draw does not make sense for either a generic two-dimensional shape or a generic three-dimensional shape.
13.10 How does polymorphism promote extensibility?
ANS: Polymorphism makes programs more extensible by making all function calls generic.
When a new class type with the appropriate virtual functions is added to the hierarchy, no changes need to be made to the generic function calls. Only client code that
instantiates new objects must be modified to accommodate new types.
13.11 You have been asked to develop a flight simulator that will have elaborate graphical outputs.
Explain why polymorphic programming would be especially effective for a problem of this nature.
ANS: A flight simulator most likely will involve displaying a number of different types of
aircraft and objects on the screen. Suppose a programmer creates an abstract base class
named FlightSimulatorObject with a pure virtual function draw. Derived classes
could be created to represent the various on-screen elements, such as Airplanes, Helicopters and Airports. Each derived class would define draw so that it displays an
appropriate image for that element. Polymorphism would allow the programmer to
display all the on-screen elements in the flight simulator in a generic manner (i.e., the
program can invoke function draw off base class FlightSimulatorObject pointers or
references to derived-class objects. The flight simulator code responsible for displaying the elements on the screen would not need to worry about the details of drawing
each type of element or about incorporating new types of on-screen elements. Each
derived class handles the drawing details, and only the code that creates new objects
would need to be modified to accommodate new types.
13.12 (Payroll System Modication) Modify the payroll system of Figs. 13.1313.23 to include
private data member birthDate in class Employee. Use class Date from Figs. 11.1211.13 to represent an employees birthday. Assume that payroll is processed once per month. Create a vector of
Employee references to store the various employee objects. In a loop, calculate the payroll for each
Employee (polymorphically), and add a $100.00 bonus to the persons payroll amount if the current
month is the month in which the Employees birthday occurs.
ANS:

1
2
3
4
5

// Exercise 13.12 Solution: Date.h


// Date class definition.
#ifndef DATE_H
#define DATE_H

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#include <iostream>
using std::ostream;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

// Exercise 13.12 Solution: Date.cpp


// Date class member-function definitions.
#include <iostream>
#include "Date.h"

class Date
{
friend ostream &operator<<( ostream &, const Date & );
public:
Date( int m = 1, int d = 1, int y = 1900 ); // default constructor
void setDate( int, int, int ); // set month, day, year
Date &operator++(); // prefix increment operator
Date operator++( int ); // postfix increment operator
const Date &operator+=( int ); // add days, modify object
bool leapYear( int ) const; // is date in a leap year?
bool endOfMonth( int ) const; // is date at the end of month?
int getMonth() const; // return the month of the date
private:
int month;
int day;
int year;
static const int days[]; // array of days per month
void helpIncrement(); // utility function for incrementing date
}; // end class Date
#endif

// initialize static member at file scope; one classwide copy


const int Date::days[] =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// Date constructor
Date::Date( int m, int d, int y )
{
setDate( m, d, y );
} // end Date constructor
// set month, day and year
void Date::setDate( int mm, int dd, int yy )
{
month = ( mm >= 1 && mm <= 12 ) ? mm : 1;
year = ( yy >= 1900 && yy <= 2100 ) ? yy : 1900;
// test for a leap year
if ( month == 2 && leapYear( year ) )
day = ( dd >= 1 && dd <= 29 ) ? dd : 1;
else
day = ( dd >= 1 && dd <= days[ month ] ) ? dd : 1;
} // end function setDate

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

6
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

Chapter 13 Object-Oriented Programming: Polymorphism

// overloaded prefix increment operator


Date &Date::operator++()
{
helpIncrement(); // increment date
return *this; // reference return to create an lvalue
} // end function operator++
// overloaded postfix increment operator; note that the
// dummy integer parameter does not have a parameter name
Date Date::operator++( int )
{
Date temp = *this; // hold current state of object
helpIncrement();
// return unincremented, saved, temporary object
return temp; // value return; not a reference return
} // end function operator++
// add specified number of days to date
const Date &Date::operator+=( int additionalDays )
{
for ( int i = 0; i < additionalDays; i++ )
helpIncrement();
return *this; // enables cascading
} // end function operator+=
// if the year is a leap year, return true; otherwise, return false
bool Date::leapYear( int testYear ) const
{
if ( testYear % 400 == 0 ||
( testYear % 100 != 0 && testYear % 4 == 0 ) )
return true; // a leap year
else
return false; // not a leap year
} // end function leapYear
// return the month of the date
int Date::getMonth() const
{
return month;
} // end function getMonth
// determine whether the day is the last day of the month
bool Date::endOfMonth( int testDay ) const
{
if ( month == 2 && leapYear( year ) )
return testDay == 29; // last day of Feb. in leap year
else
return testDay == days[ month ];
} // end function endOfMonth
// function to help increment the date

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

void Date::helpIncrement()
{
// day is not end of month
if ( !endOfMonth( day ) )
day++; // increment day
else
if ( month < 12 ) // day is end
{
month++; // increment month
day = 1; // first day of new
} // end if
else // last day of year
{
year++; // increment year
month = 1; // first month of
day = 1; // first day of new
} // end else
} // end function helpIncrement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

// Exercise 13.12 Solution: Employee.h


// Employee abstract base class.
#ifndef EMPLOYEE_H
#define EMPLOYEE_H

of month and month < 12


month

new year
month

// overloaded output operator


ostream &operator<<( ostream &output, const Date &d )
{
static char *monthName[ 13 ] = { "", "January", "February",
"March", "April", "May", "June", "July", "August",
"September", "October", "November", "December" };
output << monthName[ d.month ] << ' ' << d.day << ", " << d.year;
return output; // enables cascading
} // end function operator<<

#include <string> // C++ standard string class


using std::string;
#include "Date.h" // Date class definition
class Employee
{
public:
Employee( const string &, const string &, const string &,
int, int, int );
void setFirstName( const string & ); // set first name
string getFirstName() const; // return first name
void setLastName( const string & ); // set last name
string getLastName() const; // return last name
void setSocialSecurityNumber( const string & ); // set SSN
string getSocialSecurityNumber() const; // return SSN

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

8
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

Chapter 13 Object-Oriented Programming: Polymorphism

void setBirthDate( int, int, int ); // set birthday


Date getBirthDate() const; // return birthday
// pure virtual function makes Employee abstract base class
virtual double earnings() const = 0; // pure virtual
virtual void print() const; // virtual
private:
string firstName;
string lastName;
string socialSecurityNumber;
Date birthDate; // the Employee's birthday
}; // end class Employee
#endif // EMPLOYEE_H

// Exercise 13.12 Solution: Employee.cpp


// Abstract-base-class Employee member-function definitions.
// Note: No definitions are given for pure virtual functions.
#include <iostream>
using std::cout;
#include "Employee.h" // Employee class definition
// constructor
Employee::Employee( const string &first, const string &last,
const string &ssn, int month, int day, int year )
: firstName( first ), lastName( last ), socialSecurityNumber( ssn ),
birthDate( month, day, year )
{
// empty body
} // end Employee constructor
// set first name
void Employee::setFirstName( const string &first )
{
firstName = first;
} // end function setFirstName
// return first name
string Employee::getFirstName() const
{
return firstName;
} // end function getFirstName
// set last name
void Employee::setLastName( const string &last )
{
lastName = last;
} // end function setLastName
// return last name
string Employee::getLastName() const

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

// Exercise 13.12 Solution: SalariedEmployee.h


// SalariedEmployee class derived from Employee.
#ifndef SALARIED_H
#define SALARIED_H

return lastName;
} // end function getLastName
// set social security number
void Employee::setSocialSecurityNumber( const string &ssn )
{
socialSecurityNumber = ssn; // should validate
} // end function setSocialSecurityNumber
// return social security number
string Employee::getSocialSecurityNumber() const
{
return socialSecurityNumber;
} // end function getSocialSecurityNumber
// set birthday
void Employee::setBirthDate( int month, int day, int year )
{
birthDate.setDate( month, day, year );
} // end function setBirthDate
// return birthday
Date Employee::getBirthDate() const
{
return birthDate;
} // end function getBirthDate
// print Employee's information (virtual, but not pure virtual)
void Employee::print() const
{
cout << getFirstName() << ' ' << getLastName()
<< "\nbirthday: " << getBirthDate()
<< "\nsocial security number: " << getSocialSecurityNumber();
} // end function print

#include "Employee.h" // Employee class definition


class SalariedEmployee : public Employee
{
public:
SalariedEmployee( const string &, const string &,
const string &, int, int, int, double = 0.0 );
void setWeeklySalary( double ); // set weekly salary
double getWeeklySalary() const; // return weekly salary
// keyword virtual signals intent to override

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

10

Chapter 13 Object-Oriented Programming: Polymorphism

18
19
20
21
22
23
24

virtual double earnings() const; // calculate earnings


virtual void print() const; // print SalariedEmployee object
private:
double weeklySalary; // salary per week
}; // end class SalariedEmployee

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

// Exercise 13.12 Solution: SalariedEmployee.cpp


// SalariedEmployee class member-function definitions.
#include <iostream>
using std::cout;

#endif // SALARIED_H

#include "SalariedEmployee.h" // SalariedEmployee class definition


// constructor
SalariedEmployee::SalariedEmployee( const string &first,
const string &last, const string &ssn, int month, int day, int year,
double salary )
: Employee( first, last, ssn, month, day, year )
{
setWeeklySalary( salary );
} // end SalariedEmployee constructor
// set salary
void SalariedEmployee::setWeeklySalary( double salary )
{
weeklySalary = ( salary < 0.0 ) ? 0.0 : salary;
} // end function setWeeklySalary
// return salary
double SalariedEmployee::getWeeklySalary() const
{
return weeklySalary;
} // end function getWeeklySalary
// calculate earnings;
// override pure virtual function earnings in Employee
double SalariedEmployee::earnings() const
{
return getWeeklySalary();
} // end function earnings
// print SalariedEmployee's information
void SalariedEmployee::print() const
{
cout << "salaried employee: ";
Employee::print(); // reuse abstract base-class print function
cout << "\nweekly salary: " << getWeeklySalary();
} // end function print

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

// Exercise 13.12 Solution: HourlyEmployee.h


// HourlyEmployee class definition.
#ifndef HOURLY_H
#define HOURLY_H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

// Exercise 13.12 Solution: HourlyEmployee.cpp


// HourlyEmployee class member-function definitions.
#include <iostream>
using std::cout;

11

#include "Employee.h" // Employee class definition


class HourlyEmployee : public Employee
{
public:
HourlyEmployee( const string &, const string &,
const string &, int, int, int, double = 0.0, double = 0.0 );
void setWage( double ); // set hourly wage
double getWage() const; // return hourly wage
void setHours( double ); // set hours worked
double getHours() const; // return hours worked
// keyword virtual signals intent to override
virtual double earnings() const; // calculate earnings
virtual void print() const; // print HourlyEmployee object
private:
double wage; // wage per hour
double hours; // hours worked for week
}; // end class HourlyEmployee
#endif // HOURLY_H

#include "HourlyEmployee.h" // HourlyEmployee class definition


// constructor
HourlyEmployee::HourlyEmployee( const string &first, const string &last,
const string &ssn, int month, int day, int year,
double hourlyWage, double hoursWorked )
: Employee( first, last, ssn, month, day, year )
{
setWage( hourlyWage ); // validate hourly wage
setHours( hoursWorked ); // validate hours worked
} // end HourlyEmployee constructor
// set wage
void HourlyEmployee::setWage( double hourlyWage )
{
wage = ( hourlyWage < 0.0 ? 0.0 : hourlyWage );
} // end function setWage
// return wage

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

12

Chapter 13 Object-Oriented Programming: Polymorphism

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

double HourlyEmployee::getWage() const


{
return wage;
} // end function getWage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

// Exercise 13.12 Solution: CommissionEmployee.h


// CommissionEmployee class derived from Employee.
#ifndef COMMISSION_H
#define COMMISSION_H

// set hours worked


void HourlyEmployee::setHours( double hoursWorked )
{
hours = ( ( ( hoursWorked >= 0.0 ) && ( hoursWorked <= 168.0 ) ) ?
hoursWorked : 0.0 );
} // end function setHours
// return hours worked
double HourlyEmployee::getHours() const
{
return hours;
} // end function getHours
// calculate earnings;
// override pure virtual function earnings in Employee
double HourlyEmployee::earnings() const
{
if ( getHours() <= 40 ) // no overtime
return getWage() * getHours();
else
return 40 * getWage() + ( ( getHours() - 40 ) * getWage() * 1.5 );
} // end function earnings
// print HourlyEmployee's information
void HourlyEmployee::print() const
{
cout << "hourly employee: ";
Employee::print(); // code reuse
cout << "\nhourly wage: " << getWage() <<
"; hours worked: " << getHours();
} // end function print

#include "Employee.h" // Employee class definition


class CommissionEmployee : public Employee
{
public:
CommissionEmployee( const string &, const string &,
const string &, int, int, int, double = 0.0, double = 0.0 );
void setCommissionRate( double ); // set commission rate
double getCommissionRate() const; // return commission rate

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

13

void setGrossSales( double ); // set gross sales amount


double getGrossSales() const; // return gross sales amount
// keyword virtual signals intent to override
virtual double earnings() const; // calculate earnings
virtual void print() const; // print CommissionEmployee object
private:
double grossSales; // gross weekly sales
double commissionRate; // commission percentage
}; // end class CommissionEmployee
#endif // COMMISSION_H

// Exercise 13.12 Solution: CommissionEmployee.cpp


// CommissionEmployee class member-function definitions.
#include <iostream>
using std::cout;
#include "CommissionEmployee.h" // CommissionEmployee class definition
// constructor
CommissionEmployee::CommissionEmployee( const string &first,
const string &last, const string &ssn, int month, int day, int year,
double sales, double rate )
: Employee( first, last, ssn, month, day, year )
{
setGrossSales( sales );
setCommissionRate( rate );
} // end CommissionEmployee constructor
// set commission rate
void CommissionEmployee::setCommissionRate( double rate )
{
commissionRate = ( ( rate > 0.0 && rate < 1.0 ) ? rate : 0.0 );
} // end function setCommissionRate
// return commission rate
double CommissionEmployee::getCommissionRate() const
{
return commissionRate;
} // end function getCommissionRate
// set gross sales amount
void CommissionEmployee::setGrossSales( double sales )
{
grossSales = ( ( sales < 0.0 ) ? 0.0 : sales );
} // end function setGrossSales
// return gross sales amount
double CommissionEmployee::getGrossSales() const
{
return grossSales;
} // end function getGrossSales

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

14
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

Chapter 13 Object-Oriented Programming: Polymorphism

// calculate earnings;
// override pure virtual function earnings in Employee
double CommissionEmployee::earnings() const
{
return getCommissionRate() * getGrossSales();
} // end function earnings
// print CommissionEmployee's information
void CommissionEmployee::print() const
{
cout << "commission employee: ";
Employee::print(); // code reuse
cout << "\ngross sales: " << getGrossSales()
<< "; commission rate: " << getCommissionRate();
} // end function print

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

// Exercise 13.12 Solution: BasePlusCommissionEmployee.h


// BasePlusCommissionEmployee class derived from Employee.
#ifndef BASEPLUS_H
#define BASEPLUS_H

1
2
3
4
5
6
7
8

// Exercise 13.12 Solution: BasePlusCommissionEmployee.cpp


// BasePlusCommissionEmployee member-function definitions.
#include <iostream>
using std::cout;

#include "CommissionEmployee.h" // CommissionEmployee class definition


class BasePlusCommissionEmployee : public CommissionEmployee
{
public:
BasePlusCommissionEmployee( const string &, const string &,
const string &, int, int, int, double = 0.0, double = 0.0,
double = 0.0 );
void setBaseSalary( double ); // set base salary
double getBaseSalary() const; // return base salary
// keyword virtual signals intent to override
virtual double earnings() const; // calculate earnings
virtual void print() const; // print BasePlusCommissionEmployee object
private:
double baseSalary; // base salary per week
}; // end class BasePlusCommissionEmployee
#endif // BASEPLUS_H

// BasePlusCommissionEmployee class definition


#include "BasePlusCommissionEmployee.h"

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises

15

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

// constructor
BasePlusCommissionEmployee::BasePlusCommissionEmployee(
const string &first, const string &last, const string &ssn,
int month, int day, int year, double sales,
double rate, double salary )
: CommissionEmployee( first, last, ssn, month, day, year, sales, rate )
{
setBaseSalary( salary ); // validate and store base salary
} // end BasePlusCommissionEmployee constructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

// Exercise 13.12 Solution: ex13_12.cpp


// Processing Employee derived-class objects polymorphically.
#include <iostream>
using std::cout;
using std::endl;
using std::fixed;

// set base salary


void BasePlusCommissionEmployee::setBaseSalary( double salary )
{
baseSalary = ( ( salary < 0.0 ) ? 0.0 : salary );
} // end function setBaseSalary
// return base salary
double BasePlusCommissionEmployee::getBaseSalary() const
{
return baseSalary;
} // end function getBaseSalary
// calculate earnings;
// override pure virtual function earnings in Employee
double BasePlusCommissionEmployee::earnings() const
{
return getBaseSalary() + CommissionEmployee::earnings();
} // end function earnings
// print BasePlusCommissionEmployee's information
void BasePlusCommissionEmployee::print() const
{
cout << "base-salaried ";
CommissionEmployee::print(); // code reuse
cout << "; base salary: " << getBaseSalary();
} // end function print

#include <iomanip>
using std::setprecision;
#include <vector>
using std::vector;
#include <typeinfo>
#include <ctime>

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

Chapter 13 Object-Oriented Programming: Polymorphism

using
using
using
using

std::time_t;
std::time;
std::localtime;
std::strftime;

#include <cstdlib>
using std::atoi;
// include definitions of classes in Employee hierarchy
#include "Employee.h"
#include "SalariedEmployee.h"
#include "HourlyEmployee.h"
#include "CommissionEmployee.h"
#include "BasePlusCommissionEmployee.h"
int determineMonth(); // prototype of function that returns current month
int main()
{
// set floating-point output formatting
cout << fixed << setprecision( 2 );
// create vector of four base-class pointers
vector < Employee * > employees( 4 );
// initialize vector with Employees
employees[ 0 ] = new SalariedEmployee(
"John", "Smith", "111-11-1111", 6, 15, 1944, 800 );
employees[ 1 ] = new HourlyEmployee(
"Karen", "Price", "222-22-2222", 12, 29, 1960, 16.75, 40 );
employees[ 2 ] = new CommissionEmployee(
"Sue", "Jones", "333-33-3333", 9, 8, 1954, 10000, .06 );
employees[ 3 ] = new BasePlusCommissionEmployee(
"Bob", "Lewis", "444-44-4444", 3, 2, 1965, 5000, .04, 300 );
int month = determineMonth();
cout << "Employees processed polymorphically via dynamic binding:\n\n";
for ( size_t i = 0; i < employees.size(); i++ )
{
employees[ i ]->print(); // output employee information
cout << endl;
// downcast pointer
BasePlusCommissionEmployee *derivedPtr =
dynamic_cast < BasePlusCommissionEmployee * >
( employees[ i ] );
// determine whether element points to base-salaried
// commission employee
if ( derivedPtr != 0 ) // 0 if not a BasePlusCommissionEmployee
{
double oldBaseSalary = derivedPtr->getBaseSalary();

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

17

cout << "old base salary: $" << oldBaseSalary << endl;
derivedPtr->setBaseSalary( 1.10 * oldBaseSalary );
cout << "new base salary with 10% increase is: $"
<< derivedPtr->getBaseSalary() << endl;
} // end if
// get current employee's birthday
Date birthday = employees[ i ]->getBirthDate();
// if current month is employee's birthday month, add $100 to salary
if ( birthday.getMonth() == month )
cout << "HAPPY BIRTHDAY!\nearned $"
<< ( employees[ i ]->earnings() + 100.0 ) << endl;
else
cout << "earned $" << employees[ i ]->earnings() << endl;
cout << endl;
} // end for
// release objects pointed to by vectors elements
for ( size_t j = 0; j < employees.size(); j++ )
{
// output class name
cout << "deleting object of "
<< typeid( *employees[ j ] ).name() << endl;
delete employees[ j ];
} // end for
return 0;
} // end main
// Determine the current month using standard library functions of ctime
int determineMonth()
{
time_t currentTime;
char monthString[ 3 ];
time( &currentTime );
strftime( monthString, 3, "%m", localtime( &currentTime ) );
return atoi( monthString );
} // end function determineMonth

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

18

Chapter 13 Object-Oriented Programming: Polymorphism

Employees processed polymorphically via dynamic binding:


salaried employee: John Smith
birthday: June 15, 1944
social security number: 111-11-1111
weekly salary: 800.00
earned $800.00
hourly employee: Karen Price
birthday: December 29, 1960
social security number: 222-22-2222
hourly wage: 16.75; hours worked: 40.00
HAPPY BIRTHDAY!
earned $770.00
commission employee: Sue Jones
birthday: September 8, 1954
social security number: 333-33-3333
gross sales: 10000.00; commission rate: 0.06
earned $600.00
base-salaried commission employee: Bob Lewis
birthday: March 2, 1965
social security number: 444-44-4444
gross sales: 5000.00; commission rate: 0.04; base salary: 300.00
old base salary: $300.00
new base salary with 10% increase is: $330.00
earned $530.00
deleting
deleting
deleting
deleting

object
object
object
object

of
of
of
of

class
class
class
class

SalariedEmployee
HourlyEmployee
CommissionEmployee
BasePlusCommissionEmployee

13.13 (Shape Hierarchy) Implement the Shape hierarchy designed in Exercise 12.7 (which is based
on the hierarchy in Fig. 12.3). Each TwoDimensionalShape should contain function getArea to calculate the area of the two-dimensional shape. Each ThreeDimensionalShape should have member
functions getArea and getVolume to calculate the surface area and volume of the three-dimensional
shape, respectively. Create a program that uses a vector of Shape pointers to objects of each concrete
class in the hierarchy. The program should print the object to which each vector element points.
Also, in the loop that processes all the shapes in the vector, determine whether each shape is a
TwoDimensionalShape or a ThreeDimensionalShape. If a shape is a TwoDimensionalShape, display its
area. If a shape is a ThreeDimensionalShape, display its area and volume.
ANS:

1
2
3
4
5
6
7
8

// Exercise 13.13 Solution: Shape.h


// Definition of base-class Shape
#ifndef SHAPE_H
#define SHAPE_H
#include <iostream>
using std::ostream;

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
9
10
11
12
13
14
15
16
17
18
19
20
21

class Shape {
friend ostream & operator<<( ostream &, Shape & );
public:
Shape( double = 0.0, double = 0.0 ); // default constructor
double getCenterX() const; // return x from coordinate pair
double getCenterY() const; // return y from coordinate pair
virtual void print() const = 0; // output Shape object
protected:
double xCenter; // x part of coordinate pair
double yCenter; // y part of coordinate pair
}; // end class Shape

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

// Exercise 13.13 Solution: Shape.cpp


// Member and friend definitions for class Shape

1
2
3
4
5
6
7

#endif

#include "Shape.h"
// default constructor
Shape::Shape( double x, double y )
{
xCenter = x;
yCenter = y;
} // end Shape constructor
// return x from coordinate pair
double Shape::getCenterX() const
{
return xCenter;
} // end function getCenterX
// return y from coordinate pair
double Shape::getCenterY() const
{
return yCenter;
} // end function getCenterY
// overloaded output operator
ostream & operator<<( ostream &out, Shape &s )
{
s.print();
return out;
} // end overloaded output operator function

// Exercise 13.13 Solution: TwoDimensionalShape.h


// Definition of class TwoDimensionalShape
#ifndef TWODIM_H
#define TWODIM_H
#include "Shape.h"

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

19

20

Chapter 13 Object-Oriented Programming: Polymorphism

8
9
10
11
12
13
14
15
16
17

class TwoDimensionalShape : public Shape


{
public:
// default constructor
TwoDimensionalShape( double x, double y ) : Shape( x, y ) { }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

// Exercise 13.13 Solution: ThreeDimensionalShape.h


// Definition of class ThreeDimensionalShape
#ifndef THREEDIM_H
#define THREEDIM_H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

// Exercise 13.13 Solution: Circle.h


// Definition of class Circle
#ifndef CIRCLE_H
#define CIRCLE_H

virtual double getArea() const = 0; // area of TwoDimensionalShape


}; // end class TwoDimensionalShape
#endif

#include "Shape.h"
class ThreeDimensionalShape : public Shape
{
public:
// default constructor
ThreeDimensionalShape( double x, double y ) : Shape( x, y ) { }
virtual double getArea() const = 0; // area of 3-dimensional shape
virtual double getVolume() const = 0; // volume of 3-dimensional shape
}; // end class ThreeDimensionalShape
#endif

#include "TwoDimensionalShape.h"
class Circle : public TwoDimensionalShape
{
public:
// default consturctor
Circle( double = 0.0, double = 0.0, double = 0.0 );
virtual double getRadius() const; // return radius
virtual double getArea() const; // return area
void print() const; // output Circle object
private:
double radius; // Circle's radius
}; // end class Circle
#endif

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

// Exercise 13.13 Solution: Circle.cpp


// Member-function definitions for class Circle
#include <iostream>
using std::cout;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

// Exercise 13.13 Solution: Square.h


// Definition of class Square
#ifndef SQUARE_H
#define SQUARE_H

#include "Circle.h"
// default constructor
Circle::Circle( double r, double x, double y )
: TwoDimensionalShape( x, y )
{
radius = ( ( r > 0.0 ) ? r : 0.0 );
} // end Circle constructor
// return radius of circle object
double Circle::getRadius() const
{
return radius;
} // end function getRadius
// return area of circle object
double Circle::getArea() const
{
return 3.14159 * radius * radius;
} // end function getArea
// output circle object
void Circle::print() const
{
cout << "Circle with radius " << radius << "; center at ("
<< xCenter << ", " << yCenter << ")";
} // end function print

#include "TwoDimensionalShape.h"
class Square : public TwoDimensionalShape
{
public:
// default constructor
Square( double = 0.0, double = 0.0, double = 0.0 );
virtual double getSideLength() const; // return lenght of sides
virtual double getArea() const; // return area of Square
void print() const; // output Square object
private:
double sideLength; // length of sides
}; // end class Square

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

21

22
20
21

Chapter 13 Object-Oriented Programming: Polymorphism

#endif

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

// Exercise 13.13 Solution: Square.cpp


// Member-function definitions for class Square
#include <iostream>
using std::cout;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// Exercise 13.13 Solution: Sphere.h


// Definition of class Sphere
#ifndef SPHERE_H
#define SPHERE_H

#include "Square.h"
// default constructor
Square::Square( double s, double x, double y )
: TwoDimensionalShape( x, y )
{
sideLength = ( ( s > 0.0 ) ? s : 0.0 );
} // end Square constructor
// return side of Square
double Square::getSideLength() const
{
return sideLength;
} // end function getSideLength
// return area of Square
double Square::getArea() const
{
return sideLength * sideLength;
} // end function getArea
// output Square object
void Square::print() const
{
cout << "Square with side length " << sideLength << "; center at ("
<< xCenter << ", " << yCenter << ")";
} // end function print

#include "ThreeDimensionalShape.h"
class Sphere : public ThreeDimensionalShape
{
public:
// default constructor
Sphere( double = 0.0, double = 0.0, double = 0.0 );
virtual double getArea() const; // return area of Sphere
virtual double getVolume() const; // return volume of Sphere

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
16
17
18
19
20
21
22

double getRadius() const; // return radius of Sphere


void print() const; // output Sphere object
private:
double radius; // radius of Sphere
}; // end class Sphere

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

// Exercise 13.13 Solution: Sphere.cpp


// Member-function definitions for class Sphere
#include <iostream>
using std::cout;

1
2
3
4
5

#endif

#include "Sphere.h"
// default constructor
Sphere::Sphere( double r, double x, double y )
: ThreeDimensionalShape( x, y )
{
radius = ( ( r > 0.0 ) ? r : 0.0 );
} // end Sphere constructor
// return area of Sphere
double Sphere::getArea() const
{
return 4.0 * 3.14159 * radius * radius;
} // end function getArea
// return volume of Sphere
double Sphere::getVolume() const
{
return ( 4.0 / 3.0 ) * 3.14159 * radius * radius * radius;
} // end function getVolume
// return radius of Sphere
double Sphere::getRadius() const
{
return radius;
} // end function getRadius
// output Sphere object
void Sphere::print() const
{
cout << "Sphere with radius " << radius << "; center at ("
<< xCenter << ", " << yCenter << ")";
} // end function print

// Exercise 13.13 Solution: Cube.h


// Definition of class Cube
#ifndef CUBE_H
#define CUBE_H

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

23

24

Chapter 13 Object-Oriented Programming: Polymorphism

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#include "ThreeDimensionalShape.h"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

// Exercise 13.13 Solution: Cube.cpp


// Member-function definitions for class Cube
#include <iostream>
using std::cout;

class Cube : public ThreeDimensionalShape


{
public:
// default constructor
Cube( double = 0.0, double = 0.0, double = 0.0 );
virtual double getArea() const; // return area of Cube object
virtual double getVolume() const; // return volume of Cube object
double getSideLength() const; // return length of sides
void print() const; // output Cube object
private:
double sideLength; // length of sides of Cube
}; // end class Cube
#endif

#include "Cube.h"
// default constructor
Cube::Cube( double s, double x, double y )
: ThreeDimensionalShape( x, y )
{
sideLength = ( ( s > 0.0 ) ? s : 0.0 );
} // end Cube constructor
// return area of Cube
double Cube::getArea() const
{
return 6 * sideLength * sideLength;
} // end function getArea
// return volume of Cube
double Cube::getVolume() const
{
return sideLength * sideLength * sideLength;
} // end function getVolume
// return length of sides
double Cube::getSideLength() const
{
return sideLength;
} // end function getSideLength
// output Cube object
void Cube::print() const
{

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
36
37
38

cout << "Cube with side length " << sideLength << "; center at ("
<< xCenter << ", " << yCenter << ")";
} // end function print

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

// Exercise 13.13 Solution: ex13_13.cpp


// Driver to test Shape hierarchy
#include <iostream>
using std::cout;
using std::endl;

25

#include <vector>
using std::vector;
#include <typeinfo>
#include
#include
#include
#include
#include
#include
#include

"Shape.h"
"TwoDimensionalShape.h"
"ThreeDimensionalShape.h"
"Circle.h"
"Square.h"
"Sphere.h"
"Cube.h"

int main()
{
// create vector shapes
vector < Shape * > shapes( 4 );
// initialize
shapes[ 0 ] =
shapes[ 1 ] =
shapes[ 2 ] =
shapes[ 3 ] =

vector with Shapes


new Circle( 3.5, 6, 9 );
new Square( 12, 2, 2 );
new Sphere( 5, 1.5, 4.5 );
new Cube( 2.2 );

// output Shape objects and display area and volume as appropriate


for ( int i = 0; i < 4; i++ )
{
cout << *( shapes[ i ] ) << endl;
// downcast pointer
TwoDimensionalShape *twoDimensionalShapePtr =
dynamic_cast < TwoDimensionalShape * > ( shapes[ i ] );
// if Shape is a TwoDimensionalShape, display its area
if ( twoDimensionalShapePtr != 0 )
cout << "Area: " << twoDimensionalShapePtr->getArea() << endl;
// downcast pointer
ThreeDimensionalShape *threeDimensionalShapePtr =
dynamic_cast < ThreeDimensionalShape * > ( shapes[ i ] );
// if Shape is a ThreeDimensionalShape, display its area and volume
if ( threeDimensionalShapePtr != 0 )

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

26
50
51
52
53
54
55
56
57
58

Chapter 13 Object-Oriented Programming: Polymorphism

cout << "Area: " << threeDimensionalShapePtr->getArea()


<< "\nVolume: " << threeDimensionalShapePtr->getVolume()
<< endl;
cout << endl;
} // end for
return 0;
} // end main

Circle with radius 3.5; center at (6, 9)


Area: 38.4845
Square with side length 12; center at (2, 2)
Area: 144
Sphere with radius 5; center at (1.5, 4.5)
Area: 314.159
Volume: 523.598
Cube with side length 2.2; center at (0, 0)
Area: 29.04
Volume: 10.648

13.14 (Polymorphic Screen Manager Using Shape Hierarchy) Develop a basic graphics package. Use
the Shape hierarchy implemented in Exercise 13.13. Limit yourself to two-dimensional shapes such
as squares, rectangles, triangles and circles. Interact with the user. Let the user specify the position,
size, shape and fill characters to be used in drawing each shape. The user can specify more than one
of the same shape. As you create each shape, place a Shape * pointer to each new Shape object into
an array. Each Shape class should now have its own draw member function. Write a polymorphic
screen manager that walks through the array, sending draw messages to each object in the array to
form a screen image. Redraw the screen image each time the user specifies an additional shape.
13.15 (Package Inheritance Hierarchy) Use the Package inheritance hierarchy created in
Exercise 12.9 to create a program that displays the address information and calculates the shipping
costs for several Packages. The program should contain a vector of Package pointers to objects of
classes TwoDayPackage and OvernightPackage. Loop through the vector to process the Packages
polymorphically. For each Package, invoke get functions to obtain the address information of the
sender and the recipient, then print the two addresses as they would appear on mailing labels. Also,
call each Packages calculateCost member function and print the result. Keep track of the total
shipping cost for all Packages in the vector, and display this total when the loop terminates.
ANS: [Note: To achieve polymorphic behavior in the Package hierarchy, each class definition must declare the calculateCost member function as a virtual function.]
1
2
3
4
5
6
7
8

// Exercise 13.15 Solution: Package.h


// Definition of base class Package.
#ifndef PACKAGE_H
#define PACKAGE_H
#include <string>
using std::string;

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

27

class Package
{
public:
// constructor initiliazes data members
Package( const string &, const string &, const string &,
const string &, int, const string &, const string &, const string &,
const string &, int, double, double );
void setSenderName( const string & ); // set sender's name
string getSenderName() const; // return sender's name
void setSenderAddress( const string & ); // set sender's address
string getSenderAddress() const; // return sender's address
void setSenderCity( const string & ); // set sender's city
string getSenderCity() const; // return sender's city
void setSenderState( const string & ); // set sender's state
string getSenderState() const; // return sender's state
void setSenderZIP( int ); // set sender's ZIP code
int getSenderZIP() const; // return sender's ZIP code
void setRecipientName( const string & ); // set recipient's name
string getRecipientName() const; // return recipient's name
void setRecipientAddress( const string & ); // set recipient's address
string getRecipientAddress() const; // return recipient's address
void setRecipientCity( const string & ); // set recipient's city
string getRecipientCity() const; // return recipient's city
void setRecipientState( const string & ); // set recipient's state
string getRecipientState() const; // return recipient's state
void setRecipientZIP( int ); // set recipient's ZIP code
int getRecipientZIP() const; // return recipient's ZIP code
void setWeight( double ); // validate and store weight
double getWeight() const; // return weight of package
void setCostPerOunce( double ); // validate and store cost per ounce
double getCostPerOunce() const; // return cost per ounce
virtual double calculateCost() const; // calculate shipping cost
private:
// data members to store sender and recipient's address information
string senderName;
string senderAddress;
string senderCity;
string senderState;
int senderZIP;
string recipientName;
string recipientAddress;
string recipientCity;
string recipientState;
int recipientZIP;
double weight; // weight of the package
double costPerOunce; // cost per ounce to ship the package
}; // end class Package
#endif

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

Chapter 13 Object-Oriented Programming: Polymorphism

// Exercise 13.15 Solution: Package.cpp


// Member-function definitions of class Package.
#include "Package.h" // Package class definition
// constructor initiliazes data members
Package::Package( const string &sName, const string &sAddress,
const string &sCity, const string &sState, int sZIP,
const string &rName, const string &rAddress, const string &rCity,
const string &rState, int rZIP, double w, double cost )
: senderName( sName ), senderAddress( sAddress ), senderCity( sCity ),
senderState( sState ), senderZIP( sZIP ), recipientName( rName ),
recipientAddress( rAddress ), recipientCity( rCity ),
recipientState( rState ), recipientZIP( rZIP )
{
setWeight( w ); // validate and store weight
setCostPerOunce( cost ); // validate and store cost per ounce
} // end Package constructor
// set sender's name
void Package::setSenderName( const string &name )
{
senderName = name;
} // end function setSenderName
// return sender's name
string Package::getSenderName() const
{
return senderName;
} // end function getSenderName
// set sender's address
void Package::setSenderAddress( const string &address )
{
senderAddress = address;
} // end function setSenderAddress
// return sender's address
string Package::getSenderAddress() const
{
return senderAddress;
} // end function getSenderAddress
// set sender's city
void Package::setSenderCity( const string &city )
{
senderCity = city;
} // end function setSenderCity
// return sender's city
string Package::getSenderCity() const
{
return senderCity;
} // end function getSenderCity

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

// set sender's state


void Package::setSenderState( const string &state )
{
senderState = state;
} // end function setSenderState
// return sender's state
string Package::getSenderState() const
{
return senderState;
} // end function getSenderState
// set sender's ZIP code
void Package::setSenderZIP( int zip )
{
senderZIP = zip;
} // end function setSenderZIP
// return sender's ZIP code
int Package::getSenderZIP() const
{
return senderZIP;
} // end function getSenderZIP
// set recipient's name
void Package::setRecipientName( const string &name )
{
recipientName = name;
} // end function setRecipientName
// return recipient's name
string Package::getRecipientName() const
{
return recipientName;
} // end function getRecipientName
// set recipient's address
void Package::setRecipientAddress( const string &address )
{
recipientAddress = address;
} // end function setRecipientAddress
// return recipient's address
string Package::getRecipientAddress() const
{
return recipientAddress;
} // end function getRecipientAddress
// set recipient's city
void Package::setRecipientCity( const string &city )
{
recipientCity = city;
} // end function setRecipientCity

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

29

30
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

Chapter 13 Object-Oriented Programming: Polymorphism

// return recipient's city


string Package::getRecipientCity() const
{
return recipientCity;
} // end function getRecipientCity
// set recipient's state
void Package::setRecipientState( const string &state )
{
recipientState = state;
} // end function setRecipientState
// return recipient's state
string Package::getRecipientState() const
{
return recipientState;
} // end function getRecipientState
// set recipient's ZIP code
void Package::setRecipientZIP( int zip )
{
recipientZIP = zip;
} // end function setRecipientZIP
// return recipient's ZIP code
int Package::getRecipientZIP() const
{
return recipientZIP;
} // end function getRecipientZIP
// validate and store weight
void Package::setWeight( double w )
{
weight = ( w < 0.0 ) ? 0.0 : w;
} // end function setWeight
// return weight of package
double Package::getWeight() const
{
return weight;
} // end function getWeight
// validate and store cost per ounce
void Package::setCostPerOunce( double cost )
{
costPerOunce = ( cost < 0.0 ) ? 0.0 : cost;
} // end function setCostPerOunce
// return cost per ounce
double Package::getCostPerOunce() const
{
return costPerOunce;
} // end function getCostPerOunce

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
163
164
165
166
167
168

31

// calculate shipping cost for package


double Package::calculateCost() const
{
return getWeight() * getCostPerOunce();
} // end function calculateCost

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// Exercise 13.15 Solution: TwoDayPackage.h


// Definition of derived class TwoDayPackage.
#ifndef TWODAY_H
#define TWODAY_H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

// Exercise 13.15 Solution: TwoDayPackage.cpp


// Member-function definitions of class TwoDayPackage.

#include "Package.h" // Package class definition


class TwoDayPackage : public Package
{
public:
TwoDayPackage( const string &, const string &, const string &,
const string &, int, const string &, const string &, const string &,
const string &, int, double, double, double );
void setFlatFee( double ); // set flat fee for two-day-delivery service
double getFlatFee() const; // return flat fee
virtual double calculateCost() const; // calculate shipping cost
private:
double flatFee; // flat fee for two-day-delivery service
}; // end class TwoDayPackage
#endif

#include "TwoDayPackage.h" // TwoDayPackage class definition


// constructor
TwoDayPackage::TwoDayPackage( const string &sName,
const string &sAddress, const string &sCity, const string &sState,
int sZIP, const string &rName, const string &rAddress,
const string &rCity, const string &rState, int rZIP,
double w, double cost, double fee )
: Package( sName, sAddress, sCity, sState, sZIP,
rName, rAddress, rCity, rState, rZIP, w, cost )
{
setFlatFee( fee );
} // end TwoDayPackage constructor
// set flat fee
void TwoDayPackage::setFlatFee( double fee )
{

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

32

Chapter 13 Object-Oriented Programming: Polymorphism

21
22
23
24
25
26
27
28
29
30
31
32
33
34

flatFee = ( fee < 0.0 ) ? 0.0 : fee;


} // end function setFlatFee

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// Exercise 13.15 Solution: OvernightPackage.h


// Definition of derived class OvernightPackage.
#ifndef OVERNIGHT_H
#define OVERNIGHT_H

1
2
3
4
5
6
7
8
9
10
11
12
13

// Exercise 13.15 Solution: OvernightPackage.cpp


// Member-function definitions of class OvernightPackage.

// return flat fee


double TwoDayPackage::getFlatFee() const
{
return flatFee;
} // end function getFlatFee
// calculate shipping cost for package
double TwoDayPackage::calculateCost() const
{
return Package::calculateCost() + getFlatFee();
} // end function calculateCost

#include "Package.h" // Package class definition


class OvernightPackage : public Package
{
public:
OvernightPackage( const string &, const string &, const string &,
const string &, int, const string &, const string &, const string &,
const string &, int, double, double, double );
void setOvernightFeePerOunce( double ); // set overnight fee
double getOvernightFeePerOunce() const; // return overnight fee
virtual double calculateCost() const; // calculate shipping cost
private:
double overnightFeePerOunce; // fee per ounce for overnight delivery
}; // end class OvernightPackage
#endif

#include "OvernightPackage.h" // OvernightPackage class definition


// constructor
OvernightPackage::OvernightPackage( const string &sName,
const string &sAddress, const string &sCity, const string &sState,
int sZIP, const string &rName, const string &rAddress,
const string &rCity, const string &rState, int rZIP,
double w, double cost, double fee )
: Package( sName, sAddress, sCity, sState, sZIP,
rName, rAddress, rCity, rState, rZIP, w, cost )

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

// Exercise 13.15 Solution: ex13_15.cpp


// Processing Packages polymorphically.
#include <iostream>
using std::cout;
using std::endl;

33

setOvernightFeePerOunce( fee ); // validate and store overnight fee


} // end OvernightPackage constructor
// set overnight fee
void OvernightPackage::setOvernightFeePerOunce( double overnightFee )
{
overnightFeePerOunce = ( overnightFee < 0.0 ) ? 0.0 : overnightFee;
} // end function setOvernightFeePerOunce
// return overnight fee
double OvernightPackage::getOvernightFeePerOunce() const
{
return overnightFeePerOunce;
} // end function getOvernghtFeePerOunce
// calculate shipping cost for package
double OvernightPackage::calculateCost() const
{
return getWeight() * ( getCostPerOunce() + getOvernightFeePerOunce() );
} // end function calculateCost

#include <iomanip>
using std::setprecision;
using std::fixed;
#include <vector>
using std::vector;
#include "Package.h" // Package class definition
#include "TwoDayPackage.h" // TwoDayPackage class definition
#include "OvernightPackage.h" // OvernightPackage class definition
int main()
{
// create vector packages
vector < Package * > packages( 3 );
// initialize vector with Packages
packages[ 0 ] = new Package( "Lou Brown", "1 Main St", "Boston", "MA",
11111, "Mary Smith", "7 Elm St", "New York", "NY", 22222, 8.5, .5 );
packages[ 1 ] = new TwoDayPackage( "Lisa Klein", "5 Broadway",
"Somerville", "MA", 33333, "Bob George", "21 Pine Rd", "Cambridge",
"MA", 44444, 10.5, .65, 2.0 );
packages[ 2 ] = new OvernightPackage( "Ed Lewis", "2 Oak St", "Boston",
"MA", 55555, "Don Kelly", "9 Main St", "Denver", "CO", 66666,
12.25, .7, .25 );

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

34
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

Chapter 13 Object-Oriented Programming: Polymorphism

double totalShippingCost = 0.0;


cout << fixed << setprecision( 2 );
// print each package's information and cost
for ( size_t i = 0; i < packages.size(); i++ )
{
cout << "Package " << i + 1 << "\n\nSender:\n"
<< packages[ i ]->getSenderName() << '\n'
<< packages[ i ]->getSenderAddress() << '\n'
<< packages[ i ]->getSenderCity() << ", "
<< packages[ i ]->getSenderState() << ' '
<< packages[ i ]->getSenderZIP();
cout << "\n\nRecipient:\n" << packages[ i ]->getRecipientName()
<< '\n' << packages[ i ]->getRecipientAddress() << '\n'
<< packages[ i ]->getRecipientCity() << ", "
<< packages[ i ]->getRecipientState() << ' '
<< packages[ i ]->getRecipientZIP();
double cost = packages[ i ]->calculateCost();
cout << "\n\nCost: $" << cost << "\n\n";
totalShippingCost += cost; // add this Packages cost to total
} // end for
cout << "Total shipping cost: $" << totalShippingCost << endl;
return 0;
} // end main

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises

35

Package 1
Sender:
Lou Brown
1 Main St
Boston, MA 11111
Recipient:
Mary Smith
7 Elm St
New York, NY 22222
Cost: $4.25
Package 2
Sender:
Lisa Klein
5 Broadway
Somerville, MA 33333
Recipient:
Bob George
21 Pine Rd
Cambridge, MA 44444
Cost: $8.82
Package 3
Sender:
Ed Lewis
2 Oak St
Boston, MA 55555
Recipient:
Don Kelly
9 Main St
Denver, CO 66666
Cost: $11.64
Total shipping cost: $24.71

13.16 (Polymorphic Banking Program Using Account Hierarchy) Develop a polymorphic banking
program using the Account hierarchy created in Exercise 12.10. Create a vector of Account pointers
to SavingsAccount and CheckingAccount objects. For each Account in the vector, allow the user to
specify an amount of money to withdraw from the Account using member function debit and an
amount of money to deposit into the Account using member function credit. As you process each
Account, determine its type. If an Account is a SavingsAccount, calculate the amount of interest

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

36

Chapter 13 Object-Oriented Programming: Polymorphism

owed to the Account using member function calculateInterest, then add the interest to the account balance using member function credit. After processing an Account, print the updated account balance obtained by invoking base class member function getBalance.
ANS: [Note: To achieve polymorphic behavior in the Account hierarchy, each class definition must declare the debit and credit member functions as virtual functions.]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

// Solution 13.16 Solution: Account.h


// Definition of Account class.
#ifndef ACCOUNT_H
#define ACCOUNT_H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

// Exercise 13.16 Solution: Account.cpp


// Member-function definitions for class Account.
#include <iostream>
using std::cout;
using std::endl;

class Account
{
public:
Account( double ); // constructor initializes balance
virtual void credit( double ); // add an amount to the account balance
virtual bool debit( double ); // subtract an amount from the balance
void setBalance( double ); // sets the account balance
double getBalance(); // return the account balance
private:
double balance; // data member that stores the balance
}; // end class Account
#endif

#include "Account.h" // include definition of class Account


// Account constructor initializes data member balance
Account::Account( double initialBalance )
{
// if initialBalance is greater than or equal to 0.0, set this value
// as the balance of the Account
if ( initialBalance >= 0.0 )
balance = initialBalance;
else // otherwise, output message and set balance to 0.0
{
cout << "Error: Initial balance cannot be negative." << endl;
balance = 0.0;
} // end if...else
} // end Account constructor
// credit (add) an amount to the account balance
void Account::credit( double amount )
{
balance = balance + amount; // add amount to balance
} // end function credit

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

// debit (subtract) an amount from the account balance


// return bool indicating whether money was debited
bool Account::debit( double amount )
{
if ( amount > balance ) // debit amount exceeds balance
{
cout << "Debit amount exceeded account balance." << endl;
return false;
} // end if
else // debit amount does not exceed balance
{
balance = balance - amount;
return true;
} // end else
} // end function debit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

// Exercise 13.16 Solution: SavingsAccount.h


// Definition of SavingsAccount class.
#ifndef SAVINGS_H
#define SAVINGS_H

1
2
3

37

// set the account balance


void Account::setBalance( double newBalance )
{
balance = newBalance;
} // end function setBalance
// return the account balance
double Account::getBalance()
{
return balance;
} // end function getBalance

#include "Account.h" // Account class definition


class SavingsAccount : public Account
{
public:
// constructor initializes balance and interest rate
SavingsAccount( double, double );
double calculateInterest(); // determine interest owed
private:
double interestRate; // interest rate (percentage) earned by account
}; // end class SavingsAccount
#endif

// Exercise 13.16 Solution: SavingsAccount.cpp


// Member-function definitions for class SavingsAccount.

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

38

Chapter 13 Object-Oriented Programming: Polymorphism

4
5
6
7
8
9
10
11
12
13
14
15
16
17

#include "SavingsAccount.h" // SavingsAccount class definition

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// Exercise 13.16 Solution: CheckingAccount.h


// Definition of CheckingAccount class.
#ifndef CHECKING_H
#define CHECKING_H

1
2
3
4
5
6
7
8
9
10
11
12

// Exercise 13.16 Solution: CheckingAccount.cpp


// Member-function definitions for class CheckingAccount.
#include <iostream>
using std::cout;
using std::endl;

// constructor initializes balance and interest rate


SavingsAccount::SavingsAccount( double initialBalance, double rate )
: Account( initialBalance ) // initialize base class
{
interestRate = ( rate < 0.0 ) ? 0.0 : rate; // set interestRate
} // end SavingsAccount constructor
// return the amount of interest earned
double SavingsAccount::calculateInterest()
{
return getBalance() * interestRate;
} // end function calculateInterest

#include "Account.h" // Account class definition


class CheckingAccount : public Account
{
public:
// constructor initializes balance and transaction fee
CheckingAccount( double, double );
virtual void credit( double ); // redefined credit function
virtual bool debit( double ); // redefined debit function
private:
double transactionFee; // fee charged per transaction
// utility function to charge fee
void chargeFee();
}; // end class CheckingAccount
#endif

#include "CheckingAccount.h" // CheckingAccount class definition


// constructor initializes balance and transaction fee
CheckingAccount::CheckingAccount( double initialBalance, double fee )
: Account( initialBalance ) // initialize base class
{

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

transactionFee = ( fee < 0.0 ) ? 0.0 : fee; // set transaction fee


} // end CheckingAccount constructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

// Exercise 13.16 Solution: ex13_16.cpp


// Processing Accounts polymorphically.
#include <iostream>
using std::cout;
using std::cin;
using std::endl;

39

// credit (add) an amount to the account balance and charge fee


void CheckingAccount::credit( double amount )
{
Account::credit( amount ); // always succeeds
chargeFee();
} // end function credit
// debit (subtract) an amount from the account balance and charge fee
bool CheckingAccount::debit( double amount )
{
bool success = Account::debit( amount ); // attempt to debit
if ( success ) // if money was debited, charge fee and return true
{
chargeFee();
return true;
} // end if
else // otherwise, do not charge fee and return false
return false;
} // end function debit
// subtract transaction fee
void CheckingAccount::chargeFee()
{
Account::setBalance( getBalance() - transactionFee );
cout << "$" << transactionFee << " transaction fee charged." << endl;
} // end function chargeFee

#include <iomanip>
using std::setprecision;
using std::fixed;
#include <vector>
using std::vector;
#include "Account.h" // Account class definition
#include "SavingsAccount.h" // SavingsAccount class definition
#include "CheckingAccount.h" // CheckingAccount class definition
int main()
{
// create vector accounts
vector < Account * > accounts( 4 );

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

40
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

Chapter 13 Object-Oriented Programming: Polymorphism

// initialize
accounts[ 0 ]
accounts[ 1 ]
accounts[ 2 ]
accounts[ 3 ]

vector with Accounts


= new SavingsAccount( 25.0, .03 );
= new CheckingAccount( 80.0, 1.0 );
= new SavingsAccount( 200.0, .015 );
= new CheckingAccount( 400.0, .5 );

cout << fixed << setprecision( 2 );


// loop through vector, prompting user for debit and credit amounts
for ( size_t i = 0; i < accounts.size(); i++ )
{
cout << "Account " << i + 1 << " balance: $"
<< accounts[ i ]->getBalance();
double withdrawalAmount = 0.0;
cout << "\nEnter an amount to withdraw from Account " << i + 1
<< ": ";
cin >> withdrawalAmount;
accounts[ i ]->debit( withdrawalAmount ); // attempt to debit
double depositAmount = 0.0;
cout << "Enter an amount to deposit into Account " << i + 1
<< ": ";
cin >> depositAmount;
accounts[ i ]->credit( depositAmount ); // credit amount to Account
// downcast pointer
SavingsAccount *savingsAccountPtr =
dynamic_cast < SavingsAccount * > ( accounts[ i ] );
// if Account is a SavingsAccount, calculate and add interest
if ( savingsAccountPtr != 0 )
{
double interestEarned = savingsAccountPtr->calculateInterest();
cout << "Adding $" << interestEarned << " interest to Account "
<< i + 1 << " (a SavingsAccount)" << endl;
savingsAccountPtr->credit( interestEarned );
} // end if
cout << "Updated Account " << i + 1 << " balance: $"
<< accounts[ i ]->getBalance() << "\n\n";
} // end for
return 0;
} // end main

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

Exercises

Account 1 balance: $25.00


Enter an amount to withdraw from Account 1: 15.00
Enter an amount to deposit into Account 1: 10.50
Adding $0.61 interest to Account 1 (a SavingsAccount)
Updated Account 1 balance: $21.11
Account 2 balance: $80.00
Enter an amount to withdraw from Account 2: 90.00
Debit amount exceeded account balance.
Enter an amount to deposit into Account 2: 45.00
$1.00 transaction fee charged.
Updated Account 2 balance: $124.00
Account 3 balance: $200.00
Enter an amount to withdraw from Account 3: 75.50
Enter an amount to deposit into Account 3: 300.00
Adding $6.37 interest to Account 3 (a SavingsAccount)
Updated Account 3 balance: $430.87
Account 4 balance: $400.00
Enter an amount to withdraw from Account 4: 56.81
$0.50 transaction fee charged.
Enter an amount to deposit into Account 4: 37.83
$0.50 transaction fee charged.
Updated Account 4 balance: $380.02

2006 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved.

41