Inheritance- The ability to create new objects that maintain the properties & behaviors of ancestor objects
SuperClass & SubClass relationship - "is an"
Inherit everything you can.
Add or change only what you must.
Animals / | \ Protozoa Metazoa Parazoa / \ Anthropoda Chordata / | Vertebrata Cephalocordata / | Mammals Reptilia | Primates / HomoSapiens
Base class - superclass
Derived class - subclass
int left, top, bottom, right;
void Draw(); void Erase(); void Move(int h, int v); |
GeometricObject / \ One_D_Object Two_D_Object / \ / \ Line Arc Rectangle Ellipse | | Square CircleDesign Guideline 7. If two or more classes are logically related and share member functions and data, consider "factoring out" the common elements of the base class.
class GeometricObject
{
public:
int left, right, top, bottom;
void Draw();
void Erase();
void Move(int h, int v);
};
class Two_D_Object : public GeometricObject
{
public:
int fillPattern;
};
class Rectangle : public Two_D_Object
{
};
cout << thisRect.top;
thisRect.Move(32, -6);
thisRect.fillPattern = 1;
To declare a class to be derived from a base class, follow its name by the name of the base class, as
class DerivedClassName : public BaseClassName
The derived class will have access to all public
member data and functions of the base class, just as if they were
public members of the derived class.
8.3 INHERITANCE AND ACCESS CONTROL
Public vs. Protected vs. Private
If a data item is declared to be private to a base class, it is inaccessible to any external classes--including those that are derived from the base class.
Class Two_D_Object : public GeometricObject
{
public:
int fillPattern;
void findCenter(int&, int&);
};
findCenter can access top, bottom, left and
right because they are public.
Class member functions and data that are declared protected may be accessed by objects of that class, by friends of the class, and by objects in a derived class, but they may not be accessed by any other object.
class GeometricObject
{
public:
void Draw();
void Erase();
void Move(int h, int v);
protected:
int left, right, top, bottom;
private:
};
8.4 CREATING AND DESTROYING DERIVED CLASSES
class GeometricObject { public: void Draw(); void Erase(); void Move(int h, int v); GeometricObject(); GeometricObject(int tp, int lef, int bot, int righ); protected: int left, right, top, bottom; private: };
class Two_D_Object : public GeometricObject { public: void findCenter(int&, int&); Two_D_Object(); Two_D_Object(int tp, int lef, int bot, int righ, int fill) : GeometricObject( tp, lef, bot, righ); //initialization list protected: int fillPattern; };
class Rectangle : public Two_D_Object { public: Rectangle(); Rectangle(int tp, int lef, int bot, int righ, int fill) : Two_D_Object( tp, lef, bot, righ, fill); };
8.5 DEFINING DERIVED CLASSES
Polymorphism- calls to functions of an object will call code appropriate to whatever instance is actually in the object.
(Use the same function name to represent different "versions" of a function)
void GeometricObject::Draw() // readies the area to be drawn { : } void Two_D_Object::Draw() { GeometricObject::Draw(); // call the inherited function : // set the fill } void Rectangle::Draw() { //do some processing Two_D_Object::Draw(); // call the base class and then do the actual drawing } main() { GeometricObject geo1; Two_D_Object two1; Rectangle r1; geo1.Draw(); two1.Draw(); r1.Draw(); }
PROBLEM - WANT TO DRAW DIFFERENT TYPES OF OBJECTS
GeometricObject GO[10];
:
for (int I = 0; I < numberOfObjects; I++) GO[i].Draw();
only uses Draw for base class
SOLUTION - use virtual functions and pointers to the objects
virtual void Draw() = 0;
GeometricObject* GO[numberOfObjects]; Rectangle r; Circle c; Line l; GO[0] = &r; GO[1] = &c; GO[2] = &l; for (int I = 0; I < numberOfObjects; I++) GO[i]->Draw();
heterogeneous lists virtual functions
Step 1: Create an array of objects from the base class.
Step 2: Create individual, derived objects of each derived class.
Step 3: Put the addresses of the derived objects into the array.
Step 4: Access the collection of elements by iterating through the array.
Step 5: Change the declaration of the function to be overridden in the most abstract class by including virtual.
8.6 PROGRAM IN PROGRESS: A PAYROLL PROGRAM
Employee - everyone who receives a paycheck rom the company
name, address, SSN, net pay
Temporary - paid at hourly rate for hrs worked & no payroll deduction
Permanent - fixed deduction
Permanent Hourly - paid at hourly rate for hrs worked
Declaration: The File "EMPLOYEE.H"
// EMPLOYEE.H // Declarations for class Employee and its derived classes. Class Employee has two directly // derived subclasses, Temporary (employees who work on an hourly // basis and get no company // benefits) and Permanent. Permanent employees (all of whom have a benefit deduction) are // further subdivided into Hourly and Salaried classes. #ifndef _EMPLOYEE_H #define _EMPLOYEE_H class Employee // the information common to all employees { public: virtual void PrintCheck()=0; // a virtual function that will be implemented for each derived class protected: // accessible to derived classes only float netPay; Employee(); // default constructor Employee(char* n, char* a, char* ssn); // constructor with parameters char name[30]; char address[80]; char socSecNumber[9]; }; class Temporary: public Employee { public: // Public so that they can be invoked from main() Temporary(char* n, char* a, char* ssn, float hw, float hr); Temporary(); void PrintCheck(); private: // Temporary is an Employee with ... float hoursWorked; // a number of hours worked, and float hourlyRate; // an hourly rate of pay }; class Permanent: public Employee { // This is public so that it can be initialized externally public: // Permanent is an Employee with ... static float benefitDeduction; // a fixed deduction for benefits // All is protected so that it is only accessible to derived classes protected: Permanent(char* n, char* a, char* ssn); Permanent(); void PrintCheck()=0; // redeclared as virtual, to be implmented // in further derived classes }; class Hourly: public Permanent { public: // These must be public so that we can use them in main() Hourly(char* n, char* a, char* ssn, float hw, float hr); Hourly(); void PrintCheck(); private: // Hourly is a Permanent with ... float hoursWorked; // a number of hours worked, and float hourlyRate; // an hourly rate }; class Salaried: public Permanent { public: // These must be public so that we can use them in main() Salaried(char* n, char* a, char* ssn, float wp); Salaried(); void PrintCheck(); private: // Salaried is a Permanent with ... float weeklyPay; // a weekly salary }; #endif // EMPLOYEE.CPP // Definition file for class Employee and its derived classes. #include <iostream.h> //for cin, cout #include <string.h> //for strcmp #include "EMPLOYEE.H" //for Employee declarations float Permanent::benefitDeduction=100.00; // define static variable from class Permanent Employee::Employee() // The default constructor for class Employee solicits from the // standard input (keyboard) values for the data common to all employees. { cout << "\nType employee name, followed by <Enter>: "; cin >> name; cout << "\nType employee address, followed by <Enter>: "; cin >> address; cout << "\nType employee social security number, followed by <Enter>: "; cin >> socSecNumber; }; Employee::Employee(char* n, char* a, char* ssn) // This constructor is used when any kind of employee object is created with supplied parameters. { strcpy(name,n); strcpy(address,a); strcpy(socSecNumber,ssn); }; Temporary::Temporary() // This is the default constructor for a Temporary employee. It solicits // values from the user for the hours worked and hourly rate. { cout << "\nType number of hours worked, followed by <Enter>: "; cin >> hoursWorked; cout << "\nType hourly rate, followed by <Enter>: "; cin >> hourlyRate; }; Temporary::Temporary(char* n, char* a, char* ssn, float hw, float hr) : Employee(n, a, ssn) // This is the constructor for Temporaries declared with parameters. // It invokes the Employee constructor to retrieve the basic employee data. { hoursWorked=hw; hourlyRate=hr; }; void Temporary::PrintCheck() // Calculates the pay for a Temporary, invokes the Employee printCheck // function to display the basics, and fills in the rest of the check. { netPay = hoursWorked * hourlyRate; cout << "\n\n________________________________________________________"; cout << "\n\nPAY TO THE ORDER OF: " << '\t' << name; cout << "\n\t\t\t" << address; cout << "\n\t\t\t" << socSecNumber << '\n'; cout << "\nEMPLOYEE CLASS: Temporary"; cout << "\n\nHOURS: " << hoursWorked; cout << "\nRATE: " << hourlyRate; cout << "\n\nTHE AMOUNT OF ***************************$" << netPay << '\n'; cout << "\n\n________________________________________________________\n\n"; }; Permanent::Permanent() { // the value of static member benefitDeduction is supplied above } Permanent::Permanent(char* n, char* a, char* ssn) : Employee(n, a, ssn) // The parameterized constructor for Permanent employees merely invokes // the Employee constructor to fill in the rest of the employee data. { // the value of static member benefitDeduction is supplied above } Hourly::Hourly() // The default constructor for Hourly employees. This solicits values // for the number of hours worked and the hourly rate. { cout << "\nType number of hours worked, followed by <Enter>: "; cin >> hoursWorked; cout << "\nType hourly rate, followed by <Enter>: "; cin >> hourlyRate; }; Hourly::Hourly(char* n, char* a, char* ssn, float hw, float hr) : Permanent(n, a, ssn) // The parameterized constructor for Hourly employees. This function first invokes the Permanent // employee constructor (which, in turn, invokes the Employee constructor) to fill in the Permanent // employee data, and then fills in the hourly information from its parameters. { hoursWorked = hw; hourlyRate = hr; }; void Hourly::PrintCheck() // Prints an Hourly employee's check by: calculating the net pay, calling the printCheck function for // Permanent employees, and then printing the rest of the check. { netPay=(hoursWorked*hourlyRate)benefitDeduction; cout << "\n\n________________________________________________________"; cout << "\n\nPAY TO THE ORDER OF: " << '\t' << name; cout << "\n\t\t\t" << address; cout << "\n\t\t\t" << socSecNumber << '\n'; cout << "\nEMPLOYEE CLASS: Hourly"; cout << "\n\nBENEFITS DEDUCTION: " << benefitDeduction; cout << "\nHOURS: " << hoursWorked; cout << "\nRATE: " << hourlyRate; cout << "\n\nTHE AMOUNT OF ***************************$" << netPay << '\n'; cout << "\n\n________________________________________________________\n\n"; }; Salaried::Salaried() // The default constructor for Salaried employees. This function solicits and records a value for the // weekly salary. The other member data for salaried employees is solicited by the constructors // for Permanent and Employee classes, which are invoked implicitly. { cout << "\nType weekly salary, followed by <Enter>: "; cin >> weeklyPay; }; Salaried::Salaried(char* n, char* a, char* ssn, float wp) : Permanent(n, a, ssn) // To construct a Salaried employee using parameters, we explicitly invoke the Permanent // constructor, and then fill in the value for weekly pay. { weeklyPay = wp; }; void Salaried::PrintCheck() // This function calculates the net pay, prints the "Permament" employee // part of the check, and fills in the data for the Salaried employee. { netPay = weeklyPaybenefitDeduction; cout << "\n\n________________________________________________________"; cout << "\n\nPAY TO THE ORDER OF: " << '\t' << name; cout << "\n\t\t\t" << address; cout << "\n\t\t\t" << socSecNumber << '\n'; cout << "\nEMPLOYEE CLASS: Salaried"; cout << "\n\nBENEFITS DEDUCTION: " << benefitDeduction; cout << "\nSALARY: " << weeklyPay; cout << "\n\nTHE AMOUNT OF ***************************$" << netPay << '\n'; cout << "\n\n________________________________________________________\n\n"; }; // PIP8.CPP // Main program to test class Employee and its derived classes. #include <iostream.h> // for cin, cout #include "EMPLOYEE.H" // for Employee classes #include "UTILITY.H" // for SetNumeric, WaitForUser, Terminate #include <conio.h> // for clrscr ***IMPLEMENTATION DEPENDENT*** inline void ClearScreen() {clrscr();}; //***IMPLEMENTATION DEPENDENT*** void main() { ClearScreen(); // Create an array to hold (pointers to) our Employees Employee* pip8Emps[6]; // Creating checks via intitialized declarations and place them in our array cout << "\n\nCreating a temporary employee pay record . . ."; Temporary t("Clipper Decker","Clinton, NY","123456789",40.0,5.25); pip8Emps[0]=&t; WaitForUser(); cout << "\n\nCreating an hourly employee pay record . . ."; Hourly h("Sparky Hirshfield","Deansboro, NY","234567890",30.5,8.50); pip8Emps[1]=&h; WaitForUser(); cout << "\n\nCreating a salaried employee pay record . . ."; Salaried s("Fenton Sugarman","Boston, MA","345678901",500.00); pip8Emps[2]=&s; WaitForUser(); // Creating checks using our interactive constructors, and place them in our array cout << "\n\nEnter data for a temporary employee pay record . . ."; Temporary* tEmp = new Temporary; pip8Emps[3]=tEmp; cout << "\n\nEnter data for an hourly employee pay record . . ."; Hourly* hEmp = new Hourly; pip8Emps[4]=hEmp; cout << "\n\nEnter data for a salaried employee pay record . . ."; Salaried* sEmp = new Salaried; pip8Emps[5]=sEmp; // Set format flags for numeric output SetNumeric(); // Now, print all checks, letting C++ determine the appropriate version of PrintCheck // depending upon the type of the Employee for (int i = 0; i < 6; i++) { ClearScreen(); pip8Emps[i]>PrintCheck(); cout << "\n\n\n"; WaitForUser(); }; Terminate(); };