Chapter 15 Inheritance, Polymorphism, and Virtual Functions
15.1 What Is Inheritance?
Concept:
- Inheritance enables a new class, known as the derived class, to be created based on an existing class, the base class.
- The new class inherits all member variables and functions from the base class, with the exception of constructors and the destructor.
- In C++11 and later, a class can optionally inherit some of its base class’s constructors.
Generalization and Specialization
- Many real-world objects can be viewed as specialized versions of more general ones.
- For instance, “insect” is a general category. Grasshoppers and bumblebees are specialized types of insects.
- They share the general characteristics of insects but also possess unique traits, such as a grasshopper’s jumping ability or a bumblebee’s stinger.
Inheritance and the “Is a” Relationship
The relationship between a specialized object and a more general one is called an “is a” relationship. For example, a poodle is a dog.
In object-oriented programming, inheritance is the mechanism used to establish an “is a” relationship between classes.
This involves a base class (the general class, or parent) and a derived class (the specialized class, or child).
The derived class inherits members from the base class and can also have its own unique members added to it.
As an example, consider a
GradedActivityclass that holds a numeric score and determines a letter grade.
Contents of GradedActivity.h (Version 1)
Contents of GradedActivity.cpp (Version 1)
- The
GradedActivityclass includes constructors to initialize the score, asetScoremutator, and agetLetterGradeaccessor.
🗊 Program 15-1
💻 Program Output
💻 Program Output
- To handle specific types of graded activities, such as a final exam, we can create a derived class.
- The
FinalExamclass, for example, is derived fromGradedActivityand adds members to track the number of questions, points per question, and questions missed.
Contents of FinalExam.h
#ifndef FINALEXAM_H
#define FINALEXAM_H
#include "GradedActivity.h"
class FinalExam : public GradedActivity
{
private:
int numQuestions;
double pointsEach;
int numMissed;
public:
FinalExam()
{ numQuestions = 0;
pointsEach = 0.0;
numMissed = 0; }
FinalExam(int questions, int missed)
{ set(questions, missed); }
void set(int, int);
double getNumQuestions() const
{ return numQuestions; }
double getPointsEach() const
{ return pointsEach; }
int getNumMissed() const
{ return numMissed; }
};
#endifContents of FinalExam.cpp
- The declaration
class FinalExam : public GradedActivityindicates thatFinalExamis the derived class andGradedActivityis the base class. This establishes a “FinalExam is a GradedActivity” relationship. - The
publickeyword is the base class access specification. It determines how the base class members are inherited. - With
publicaccess specification,publicmembers ofGradedActivitybecomepublicmembers ofFinalExam. privatemembers ofGradedActivity(likescore) are inherited but are inaccessible directly byFinalExam’s member functions. They can only be accessed via the public member functions of the base class.- Constructors are not inherited.
- The
FinalExam::setfunction calculates the numeric score and then calls the inheritedsetScorefunction to store it.
| Private Members: | |
int numQuestions |
Declared in the FinalExamclass |
double pointsEach |
Declared in the FinalExamclass |
int numMissed |
Declared in the FinalExamclass |
| Public Members: | |
FinalExam() |
Defined in the FinalExamclass |
FinalExam(int, int) |
Defined in the FinalExamclass |
set(int, int) |
Defined in the FinalExamclass |
getNumQuestions() |
Defined in the FinalExamclass |
getPointsEach() |
Defined in the FinalExamclass |
getNumMissed() |
Defined in the FinalExamclass |
setScore(double) |
Inherited from GradedActivity |
getScore() |
Inherited from GradedActivity |
getLetterGrade() |
Inherited from GradedActivity |
🗊 Program 15-2
#include <iostream>
#include <iomanip>
#include "FinalExam.h"
using namespace std;
int main()
{
int questions;
int missed;
cout << "How many questions are on the final exam? ";
cin >> questions;
cout << "How many questions did the student miss? ";
cin >> missed;
FinalExam test(questions, missed);
cout << setprecision(2);
cout << "\nEach question counts " << test.getPointsEach()
<< " points.\n";
cout << "The exam score is " << test.getScore() << endl;
cout << "The exam grade is " << test.getLetterGrade() << endl;
return 0;
}💻 Program Output
- A
FinalExamobject can directly call public member functions inherited fromGradedActivity, such asgetScore()andgetLetterGrade(). - Inheritance is a one-way relationship; a base class cannot call member functions of a derived class.
class BadBase
{
private:
int x;
public:
BadBase() { x = getVal(); }
};
class Derived : public BadBase
{
private:
int y;
public:
Derived(int z) { y = z; }
int getVal() { return y; }
};Checkpoint
15.1 Here is the first line of a class declaration. What is the name of the base class?
class Truck : public Vehicle15.2 What is the name of the derived class in the following declaration line?
class Truck : public Vehicle15.3 Suppose a program has the following class declarations:
class Shape { private: double area; public: void setArea(double a) { area = a; } double getArea() { return area; } }; class Circle : public Shape { private: double radius; public: void setRadius(double r) { radius = r; setArea(3.14 * r * r); } double getRadius() { return radius; } };Answer the following questions concerning these classes:
When an object of the
Circleclass is created, what are its private members?When an object of the
Circleclass is created, what are its public members?What members of the
Shapeclass are not accessible to member functions of theCircleclass?
15.2 Protected Members and Class Access
Concept:
- Protected members of a base class function like private members but can be accessed by derived classes.
- The base class access specification controls how
private,public, andprotectedbase class members are accessed by the derived class.
C++ offers a third access specifier,
protected.protectedmembers of a base class can be accessed by member functions of that base class and by member functions of any derived classes.To code outside the base or derived classes, protected members are inaccessible, just like private members.
Here is a modified
GradedActivityclass where thescoremember is changed fromprivatetoprotected.
Contents of GradedActivity.h (Version 2)
- Because
scoreis nowprotected, a derived class likeFinalExamcan directly access and modify it. - A new function,
adjustScore, is added toFinalExamto round the score up if its fractional part is 0.5 or greater. This function directly accesses the inheritedscoremember.
Contents of FinalExam.h (Version 2)
#ifndef FINALEXAM_H
#define FINALEXAM_H
#include "GradedActivity.h"
class FinalExam : public GradedActivity
{
private:
int numQuestions;
double pointsEach;
int numMissed;
public:
FinalExam()
{ numQuestions = 0;
pointsEach = 0.0;
numMissed = 0; }
FinalExam(int questions, int missed)
{ set(questions, missed); }
void set(int, int);
void adjustScore();
double getNumQuestions() const
{ return numQuestions; }
double getPointsEach() const
{ return pointsEach; }
int getNumMissed() const
{ return numMissed; }
};
#endifContents of FinalExam.cpp (Version 2)
#include "FinalExam.h"
void FinalExam::set(int questions, int missed)
{
double numericScore;
numQuestions = questions;
numMissed = missed;
pointsEach = 100.0 / numQuestions;
numericScore = 100.0 - (missed * pointsEach);
setScore(numericScore);
adjustScore();
}
void FinalExam::adjustScore()
{
double fraction = score - static_cast<int>(score);
if (fraction >= 0.5)
{
score += (1.0 - fraction);
}
}🗊 Program 15-3
#include <iostream>
#include <iomanip>
#include "FinalExam.h"
using namespace std;
int main()
{
int questions;
int missed;
cout << "How many questions are on the final exam? ";
cin >> questions;
cout << "How many questions did the student miss? ";
cin >> missed;
FinalExam test(questions, missed);
cout << setprecision(2) << fixed;
cout << "\nEach question counts "
<< test.getPointsEach() << " points.\n";
cout << "The adjusted exam score is "
<< test.getScore() << endl;
cout << "The exam grade is "
<< test.getLetterGrade() << endl;
return 0;
}💻 Program Output
More about Base Class Access Specification
- Base class access specification controls how inherited members are accessed in the derived class. This is distinct from member access specification (
private,protected,public), which applies to members defined within a class. - The base class access specification acts as a filter for inherited members.
| Base Class Access Specification | How Members of the Base Class Appear in the Derived Class |
|---|---|
private |
Private members of the base class are inaccessible to the derived class. Protected members of the base class become private members of the derived class. Public members of the base class become private members of the derived class. |
protected |
Private members of the base class are inaccessible to the derived class. Protected members of the base class become protected members of the derived class. Public members of the base class become protected members of the derived class. |
public |
Private members of the base class are inaccessible to the derived class. Protected members of the base class become protected members of the derived class. Public members of the base class become public members of the derived class. |
Note:
- If the base class access specification is omitted, it defaults to
private.
class Test : Grade Checkpoint
15.4 What is the difference between private members and protected members?
15.5 What is the difference between member access specification and class access specification?
15.6 Suppose a program has the following class declaration:
class CheckPoint { private: int a; protected: int b; int c; void setA(int x) { a = x;} public: void setB(int y) { b = y;} void setC(int z) { c = z;} };Answer the following questions regarding the class:
Suppose another class,
Quiz, is derived from theCheckPointclass. Here is the first line of its declaration:class Quiz : private CheckPointIndicate whether each member of the
CheckPointclass isprivate,protected,public, or inaccessible:a b c setA setB setCSuppose the
Quizclass, derived from theCheckPointclass, is declared asclass Quiz : protected CheckpointIndicate whether each member of the
CheckPointclass isprivate,protected,public, or inaccessible:a b c setA setB setCSuppose the
Quizclass, derived from theCheckPointclass, is declared asclass Quiz : public CheckpointIndicate whether each member of the
CheckPointclass isprivate,protected,public, or inaccessible:a b c setA setB setCSuppose the
Quizclass, derived from theCheckPointclass, is declared asclass Quiz : CheckpointIs the
CheckPointclass aprivate,public, orprotectedbase class?
15.3 Constructors and Destructors in Base and Derived Classes
Concept:
- When an object of a derived class is created, the base class’s constructor is executed first, followed by the derived class’s constructor.
- Destructors are called in the reverse order: the derived class’s destructor is called first, then the base class’s destructor.
- In an inheritance relationship, constructors are executed from the base class down to the derived class.
- Destructors are executed in the opposite order, from the derived class up to the base class.
- The following program demonstrates this sequence by displaying messages from the constructors and destructors of a base and derived class.
🗊 Program 15-4
#include <iostream>
using namespace std;
class BaseClass
{
public:
BaseClass()
{ cout << "This is the BaseClass constructor.\n"; }
~BaseClass()
{ cout << "This is the BaseClass destructor.\n"; }
};
class DerivedClass : public BaseClass
{
public:
DerivedClass()
{ cout << "This is the DerivedClass constructor.\n"; }
~DerivedClass()
{ cout << "This is the DerivedClass destructor.\n"; }
};
int main()
{
cout << "We will now define a DerivedClass object.\n";
DerivedClass object;
cout << "The program is now going to end.\n";
return 0;
}💻 Program Output
Passing Arguments to Base Class Constructors
- If a base class constructor requires arguments, the derived class constructor is responsible for passing those arguments to it.
- Consider a
Rectangleclass with multiple constructors.
Contents of Rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_H
class Rectangle
{
private:
double width;
double length;
public:
Rectangle()
{ width = 0.0;
length = 0.0; }
Rectangle(double w, double len)
{ width = w;
length = len; }
double getWidth() const
{ return width; }
double getLength() const
{ return length; }
double getArea() const
{ return width * length; }
};
#endif- A
Boxclass derived fromRectanglemust call the appropriateRectangleconstructor.
Contents of Box.h
#ifndef BOX_H
#define BOX_H
#include "Rectangle.h"
class Box : public Rectangle
{
protected:
double height;
double volume;
public:
Box() : Rectangle()
{ height = 0.0; volume = 0.0; }
Box(double w, double len, double h) : Rectangle(w, len)
{ height = h;
volume = getArea() * h; }
double getHeight() const
{ return height; }
double getVolume() const
{ return volume; }
};
#endifA special syntax is used in the derived class constructor’s header to call the base class constructor.
The syntax involves placing a colon after the constructor’s parameter list, followed by a call to the base class constructor. For example:
Box() : Rectangle()calls the base class’s default constructor.The general format is:
ClassName::ClassName(ParameterList) : BaseClassName(ArgumentList)Arguments can also be passed, as seen in the second
Boxconstructor:Box(double w, double len, double h) : Rectangle(w, len). Here,wandlenare passed up to theRectangleconstructor.This notation is used in the constructor’s definition, not its prototype.
The base class constructor always executes before the derived class constructor’s body.
Arguments passed to the base class constructor can be parameters from the derived class constructor, literal values, or accessible global variables.
🗊 Program 15-5
#include <iostream>
#include "Box.h"
using namespace std;
int main()
{
double boxWidth;
double boxLength;
double boxHeight;
cout << "Enter the dimensions of a box:\n";
cout << "Width: ";
cin >> boxWidth;
cout << "Length: ";
cin >> boxLength;
cout << "Height: ";
cin >> boxHeight;
Box myBox(boxWidth, boxLength, boxHeight);
cout << "Here are the box's properties:\n";
cout << "Width: " << myBox.getWidth() << endl;
cout << "Length: " << myBox.getLength() << endl;
cout << "Height: " << myBox.getHeight() << endl;
cout << "Base area: " << myBox.getArea() << endl;
cout << "Volume: " << myBox.getVolume() << endl;
return 0;
}💻 Program Output
Note:
- If a base class does not have a default constructor, any derived class must explicitly call one of the base class’s other constructors.
In the Spotlight:
The Automobile, Car, Truck, and SUV Classes
- To manage a car dealership’s inventory, it’s inefficient to create separate, unrelated classes for cars, trucks, and SUVs because they share many common attributes (make, model, mileage, price).
- A better design uses an
Automobilebase class for the common data and derived classes (Car,Truck,SUV) for specific data.
Contents of Automobile.h
#ifndef AUTOMOBILE_H
#define AUTOMOBILE_H
#include <string>
using namespace std;
class Automobile
{
private:
string make;
int model;
int mileage;
double price;
public:
Automobile()
{ make = "";
model = 0;
mileage = 0;
price = 0.0; }
Automobile(string autoMake, int autoModel,
int autoMileage, double autoPrice)
{ make = autoMake;
model = autoModel;
mileage = autoMileage;
price = autoPrice; }
string getMake() const
{ return make; }
int getModel() const
{ return model; }
int getMileage() const
{ return mileage; }
double getPrice() const
{ return price; }
};
#endif- The
Carclass inherits fromAutomobileand adds adoorsattribute. Its constructors call the correspondingAutomobileconstructors to initialize the inherited members.
Contents of Car.h
#ifndef CAR_H
#define CAR_H
#include "Automobile.h"
#include <string>
using namespace std;
class Car : public Automobile
{
private:
int doors;
public:
Car() : Automobile()
{ doors = 0;}
Car(string carMake, int carModel, int carMileage,
double carPrice, int carDoors) :
Automobile(carMake, carModel, carMileage, carPrice)
{ doors = carDoors; }
int getDoors()
{return doors;}
};
#endif- Similarly, the
Truckclass inherits fromAutomobileand adds adriveTypeattribute, with constructors that call the base class constructors.
Contents of Truck.h
#ifndef TRUCK_H
#define TRUCK_H
#include "Automobile.h"
#include <string>
using namespace std;
class Truck : public Automobile
{
private:
string driveType;
public:
Truck() : Automobile()
{ driveType = ""; }
Truck(string truckMake, int truckModel, int truckMileage,
double truckPrice, string truckDriveType) :
Automobile(truckMake, truckModel, truckMileage, truckPrice)
{ driveType = truckDriveType; }
string getDriveType()
{ return driveType; }
};
#endif- The
SUVclass also inherits fromAutomobileand adds apassengersattribute, following the same constructor pattern.
Contents of SUV.h
#ifndef SUV_H
#define SUV_H
#include "Automobile.h"
#include <string>
using namespace std;
class SUV : public Automobile
{
private:
int passengers;
public:
SUV() : Automobile()
{ passengers = 0; }
SUV(string SUVMake, int SUVModel, int SUVMileage,
double SUVPrice, int SUVPassengers) :
Automobile(SUVMake, SUVModel, SUVMileage, SUVPrice)
{ passengers = SUVPassengers; }
int getPassengers()
{ return passengers; }
};
#endif- The following program demonstrates the creation and use of objects from each of these derived classes.
🗊 Program 15-6
#include <iostream>
#include <iomanip>
#include "Car.h"
#include "Truck.h"
#include "SUV.h"
using namespace std;
int main()
{
Car car("BMW", 2007, 50000, 15000.0, 4);
Truck truck("Toyota", 2006, 40000, 12000.0, "4WD");
SUV suv("Volvo", 2005, 30000, 18000.0, 5);
cout << fixed << showpoint << setprecision(2);
cout << "We have the following car in inventory:\n"
<< car.getModel() << " " << car.getMake()
<< " with " << car.getDoors() << " doors and "
<< car.getMileage() << " miles.\nPrice: $"
<< car.getPrice() << endl << endl;
cout << "We have the following truck in inventory:\n"
<< truck.getModel() << " " << truck.getMake()
<< " with " << truck.getDriveType()
<< " drive type and " << truck.getMileage()
<< " miles.\nPrice: $" << truck.getPrice()
<< endl << endl;
cout << "We have the following SUV in inventory:\n"
<< suv.getModel() << " " << suv.getMake()
<< " with " << suv.getMileage() << " miles and "
<< suv.getPassengers() << " passenger capacity.\n"
<< "Price: $" << suv.getPrice() << endl;
return 0;
}💻 Program Output
Constructor Inheritance
- C++ 11 allows a derived class to inherit constructors from its base class using a
usingdeclaration. - The default constructor, copy constructor, and move constructor cannot be inherited this way.
- This is useful when a derived class constructor’s only job is to call a base class constructor.
- The syntax is
using BaseClassName::BaseClassName;inside the derived class definition. - This allows instances of the derived class to be created by calling the inherited base class constructors directly.
- A derived class can still have its own constructors in addition to the inherited ones.
- If a derived class defines a constructor with the same parameter list as a base class constructor, the base class version is not inherited.
Checkpoint
15.7 What will the following program display?
#include <iostream> using namespace std; class Sky { public: Sky() { cout << "Entering the sky.\n"; } ~Sky() { cout << "Leaving the sky.\n"; } }; class Ground : public Sky { public: Ground() { cout << "Entering the Ground.\n"; } ~Ground() { cout << "Leaving the Ground.\n"; } }; int main() { Ground object; return 0; }15.8 What will the following program display?
#include <iostream> using namespace std; class Sky { public: Sky() { cout << "Entering the sky.\n"; } Sky(string color) { cout << "The sky is " << color << endl; } ~Sky() { cout << "Leaving the sky.\n"; } }; class Ground : public Sky { public: Ground() { cout << "Entering the Ground.\n"; } Ground(string c1, string c2) : Sky(c1) { cout << "The ground is " << c2 << endl; } ~Ground() { cout << "Leaving the Ground.\n"; } }; int main() { Ground object; return 0; }
15.4 Redefining Base Class Functions
Concept:
- A derived class can redefine a member function from its base class.
Redefining a Base Class Function in a Derived Class
- Function redefinition is useful for extending or modifying the behavior of a base class.
- For instance, a
GradedActivityclass might determine a letter grade from a numeric score. - A derived class,
CurvedActivity, could redefine the function that sets the score to first apply a curve.
Contents of CurvedActivity.h
#ifndef CURVEDACTIVITY_H
#define CURVEDACTIVITY_H
#include "GradedActivity.h"
class CurvedActivity : public GradedActivity
{
protected:
double rawScore;
double percentage;
public:
CurvedActivity() : GradedActivity()
{ rawScore = 0.0; percentage = 0.0; }
void setScore(double s)
{ rawScore = s;
GradedActivity::setScore(rawScore * percentage); }
void setPercentage(double c)
{ percentage = c; }
double getPercentage() const
{ return percentage; }
double getRawScore() const
{ return rawScore; }
};
#endif- When a derived class member function has the same name as a base class function, it is said to redefine the base function.
- Objects of the derived class will call the derived class’s version of the function.
- Redefining is different from overloading. Overloading involves functions with the same name but different parameter lists, all within the same scope. Redefining occurs across a base and derived class.
- A redefined function in a derived class can explicitly call the base class version using the scope resolution operator:
BaseClassName::functionName(ArgumentList);. - In the
CurvedActivityexample,setScorecallsGradedActivity::setScore()to pass the adjusted score to the base class.
Note:
- The
CurvedActivityclass has a protected member section, which is a good practice in case it is later used as a base class for another class.
🗊 Program 15-7
#include <iostream>
#include <iomanip>
#include "CurvedActivity.h"
using namespace std;
int main()
{
double numericScore;
double percentage;
CurvedActivity exam;
cout << "Enter the student's raw numeric score: ";
cin >> numericScore;
cout << "Enter the curve percentage for this student: ";
cin >> percentage;
exam.setPercentage(percentage);
exam.setScore(numericScore);
cout << fixed << setprecision(2);
cout << "The raw score is "
<< exam.getRawScore() << endl;
cout << "The curved score is "
<< exam.getScore() << endl;
cout << "The curved grade is "
<< exam.getLetterGrade() << endl;
return 0;
}💻 Program Output
- It’s important to remember that objects of the base class type will always call the base class version of a function, even if it is redefined in a derived class.
🗊 Program 15-8
#include <iostream>
using namespace std;
class BaseClass
{
public:
void showMessage()
{ cout << "This is the Base class.\n";}
};
class DerivedClass : public BaseClass
{
public:
void showMessage()
{ cout << "This is the Derived class.\n"; }
};
int main()
{
BaseClass b;
DerivedClass d;
b.showMessage();
d.showMessage();
return 0;
}💻 Program Output
15.5 Class Hierarchies
Concept:
- A class can be derived from another class, which itself is derived from another class, forming a class hierarchy.
This chain of inheritance can extend for many levels, with each class inheriting the members of all its ancestors.
As an example, a
PassFailActivityclass can be derived fromGradedActivityto handle pass/fail grading.
Contents of PassFailActivity.h
#ifndef PASSFAILACTIVITY_H
#define PASSFAILACTIVITY_H
#include "GradedActivity.h"
class PassFailActivity : public GradedActivity
{
protected:
double minPassingScore;
public:
PassFailActivity() : GradedActivity()
{ minPassingScore = 0.0; }
PassFailActivity(double mps) : GradedActivity()
{ minPassingScore = mps; }
void setMinPassingScore(double mps)
{ minPassingScore = mps; }
double getMinPassingScore() const
{ return minPassingScore; }
char getLetterGrade() const;
};
#endif- This class redefines the
getLetterGradefunction to return ‘P’ (Pass) or ‘F’ (Fail) based on a minimum passing score.
Contents of PassFailActivity.cpp
- A more specialized class, such as
PassFailExam, can then be derived fromPassFailActivity. PassFailExaminherits all members fromPassFailActivity, including thosePassFailActivityinherited fromGradedActivity.
Contents of PassFailExam.h
#ifndef PASSFAILEXAM_H
#define PASSFAILEXAM_H
#include "PassFailActivity.h"
class PassFailExam : public PassFailActivity
{
private:
int numQuestions;
double pointsEach;
int numMissed;
public:
PassFailExam() : PassFailActivity()
{ numQuestions = 0;
pointsEach = 0.0;
numMissed = 0; }
PassFailExam(int questions, int missed, double mps) :
PassFailActivity(mps)
{ set(questions, missed); }
void set(int, int);
double getNumQuestions() const
{ return numQuestions; }
double getPointsEach() const
{ return pointsEach; }
int getNumMissed() const
{ return numMissed; }
};
#endifContents of PassFailExam.cpp
- The
PassFailExamclass contains its own members plus all the public and protected members from its entire inheritance chain.
| Member Variable | Access | Inherited? |
|---|---|---|
numQuestions |
protected | No |
pointsEach |
protected | No |
numMissed |
protected | No |
minPassingScore |
protected | Yes, from PassFailActivity |
score |
protected | Yes, from PassFailActivity, which inherited it from GradedActivity |
| Member Function | Access | Inherited? |
|---|---|---|
set |
public | No |
getNumQuestions |
public | No |
getPointsEach |
public | No |
getNumMissed |
public | No |
setMinPassingScore |
public | Yes, from PassFailActivity |
getMinPassingScore |
public | Yes, from PassFailActivity |
getLetterGrade |
public | Yes, from PassFailActivity |
setScore |
public | Yes, from PassFailActivity, which inherited it from GradedActivity |
getScore |
public | Yes, from PassFailActivity, which inherited it from GradedActivity |
🗊 Program 15-9
#include <iostream>
#include <iomanip>
#include "PassFailExam.h"
using namespace std;
int main()
{
int questions;
int missed;
double minPassing;
cout << "How many questions are on the exam? ";
cin >> questions;
cout << "How many questions did the student miss? ";
cin >> missed;
cout << "Enter the minimum passing score for this test: ";
cin >> minPassing;
PassFailExam exam(questions, missed, minPassing);
cout << fixed << setprecision(1);
cout << "\nEach question counts "
<< exam.getPointsEach() << " points.\n";
cout << "The minimum passing score is "
<< exam.getMinPassingScore() << endl;
cout << "The student's exam score is "
<< exam.getScore() << endl;
cout << "The student's grade is "
<< exam.getLetterGrade() << endl;
return 0;
}💻 Program Output
- Because
PassFailExamis derived fromPassFailActivity, it inherits the redefinedgetLetterGradefunction that reports ‘P’ or ‘F’. - Class hierarchy diagrams are used to visualize inheritance relationships, with general classes at the top and specialized classes at the bottom.
15.6 Polymorphism and Virtual Member Functions
Concept:
- Polymorphism is a feature that allows a base class pointer or reference to refer to objects of different derived types.
- It enables the program to call the correct member function for the object’s actual type.
Polymorphism
- Consider a function
displayGradethat takes aGradedActivityreference as a parameter.
void displayGrade(const GradedActivity &activity)
{
cout << setprecision(1) << fixed;
cout << "The activity's numeric score is "
<< activity.getScore() << endl;
cout << "The activity's letter grade is "
<< activity.getLetterGrade() << endl;
}- Because of the “is-a” relationship, you can pass an object of a class derived from
GradedActivity(likeFinalExam) to this function. - A problem occurs when a derived class redefines a member function. For example, the
PassFailActivityclass redefinesgetLetterGrade. - When a
PassFailActivityobject is passed todisplayGrade, the base class’sgetLetterGradefunction is called, not the redefined one, leading to incorrect output.
🗊 Program 15-10
#include <iostream>
#include <iomanip>
#include "PassFailActivity.h"
using namespace std;
void displayGrade(const GradedActivity &);
int main()
{
PassFailActivity test(70);
test.setScore(72);
displayGrade(test);
return 0;
}
void displayGrade(const GradedActivity &activity)
{
cout << setprecision(1) << fixed;
cout << "The activity's numeric score is "
<< activity.getScore() << endl;
cout << "The activity's letter grade is "
<< activity.getLetterGrade() << endl;
}💻 Program Output
- This issue happens because of static binding, where the compiler determines at compile time which function to call based on the parameter’s type (
GradedActivity), not the actual object’s type (PassFailActivity). - To fix this, the function can be made virtual. A virtual function uses dynamic binding, where the decision of which function to call is made at runtime, based on the object’s actual type.
- To declare a virtual function, use the
virtualkeyword in the base class function declaration.
virtual char getLetterGrade() const;Note:
- The
virtualkeyword is used only in the function’s declaration or prototype within the class, not in the external definition.
- Here is the updated
GradedActivityclass with a virtual function.
Contents ofGradedActivity.h (Version 3)
#ifndef GRADEDACTIVITY_H
#define GRADEDACTIVITY_H
class GradedActivity
{
protected:
double score;
public:
GradedActivity()
{ score = 0.0; }
GradedActivity(double s)
{ score = s; }
void setScore(double s)
{ score = s; }
double getScore() const
{ return score; }
virtual char getLetterGrade() const;
};
#endif- When a base class function is
virtual, any redefined versions in derived classes automatically becomevirtual. It is good practice to also declare them asvirtualfor clarity.
Contents of PassFailActivity.h
#ifndef PASSFAILACTIVITY_H
#define PASSFAILACTIVITY_H
#include "GradedActivity.h"
class PassFailActivity : public GradedActivity
{
protected:
double minPassingScore;
public:
PassFailActivity() : GradedActivity()
{ minPassingScore = 0.0; }
PassFailActivity(double mps) : GradedActivity()
{ minPassingScore = mps; }
void setMinPassingScore(double mps)
{ minPassingScore = mps; }
double getMinPassingScore() const
{ return minPassingScore; }
virtual char getLetterGrade() const;
};
#endif- With the
getLetterGradefunction nowvirtual, the program works as expected.
🗊 Program 15-11
#include <iostream>
#include <iomanip>
#include "PassFailActivity.h"
using namespace std;
void displayGrade(const GradedActivity &);
int main()
{
PassFailActivity test(70);
test.setScore(72);
displayGrade(test);
return 0;
}
void displayGrade(const GradedActivity &activity)
{
cout << setprecision(1) << fixed;
cout << "The activity's numeric score is "
<< activity.getScore() << endl;
cout << "The activity's letter grade is "
<< activity.getLetterGrade() << endl;
}💻 Program Output
- Polymorphism, meaning “the ability to take many forms,” allows the
displayGradefunction to work correctly with objects of different classes derived fromGradedActivity.
🗊 Program 15-12
#include <iostream>
#include <iomanip>
#include "PassFailExam.h"
using namespace std;
void displayGrade(const GradedActivity &);
int main()
{
GradedActivity test1(88.0);
PassFailExam test2(100, 25, 70.0);
cout << "Test 1:\n";
displayGrade(test1);
cout << "\nTest 2:\n";
displayGrade(test2);
return 0;
}
void displayGrade(const GradedActivity &activity)
{
cout << setprecision(1) << fixed;
cout << "The activity's numeric score is "
<< activity.getScore() << endl;
cout << "The activity's letter grade is "
<< activity.getLetterGrade() << endl;
}💻 Program Output
Polymorphism Requires References or Pointers
- Polymorphic behavior is only achieved when using base class references or pointers.
- If an object is passed by value, static binding occurs, and the base class’s version of the function is always called.
- Using a base class pointer as a parameter also enables polymorphism.
🗊 Program 15-13
#include <iostream>
#include <iomanip>
#include "PassFailExam.h"
using namespace std;
void displayGrade(const GradedActivity *);
int main()
{
GradedActivity test1(88.0);
PassFailExam test2(100, 25, 70.0);
cout << "Test 1:\n";
displayGrade(&test1);
cout << "\nTest 2:\n";
displayGrade(&test2);
return 0;
}
void displayGrade(const GradedActivity *activity)
{
cout << setprecision(1) << fixed;
cout << "The activity's numeric score is "
<< activity->getScore() << endl;
cout << "The activity's letter grade is "
<< activity->getLetterGrade() << endl;
}💻 Program Output
Base Class Pointers
- A base class pointer can be assigned the address of a derived class object.
- This allows for creating heterogeneous collections, such as an array of base class pointers where each element points to an object of a different derived class.
🗊 Program 15-14
#include <iostream>
#include <iomanip>
#include "PassFailExam.h"
using namespace std;
void displayGrade(const GradedActivity *);
int main()
{
const int NUM_TESTS = 4;
GradedActivity *tests[NUM_TESTS] =
{ new GradedActivity(88.0),
new PassFailExam(100, 25, 70.0),
new GradedActivity(67.0),
new PassFailExam(50, 12, 60.0)
};
for (int count = 0; count < NUM_TESTS; count++)
{
cout << "Test #" << (count + 1) << ":\n";
displayGrade(tests[count]);
cout << endl;
}
return 0;
}
void displayGrade(const GradedActivity *activity)
{
cout << setprecision(1) << fixed;
cout << "The activity's numeric score is "
<< activity->getScore() << endl;
cout << "The activity's letter grade is "
<< activity->getLetterGrade() << endl;
}💻 Program Output
Base Class Pointers and References Know Only about Base Class Members
- A base class pointer or reference can only be used to call members that are defined in the base class.
- Attempting to call a derived-class-specific member through a base class pointer will result in a compiler error.
The “Is-a” Relationship Does Not Work in Reverse
- The “is-a” relationship is one-way: a
FinalExamis aGradedActivity, but aGradedActivityis not necessarily aFinalExam. - You cannot assign the address of a base class object to a derived class pointer without an explicit type cast.
- Even with a type cast, calling derived-class-specific members on a base class object will cause a runtime error.
Redefining versus Overriding
- Redefining occurs when a derived class function has the same name as a base class function. These calls are statically bound.
- Overriding occurs when a derived class provides its own version of a
virtualfunction from the base class. These calls are dynamically bound.
Virtual Destructors
- If a class might be used as a base class, its destructor should always be declared
virtual. - If the destructor is not virtual, deleting a derived class object through a base class pointer will only call the base class’s destructor, potentially leading to memory leaks.
- Declaring the base class destructor as
virtualensures that both the derived and base class destructors are called in the correct order (derived first, then base).
🗊 Program 15-15
#include <iostream>
using namespace std;
class Animal
{
public:
Animal()
{ cout << "Animal constructor executing.\n"; }
~Animal()
{ cout << "Animal destructor executing.\n"; }
};
class Dog : public Animal
{
public:
Dog() : Animal()
{ cout << "Dog constructor executing.\n"; }
~Dog()
{ cout << "Dog destructor executing.\n"; }
};
int main()
{
Animal *myAnimal = new Dog;
delete myAnimal;
return 0;
}💻 Program Output
🗊 Program 15-16
#include <iostream>
using namespace std;
class Animal
{
public:
Animal()
{ cout << "Animal constructor executing.\n"; }
virtual ~Animal()
{ cout << "Animal destructor executing.\n"; }
};
class Dog : public Animal
{
public:
Dog() : Animal()
{ cout << "Dog constructor executing.\n"; }
~Dog()
{ cout << "Dog destructor executing.\n"; }
};
int main()
{
Animal *myAnimal = new Dog;
delete myAnimal;
return 0;
}💻 Program Output
- Good practice: Any class with a virtual function should also have a virtual destructor.
C++ 11’s override and final Key Words
- The
overridekeyword can be added to a derived class function to ensure it is correctly overriding a base class virtual function. The compiler will issue an error if the function signature does not match a base class virtual function. - This helps catch subtle bugs where a function in the derived class was intended to override but instead overloads the base class function due to a different signature.
- The
finalkeyword can be used to prevent a virtual function from being overridden in any subsequent derived classes.
🗊 Program 15-17
#include <iostream>
using namespace std;
class Base
{
public:
virtual void functionA(int arg) const
{ cout << "This is Base::functionA" << endl; }
};
class Derived : public Base
{
public:
virtual void functionA(long arg) const
{ cout << "This is Derived::functionA" << endl; }
};
int main()
{
Base *b = new Derived();
Derived *d = new Derived();
b->functionA(99);
d->functionA(99);
return 0;
}💻 Program Output
🗊 Program 15-18
#include <iostream>
using namespace std;
class Base
{
public:
virtual void functionA(int arg) const
{ cout << "This is Base::functionA" << endl; }
};
class Derived : public Base
{
public:
virtual void functionA(int arg) const override
{ cout << "This is Derived::functionA" << endl; }
};
int main()
{
Base *b = new Derived();
Derived *d = new Derived();
b->functionA(99);
d->functionA(99);
return 0;
}💻 Program Output
15.7 Abstract Base Classes and Pure Virtual Functions
Concept:
- An abstract base class cannot be instantiated and is used only as a base for other classes.
- A class becomes abstract when it contains at least one pure virtual function.
- A pure virtual function must be overridden by any derived class that is to be instantiated.
- An abstract base class represents a generic concept from which more specific classes are derived.
- A pure virtual function is declared with
= 0at the end of its prototype and has no definition in the base class.
virtual void showInfo() = 0;- The compiler will generate an error if you try to create an object of an abstract base class.
- The following
Studentclass is an abstract base class because it contains a pure virtual function,getRemainingHours.
Contents of Student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <string>
using namespace std;
class Student
{
protected:
string name;
string idNumber;
int yearAdmitted;
public:
Student()
{ name = "";
idNumber = "";
yearAdmitted = 0; }
Student(string n, string id, int year)
{ set(n, id, year); }
void set(string n, string id, int year)
{ name = n;
idNumber = id;
yearAdmitted = year; }
const string getName() const
{ return name; }
const string getIdNum() const
{ return idNumber; }
int getYearAdmitted() const
{ return yearAdmitted; }
virtual int getRemainingHours() const = 0;
};
#endif- The
getRemainingHoursfunction is made pure virtual because its implementation depends on the student’s major, which will be specified in a derived class. - The
CsStudentclass, derived fromStudent, provides a concrete implementation forgetRemainingHours.
Contents of CsStudent.h
#ifndef CSSTUDENT_H
#define CSSTUDENT_H
#include "Student.h"
const int MATH_HOURS = 20;
const int CS_HOURS = 40;
const int GEN_ED_HOURS = 60;
class CsStudent : public Student
{
private:
int mathHours;
int csHours;
int genEdHours;
public:
CsStudent() : Student()
{ mathHours = 0;
csHours = 0;
genEdHours = 0; }
CsStudent(string n, string id, int year) :
Student(n, id, year)
{ mathHours = 0;
csHours = 0;
genEdHours = 0; }
void setMathHours(int mh)
{ mathHours = mh; }
void setCsHours(int csh)
{ csHours = csh; }
void setGenEdHours(int geh)
{ genEdHours = geh; }
virtual int getRemainingHours() const;
};
#endifContents of CsStudent.cpp
🗊 Program 15-19
#include <iostream>
#include "CsStudent.h"
using namespace std;
int main()
{
CsStudent student("Jennifer Haynes", "167W98337", 2006);
student.setMathHours(12);
student.setCsHours(20);
student.setGenEdHours(40);
cout << "The student " << student.getName()
<< " needs to take " << student.getRemainingHours()
<< " more hours to graduate.\n";
return 0;
}💻 Program Output
- Key points:
- A class with a pure virtual function is abstract.
- Abstract classes cannot be instantiated.
- Pure virtual functions must be overridden in a derived class for that derived class to be non-abstract and instantiable.
Checkpoint
15.9 Explain the difference between overloading a function and redefining a function.
15.10 Explain the difference between static binding and dynamic binding.
15.11 Are virtual functions statically bound or dynamically bound?
15.12 What will the following program display?
#include <iostream.> using namespace std; class First { protected: int a; public: First(int x = 1) { a = x; } int getVal() { return a; } }; class Second : public First { private: int b; public: Second(int y = 5) { b = y; } int getVal() { return b; } }; int main() { First object1; Second object2; cout << object1.getVal() << endl; cout << object2.getVal() << endl; return 0; }15.13 What will the following program display?
#include <iostream> using namespace std; class First { protected: int a; public: First(int x = 1) { a = x; } void twist() { a *= 2; } int getVal() { twist(); return a; } }; class Second : public First { private: int b; public: Second(int y = 5) { b = y; } void twist() { b *= 10; } }; int main() { First object1; Second object2; cout << object1.getVal() << endl; cout << object2.getVal() << endl; return 0; }15.14 What will the following program display?
#include <iostream> using namespace std; class First { protected: int a; public: First(int x = 1) { a = x; } virtual void twist() { a *= 2; } int getVal() { twist(); return a; } }; class Second : public First { private: int b; public: Second(int y = 5) { b = y; } virtual void twist() { b *= 10; } }; int main() { First object1; Second object2; cout << object1.getVal() << endl; cout << object2.getVal() << endl; return 0; }15.15 What will the following program display?
#include <iostream> using namespace std; class Base { protected: int baseVar; public: Base(int val = 2) { baseVar = val; } int getVar() { return baseVar; } }; class Derived : public Base { private: int derivedVar; public: Derived(int val = 100) { derivedVar = val; } int getVar() { return derivedVar; } }; int main() { Base *optr = nullptr; Derived object; optr = &object; cout << optr->getVar() << endl; return 0; }
15.8 Multiple Inheritance
Concept:
- Multiple inheritance allows a derived class to have two or more base classes.
Multiple inheritance is distinct from a chain of inheritance, where a class inherits from another class that is itself derived.
With multiple inheritance, a class directly inherits members from several base classes simultaneously.
As an example, a
DateTimeclass can inherit from both aDateclass and aTimeclass.
Contents of Date.h
#ifndef DATE_H
#define DATE_H
class Date
{
protected:
int day;
int month;
int year;
public:
Date(int d, int m, int y)
{ day = 1; month = 1; year = 1900; }
Date(int d, int m, int y)
{ day = d; month = m; year = y; }
int getDay() const
{ return day; }
int getMonth() const
{ return month; }
int getYear() const
{ return year; }
};
#endifContents of Time.h
#ifndef TIME_H
#define TIME_H
class Time
{
protected:
int hour;
int min;
int sec;
public:
Time()
{ hour = 0; min = 0; sec = 0; }
Time(int h, int m, int s)
{ hour = h; min = m; sec = s; }
int getHour() const
{ return hour; }
int getMin() const
{ return min; }
int getSec() const
{ return sec; }
};
#endif- The syntax for declaring a class with multiple bases involves listing each base class and its access specifier, separated by commas.
Contents of DateTime.h
Contents of DateTime.cpp
#include <iostream>
#include <string>
#include "DateTime.h"
using namespace std;
DateTime::DateTime() : Date(), Time()
{}
DateTime::DateTime(int dy, int mon, int yr, int hr, int mt, int sc) :
Date(dy, mon, yr), Time(hr, mt, sc)
{}
void DateTime::showDateTime() const
{
cout << getMonth() << "/" << getDay() << "/" << getYear() << " ";
cout << getHour() << ":" << getMin() << ":" << getSec() << endl;
}- In the derived class’s constructor, calls to the base class constructors are listed after a colon, separated by commas.
- Base class constructors are always called in the order they are listed in the class declaration, regardless of the order in the constructor’s initializer list.
- Destructors are called in the reverse order of inheritance.
🗊 Program 15-20
💻 Program Output
Note:
- Multiple inheritance can lead to ambiguity if two or more base classes have members with the same name.
- To resolve this, the derived class should redefine or override the ambiguous functions and use the scope resolution operator (
::) to specify which base class member to access.
Checkpoint
15.16 Does the following diagram depict multiple inheritance or a chain of inheritance?
15.17 Does the following diagram depict multiple inheritance or a chain of inheritance?
15.18 Examine the following classes. The table lists the variables that are members of the
Thirdclass (some are inherited). Complete the table by filling in the access specification each member will have in theThirdclass. Write “inaccessible” if a member is inaccessible to theThirdclass.class First { private: int a; protected: double b; public: long c; }; class Second : protected First { private: int d; protected: double e; public: long f; }; class Third : public Second { private: int g; protected: double h; public: long i; };Member Variable Access Specification in Third Class abcdefghi15.19 Examine the following class declarations:
class Van { protected: int passengers; public: Van(int p) { passengers = p; } }; class FourByFour { protected: double cargoWeight; public: FourByFour(float w) { cargoWeight = w; } };
Write the declaration of a class named SportUtility. The class should be derived from both the Van and FourByFour classes above. (This should be a case of multiple inheritance, where both Van and FourByFour are base classes.)
Review Questions and Exercises
Short Answer
What is an “is a” relationship?
A program uses two classes:
DogandPoodle. Which class is the base class, and which is the derived class?How does base class access specification differ from class member access specification?
What is the difference between a protected class member and a private class member?
Can a derived class ever directly access the private members of its base class?
Which constructor is called first, that of the derived class or the base class?
What is the difference between redefining a base class function and overriding a base class function?
When does static binding take place? When does dynamic binding take place?
What is an abstract base class?
A program has a class
Potato, which is derived from the classVegetable, which is derived from the classFood. Is this an example of multiple inheritance? Why or why not?What base class is named in the line below?
class Pet : public DogWhat derived class is named in the line below?
class Pet : public DogWhat is the class access specification of the base class named below?
class Pet : public DogWhat is the class access specification of the base class named below?
class Pet : FishProtected members of a base class are like ____________________ members, except they may be accessed by derived classes.
Complete the table on the next page by filling in private, protected, public, or inaccessible in the right-hand column:
In a private base class, this base class MEMBER access specification… …becomes this access specification in the derived class. privateprotectedpublicComplete the table below by filling in private, protected, public, or inaccessible in the right-hand column:
In a protected base class, this base class MEMBER access specification… …becomes this access specification in the derived class. privateprotectedpublicComplete the table below by filling in private, protected, public, or inaccessible in the right-hand column:
In a public base class, this base class MEMBER access specification… …becomes this access specification in the derived class. privateprotectedpublic
Fill-in-the-Blank
A derived class inherits the ____________________ of its base class.
When both a base class and a derived class have constructors, the base class’s constructor is called ____________________ (first/last).
When both a base class and a derived class have destructors, the base class’s constructor is called ____________________ (first/last).
An overridden base class function may be called by a function in a derived class by using the ____________________ operator.
When a derived class redefines a function in a base class, which version of the function do objects that are defined of the base class call? ____________________
A(n) ____________________ member function in a base class expects to be overridden in a derived class.
____________________ binding is when the compiler binds member function calls at compile time.
____________________ binding is when a function call is bound at runtime.
____________________ is when member functions in a class hierarchy behave differently, depending upon which object performs the call.
When a pointer to a base class is made to point to a derived class, the pointer ignores any ____________________ the derived class performs, unless the function is ____________________.
A(n) ____________________ class cannot be instantiated.
A(n) ____________________ function has no body, or definition, in the class in which it is declared.
A(n) ____________________ of inheritance is where one class is derived from a second class, which in turn is derived from a third class.
____________________ is where a derived class has two or more base classes.
In multiple inheritance, the derived class should always ____________________ a function that has the same name in more than one base class.
Algorithm Workbench
Write the first line of the declaration for a
Poodleclass. The class should be derived from theDogclass with public base class access.Write the first line of the declaration for a
SoundSystemclass. Use multiple inheritance to base the class on theCDplayerclass, theTunerclass, and theMP3Playerclass. Use public base class access in all cases.Suppose a class named
Tigeris derived from both theFelisclass and theCarnivoreclass. Here is the first line of theTigerclass declaration:class Tiger : public Felis, public CarnivoreHere is the function header for the
Tigerconstructor:Tiger(int x, int y) : Carnivore(x), Felis(y)Which base class constructor is called first,
CarnivoreorFelis?Write the declaration for class
B. The class’s members should be as follows:m: an integer. This variable should not be accessible to code outside the class or to member functions in any class derived from classB.n: an integer. This variable should not be accessible to code outside the class, but should be accessible to member functions in any class derived from classB.setM,getM,setN, andgetN: These are the set and get functions for the member variablesmandn. These functions should be accessible to code outside the class.calc: a public virtual member function that returns the value ofmtimesn.
Next, write the declaration for class
D, which is derived from classB. The class’s members should be as follows:q: afloat. This variable should not be accessible to code outside the class but should be accessible to member functions in any class derived from classD.r: afloat. This variable should not be accessible to code outside the class, but should be accessible to member functions in any class derived from classD.setQ,getQ,setR, andgetR: These are the set and get functions for the member variablesqandr. These functions should be accessible to code outside the class.calc: a public member function that overrides the base classcalcfunction. This function should return the value ofqtimesr.
True or False
T F The base class’s access specification affects the way base class member functions may access base class member variables.
T F The base class’s access specification affects the way the derived class inherits members of the base class.
T F Private members of a private base class become inaccessible to the derived class.
T F Public members of a private base class become private members of the derived class.
T F Protected members of a private base class become public members of the derived class.
T F Public members of a protected base class become private members of the derived class.
T F Private members of a protected base class become inaccessible to the derived class.
T F Protected members of a public base class become public members of the derived class.
T F The base class constructor is called after the derived class constructor.
T F The base class destructor is called after the derived class destructor.
T F It isn’t possible for a base class to have more than one constructor.
T F Arguments are passed to the base class constructor by the derived class constructor.
T F A member function of a derived class may not have the same name as a member function of the base class.
T F Pointers to a base class may be assigned the address of a derived class object.
T F A base class may not be derived from another class.
Find the Errors
Each of the class declarations and/or member function definitions below has errors. Find as many as you can.
-
class Car, public Vehicle { public: Car(); ~Car(); protected: int passengers; } -
class Truck, public : Vehicle, protected { private: double cargoWeight; public: Truck(); ~Truck(); }; -
class SnowMobile : Vehicle { protected: int horsePower; double weight; public: SnowMobile(int h, double w), Vehicle(h) { horsePower = h; } ~SnowMobile(); }; -
class Table : public Furniture { protected: int numSeats; public: Table(int n) : Furniture(numSeats) { numSeats = n; } ~Table(); }; -
class Tank : public Cylinder { private: int fuelType; double gallons; public: Tank(); ~Tank(); void setContents(double); void setContents(double); }; -
class Three : public Two : public One { protected: int x; public: Three(int a, int b, int c), Two(b), Three(c) { x = a; } ~Three(); };
Programming Challenges
EmployeeandProductionWorkerClasses
Solving the
EmployeeandProductionWorkerClasses ProblemDesign a class named
Employee. The class should keep the following information:Employee name
Employee number
Hire date
Write one or more constructors, and the appropriate accessor and mutator functions, for the class.
Next, write a class named
ProductionWorkerthat is derived from theEmployeeclass. TheProductionWorkerclass should have member variables to hold the following information:Shift (an integer)
Hourly pay rate (a
double)
The workday is divided into two shifts: day and night. The shift variable will hold an integer value representing the shift that the employee works. The day shift is shift 1, and the night shift is shift 2. Write one or more constructors, and the appropriate accessor and mutator functions, for the class. Demonstrate the classes by writing a program that uses a
ProductionWorkerobject.ShiftSupervisorClassIn a particular factory, a shift supervisor is a salaried employee who supervises a shift. In addition to a salary, the shift supervisor earns a yearly bonus when his or her shift meets production goals. Design a
ShiftSupervisorclass that is derived from theEmployeeclass you created in Programming Challenge 1 (Employee and Production Worker Classes). TheShiftSupervisorclass should have a member variable that holds the annual salary, and a member variable that holds the annual production bonus that a shift supervisor has earned. Write one or more constructors and the appropriate accessor and mutator functions for the class. Demonstrate the class by writing a program that uses aShiftSupervisorobject.TeamLeaderClassIn a particular factory, a team leader is an hourly paid production worker who leads a small team. In addition to hourly pay, team leaders earn a fixed monthly bonus. Team leaders are required to attend a minimum number of hours of training per year. Design a
TeamLeaderclass that extends theProductionWorkerclass you designed in Programming Challenge 1 (Employee and Production Worker Classes). TheTeamLeaderclass should have member variables for the monthly bonus amount, the required number of training hours, and the number of training hours that the team leader has attended. Write one or more constructors and the appropriate accessor and mutator functions for the class. Demonstrate the class by writing a program that uses aTeamLeaderobject.Time Format
In Program 15-20, the file
Time.hcontains aTimeclass. Design a class calledMilTimethat is derived from theTimeclass. TheMilTimeclass should convert time in military (24-hour) format to the standard time format used by theTimeclass. The class should have the following member variables:milHours:Contains the hour in 24-hour format. For example, 1:00 p.m. would be stored as 1300 hours, and 4:30 p.m. would be stored as 1630 hours. milSeconds:Contains the seconds in standard format. The class should have the following member functions:
Constructor:The constructor should accept arguments for the hour and seconds, in military format. The time should then be converted to standard time and stored in the hours,min, andsecvariables of theTimeclass.setTime:Accepts arguments to be stored in the milHoursandmilSecondsvariables. The time should then be converted to standard time and stored in thehours,min, andsecvariables of theTimeclass.getHour:Returns the hour in military format. getStandHr:Returns the hour in standard format. Demonstrate the class in a program that asks the user to enter the time in military format. The program should then display the time in both military and standard format.
Input Validation: The
MilTimeclass should not accept hours greater than 2359, or less than 0. It should not accept seconds greater than 59 or less than 0.Time Clock
Design a class named
TimeClock. The class should be derived from theMilTimeclass you designed in Programming Challenge 4 (Time Format). The class should allow the programmer to pass two times to it: starting time and ending time. The class should have a member function that returns the amount of time elapsed between the two times. For example, if the starting time is 900 hours (9:00 a.m.), and the ending time is 1300 hours (1:00 p.m.), the elapsed time is 4 hours.Input Validation: The class should not accept hours greater than 2359 or less than 0.
EssayClassDesign an
Essayclass that is derived from theGradedActivityclass presented in this chapter. TheEssayclass should determine the grade a student receives on an essay. The student’s essay score can be up to 100, and is determined in the following manner:Grammar: 30 points
Spelling: 20 points
Correct length: 20 points
Content: 30 points
Demonstrate the class in a simple program.
PersonDataandCustomerDataClassesDesign a class named
PersonDatawith the following member variables:lastNamefirstNameaddresscitystate
zipphone
Write the appropriate accessor and mutator functions for these member variables.
Next, design a class named
CustomerData, which is derived from thePersonDataclass. TheCustomerDataclass should have the following member variables:customerNumbermailingList
The
customerNumbervariable will be used to hold a unique integer for each customer. ThemailingListvariable should be abool. It will be set totrueif the customer wishes to be on a mailing list, orfalseif the customer does not wish to be on a mailing list. Write appropriate accessor and mutator functions for these member variables. Demonstrate an object of theCustomerDataclass in a simple program.PreferredCustomerClassA retail store has a preferred customer plan where customers may earn discounts on all their purchases. The amount of a customer’s discount is determined by the amount of the customer’s cumulative purchases in the store.
When a preferred customer spends $500, he or she gets a 5 percent discount on all future purchases.
When a preferred customer spends $1,000, he or she gets a 6 percent discount on all future purchases.
When a preferred customer spends $1,500, he or she gets a 7 percent discount on all future purchases.
When a preferred customer spends $2,000 or more, he or she gets a 10 percent discount on all future purchases.
Design a class named
PreferredCustomer, which is derived from theCustomerDataclass you created in Programming Challenge 7. ThePreferredCustomerclass should have the following member variables:purchasesAmount(adouble)discountLevel(adouble)
The
purchasesAmountvariable holds the total of a customer’s purchases to date. ThediscountLevelvariable should be set to the correct discount percentage, according to the store’s preferred customer plan. Write appropriate member functions for this class and demonstrate it in a simple program.Input Validation: Do not accept negative values for any sales figures.
File Filter
A file filter reads an input file, transforms it in some way, and writes the results to an output file. Write an abstract file filter class that defines a pure virtual function for transforming a character. Create one derived class of your file filter class that performs encryption, another that transforms a file to all uppercase, and another that creates an unchanged copy of the original file. The class should have the following member function:
void doFilter(ifstream &in, ofstream &out)This function should be called to perform the actual filtering. The member function for transforming a single character should have the prototype:
char transform(char ch)The encryption class should have a constructor that takes an integer as an argument and uses it as the encryption key.
File Double-Spacer
Create a derived class of the abstract filter class of Programming Challenge 9 (File Filter) that double-spaces a file, that is, it inserts a blank line between any two lines of the file.
Course Grades
In a course, a teacher gives the following tests and assignments:
A lab activity that is observed by the teacher and assigned a numeric score.
A pass/fail exam that has ten questions. The minimum passing score is 70.
An essay that is assigned a numeric score.
A final exam that has 50 questions.
Write a class named
CourseGrades. The class should have a member namedgradesthat is an array ofGradedActivitypointers. Thegradesarray should have four elements, one for each of the assignments previously described. The class should have the following member functions:setLab:This function should accept the address of a GradedActivityobject as its argument. This object should already hold the student’s score for the lab activity. Element 0 of thegradesarray should reference this object.setPassFailExam:This function should accept the address of a PassFailExamobject as its argument. This object should already hold the student’s score for the pass/fail exam. Element 1 of thegradesarray should reference this object.setEssay:This function should accept the address of an Essayobject as its argument. (See Programming Challenge 6 for theEssayclass. If you have not completed Programming Challenge 6, use aGradedActivityobject instead.) This object should already hold the student’s score for the essay. Element 2 of thegradesarray should reference this object.setPassFailExam:This function should accept the address of a FinalExamobject as its argument. This object should already hold the student’s score for the final exam. Element 3 of thegradesarray should reference this object.print:This function should display the numeric scores and grades for each element in the gradesarray.Demonstrate the class in a program.
Ship,CruiseShip, andCargoShipClassesDesign a
Shipclass that has the following members:A member variable for the name of the ship (a string)
A member variable for the year that the ship was built (a string)
A constructor and appropriate accessors and mutators
A virtual
printfunction that displays the ship’s name and the year it was built.
Design a
CruiseShipclass that is derived from theShipclass. TheCruiseShipclass should have the following members:A member variable for the maximum number of passengers (an
int)A constructor and appropriate accessors and mutators
A
printfunction that overrides theprintfunction in the base class. TheCruiseShipclass’s print function should display only the ship’s name and the maximum number of passengers.
Design a
CargoShipclass that is derived from theShipclass. TheCargoShipclass should have the following members:A member variable for the cargo capacity in tonnage (an
int)A constructor and appropriate accessors and mutators
A
printfunction that overrides theprintfunction in the base class. TheCargoShipclass’s print function should display only the ship’s name and the ship’s cargo capacity.
Demonstrate the classes in a program that has an array of
Shippointers. The array elements should be initialized with the addresses of dynamically allocatedShip,CruiseShip, andCargoShipobjects. (See Program 15-14, lines 17 through 22, for an example of how to do this.) The program should then step through the array, calling each object’sprintfunction.Pure Abstract Base Class Project
Define a pure abstract base class called
BasicShape. TheBasicShapeclass should have the following members:Private Member Variable:
area: A double used to hold the shape’s area.
Public Member Functions:
getArea:This function should return the value in the member variable area.calcArea:This function should be a pure virtual function.
Next, define a class named
Circle. It should be derived from theBasicShapeclass. It should have the following members:Private Member Variables:
centerX:a long integer used to hold the x coordinate of the circle’s centercenterY:a long integer used to hold the y coordinate of the circle’s centerradius: a double used to hold the circle’s radius
Public Member Functions:
constructor: accepts values for
centerX, centerY, andradius.Should call the overriddencalcAreafunction described below.getCenterX: returns the value incenterXgetCenterY: returns the value incenterYcalcArea: calculates the area of the circle (area = 3.14159 * radius * radius) and stores the result in the inherited member area.
Next, define a class named
Rectangle. It should be derived from theBasicShapeclass. It should have the following members:Private Member Variables:
width: a long integer used to hold the width of the rectanglelength: a long integer used to hold the length of the rectangle
Public Member Functions:
constructor: accepts values for width and length. Should call the overriddencalcAreafunction described below.getWidth: returns the value in width.getLength: returns the value in length.calcArea: calculates the area of the rectangle (area = length * width) and stores the result in the inherited member area.
After you have created these classes, create a driver program that defines a
Circleobject and aRectangleobject. Demonstrate that each object properly calculates and reports its area.
Group Project
Bank Accounts
This program should be designed and written by a team of students. Here are some suggestions:
One or more students may work on a single class.
The requirements of the program should be analyzed so that each student is given about the same work load.
The parameters and return types of each function and class member function should be decided in advance.
The program will be best implemented as a multi-file program.
Design a generic class to hold the following information about a bank account:
Balance
Number of deposits this month
Number of withdrawals
Annual interest rate
Monthly service charges
The class should have the following member functions:
constructor:Accepts arguments for the balance and annual interest rate. deposit:A virtual function that accepts an argument for the amount of the deposit. The function should add the argument to the account balance. It should also increment the variable holding the number of deposits. withdraw:A virtual function that accepts an argument for the amount of the withdrawal. The function should subtract the argument from the balance. It should also increment the variable holding the number of withdrawals. calcInt:A virtual function that updates the balance by calculating the monthly interest earned by the account, and adding this interest to the balance. This is performed by the following formulas:
\begin{array}{l} {\text{Monthly}\,\text{Interest}\,\text{Rate}\, = \,\text{(Annual}\,\text{Interest}\,\text{Rate}\,\text{/}\,\text{12}} \\ {\text{Monthly}\,\text{Interest}\, = \,\text{Balance}\,*\,\text{Monthly}\,\text{Interest}\,\text{Rate}} \\ {\text{Balance}\, = \,\text{Balance}\, + \,\text{Monthly}\,\text{Interest}} \end{array}
monthlyProc:A virtual function that subtracts the monthly service charges from the balance, calls the calcIntfunction, then sets the variables that hold the number of withdrawals, number of deposits, and monthly service charges to zero.Next, design a savings account class, derived from the generic account class. The savings account class should have the following additional member:
status (to represent an active or inactive account)
If the balance of a savings account falls below $25, it becomes inactive. (The
statusmember could be a flag variable.) No more withdrawals may be made until the balance is raised above $25, at which time the account becomes active again. The savings account class should have the following member functions:withdraw:A function that checks to see if the account is inactive before a withdrawal is made. (No withdrawal will be allowed if the account is not active.) A withdrawal is then made by calling the base class version of the function. deposit:A function that checks to see if the account is inactive before a deposit is made. If the account is inactive and the deposit brings the balance above $25, the account becomes active again. The deposit is then made by calling the base class version of the function. monthlyProc:Before the base class function is called, this function checks the number of withdrawals. If the number of withdrawals for the month is more than 4, a service charge of $1 for each withdrawal above 4 is added to the base class variable that holds the monthly service charges. (Don’t forget to check the account balance after the service charge is taken. If the balance falls below $25, the account becomes inactive.) Next, design a checking account class, also derived from the generic account class. It should have the following member functions:
withdraw:Before the base class function is called, this function will determine if a withdrawal (a check written) will cause the balance to go below $0. If the balance goes below $0, a service charge of $15 will be taken from the account. (The withdrawal will not be made.) If there isn’t enough in the account to pay the service charge, the balance will become negative and the customer will owe the negative amount to the bank. monthlyProc:Before the base class function is called, this function adds the monthly fee of $5 plus $0.10 per withdrawal (check written) to the base class variable that holds the monthly service charges. Write a complete program that demonstrates these classes by asking the user to enter the amounts of deposits and withdrawals for a savings account and checking account. The program should display statistics for the month, including beginning balance, total amount of deposits, total amount of withdrawals, service charges, and ending balance.
Note:You may need to add more member variables and functions to the classes than those listed above.