11.3 (Composition as an Alternative to Inheritance) Many programs written with inheritance can be written with composition instead, and vice versa. Rewrite class BasePlusCommissionEmployee
of the CommissionEmployee
–BasePlusCommissionEmployee
hierarchy to use composition rather than inheritance. After you do this, assess the relative merits of the two approaches for designing classes CommissionEmployee
and BasePlusCommissionEmployee
, as well as for object-oriented programs in general. Which approach is more natural? Why?
11.4 (Inheritance Advantage) Discuss the ways in which inheritance saves time during program development and helps prevent errors.
11.5 (Protected vs. Private Base Classes) Some programmers prefer not to use protected
access because they believe it breaks the encapsulation of the base class. Discuss the relative merits of using protected
access vs. using private
access in base classes.
11.6 (Student Inheritance Hierarchy) Draw an inheritance hierarchy for students at a university similar to the hierarchy shown in Fig. 11.2. Use Student
as the base class of the hierarchy, then include classes UndergraduateStudent
and GraduateStudent
that derive from Student
. Continue to extend the hierarchy as deep (i.e., as many levels) as possible. For example, Freshman
, Sophomore
, Junior
and Senior
might derive from UndergraduateStudent
, and DoctoralStudent
and Masters-Student
might derive from GraduateStudent
. After drawing the hierarchy, discuss the relationships that exist between the classes. [Note: You do not need to write any code for this exercise.]
11.7 (Richer Shape Hierarchy) The world of shapes is much richer than the shapes included in the inheritance hierarchy of Fig. 11.3. Write down all the shapes you can think of—both two-dimensional and three-dimensional—and form them into a more complete Shape
hierarchy with as many levels as possible. Your hierarchy should have the base-class Shape
from which class TwoDimensionalShape
and class ThreeDimensionalShape
are derived. [Note: You do not need to write any code for this exercise.] We’ll use this hierarchy in the exercises of Chapter 12 to process a set of distinct shapes as objects of base-class Shape
. (This technique, called polymorphism, is the subject of Chapter 12.)
11.8 (Quadrilateral Inheritance Hierarchy) Draw an inheritance hierarchy for classes Quadrilateral
, Trapezoid
, Parallelogram
, Rectangle
and Square
. Use Quadrilateral
as the base class of the hierarchy. Make the hierarchy as deep as possible.
11.9 (Package
Inheritance Hierarchy) Package-delivery services, such as FedEx®, DHL® and UPS®, offer a number of different shipping options, each with specific costs associated. Create an inheritance hierarchy to represent various types of packages. Use class Package
as the base class of the hierarchy, then include classes TwoDayPackage
and OvernightPackage
that derive from Package
.
Base-class Package
should include data members representing the name, address, city, state and ZIP code for both the sender and the recipient of the package, in addition to data members that store the weight (in ounces) and cost per ounce to ship the package. Package
’s constructor should initialize these data members. Ensure that the weight and cost per ounce contain positive values. Package
should provide a public
member function calculateCost
that returns a double
indicating the cost associated with shipping the package. Package
’s calculateCost
function should determine the cost by multiplying the weight by the cost per ounce.
Derived-class TwoDayPackage
should inherit the functionality of base-class Package
, but also include a data member that represents a flat fee that the shipping company charges for two-day-delivery service. TwoDayPackage
’s constructor should receive a value to initialize this data member. TwoDayPackage
should redefine member function calculateCost
so that it computes the shipping cost by adding the flat fee to the weight-based cost calculated by base-class Package
’s calculateCost
function.
Class OvernightPackage
should inherit directly from class Package
and contain an additional data member representing an additional fee per ounce charged for overnight-delivery service. OvernightPackage
should redefine member function calculateCost
so that it adds the additional fee per ounce to the standard cost per ounce before calculating the shipping cost. Write a test program that creates objects of each type of Package
and tests member function calculateCost
.
11.10 (Account
Inheritance Hierarchy) Create an inheritance hierarchy that a bank might use to represent customers’ bank accounts. All customers at this bank can deposit (i.e., credit) money into their accounts and withdraw (i.e., debit) money from their accounts. More specific types of accounts also exist. Savings accounts, for instance, earn interest on the money they hold. Checking accounts, on the other hand, charge a fee per transaction (i.e., credit or debit).
Create an inheritance hierarchy containing base-class Account
and derived classes SavingsAccount
and CheckingAccount
that inherit from class Account
. Base-class Account
should include one data member of type double
to represent the account balance. The class should provide a constructor that receives an initial balance and uses it to initialize the data member. The constructor should validate the initial balance to ensure that it’s greater than or equal to 0.0
. If not, the balance should be set to 0.0
and the constructor should display an error message, indicating that the initial balance was invalid. The class should provide three member functions. Member function credit
should add an amount to the current balance. Member function debit
should withdraw money from the Account
and ensure that the debit amount does not exceed the Account
’s balance. If it does, the balance should be left unchanged and the function should print the message "Debit amount
exceeded
account
balance."
Member function getBalance
should return the current balance.
Derived-class SavingsAccount
should inherit the functionality of an Account
, but also include a data member of type double
indicating the interest rate (percentage) assigned to the Account
. SavingsAccount
’s constructor should receive the initial balance, as well as an initial value for the SavingsAccount
’s interest rate. SavingsAccount
should provide a public
member function calculateInterest
that returns a double
indicating the amount of interest earned by an account. Member function calculateInterest
should determine this amount by multiplying the interest rate by the account balance. [Note: SavingsAccount
should inherit member functions credit
and debit
as is without redefining them.]
Derived-class CheckingAccount
should inherit from base-class Account
and include an additional data member of type double
that represents the fee charged per transaction. CheckingAccount
’s constructor should receive the initial balance, as well as a parameter indicating a fee amount. Class CheckingAccount
should redefine member functions credit
and debit
so that they subtract the fee from the account balance whenever either transaction is performed successfully. CheckingAccount
’s versions of these functions should invoke the base-class Account
version to perform the updates to an account balance. CheckingAccount
’s debit
function should charge a fee only if money is actually withdrawn (i.e., the debit amount does not exceed the account balance). [Hint: Define Account
’s debit
function so that it returns a bool
indicating whether money was withdrawn. Then use the return value to determine whether a fee should be charged.]
After defining the classes in this hierarchy, write a program that creates objects of each class and tests their member functions. Add interest to the SavingsAccount
object by first invoking its calculateInterest
function, then passing the returned interest amount to the object’s credit
function.