| [ Introduction to OOP ] [ Encapsulation ] [ Objects ] [ More on Objects ] [ Abstract Data Types ] [ Inheritance ] [ Abstract Classes ] [ Templates ] |
7.1 IntroductionAn abstract class is a class that is not fully defined. C++ provides a mechanism that permits the declaration of such classes. An abstract class contains methods that are declared but not implemented. Implementation details are to be filled in by derived classes. The class conveys an idea but the idea itself is not concrete.
Consider the following case where the concept polygon is to be refined. Associated with a "polygon" is the method Area. We do not know what the shape is, i.e. it could be a triangle or a octogon or a rectangle.The above idea can be represented in C++ as
When a virtual method or a function is specified as "= 0", then the class is considered as an abstract class and the functions are called pure virtual functions. The abstract class serves as a guideline for programmers to implement derived classes. When we define a class Rectangle, we simply inherit the class Polygon and define the functions declared as pure virtual functions. It is mandatory to override all the pure virtual functions, or else the derived class is also treated as abstract class.
class Polygon{
private:
float Side;
public:
virtual void SetSide(float) = 0
virtual double Area(float) = 0
};Consider the following:
class Square: public Polygon{
public:
void SetSide(float s) { side = s; }
double Area { return side*side; }
};A minor point to be noted is that prior to the incorporation of pure virtual functions in C++, abstraction was sought through declaring the functions in the base class as virtual and implementing a null body as shown below
This did not stop the programmer from declaring an object of class Polygon. Thus Polygon P; was a valid statement. This drawback has been overcome with the mechanism for pure virtual functions.
class Square{
private:
float Side;
public:
virtual void SetSide(float) { };
virtual double Area { };
};7.2 Manufacturer Example
Consider a class for a computer manufacturer. The components used by various manufacturers differ. A base class is declared and some of its methods are declared to be pure virtual methods.
From this class we can now derive two "concrete" classes.
// An abstract class ComputerManufacturer.
class ComputerManufacturer{
private:
char* HardDiskMan;
char* RAMMan;
char* ProcessorMan;
public:
ComputerManufacturer() {};
virtual void SetHardDisk (void) = 0;
virtual void SetRAM(void) = 0;
virtual void SetProcessor(void) = 0;
void PrintFeatures(void);
};void ComputerManufacturer::PrintFeatures(void){
cout << "Processor manufactured by: " << ProcessorMan << endl;
cout << "Memory manufactured by: " << RAMMan << endl;
cout << "Hard Disk manufactured by: " << HardDiskMan() << endl;
cout << endl;
return;
}
class DellComputer: public ComputerManufacturer{
public:
void SetHardDisk(void) {strcpy(HardDiskMan, "Intel")};
void SetRAM(void) {strcpy(RAMMan, "Texas Instruments")};
void SetProcessor(void){strcpy(ProcessorType, "Intel")};
}class HPComputer: public ComputerManufacturer{
public:
void SetHardDisk(void) {strcpy(HardDiskMan, "Intel")};
void SetRAM(void) {strcpy(RAMSize, "HP")};
void SetProcessor(void){strcpy(ProcessorType, "Motorola")};
}int main(void){
DellComputer D1;
HPComputer H1;
D1.PrintFeatures();
H1.PrintFeatures();
return 0;
}7.3 Employee Example
Consider yet another example of abstract classes. A base class named "Employee" is defined. The derived concrete classes are the Manager who gets paid a fixed weekly salary regardless of the number of hours worked, SalesPerson who gets paid a flat base salary plus a percentage of the sales, and an HourlyWorker who gets paid by the number of hours and receives overtime pay.
Here is the base class Employee.
The WeeklyEarnings function call applies generically to all the employees. The way each employee's earnings are calculated depends on the kind of employee. This is handled in the concrete classes are all derived from the base class Employee. To calculate an employee's earnings the program simply uses a reference to the specific employee and invokes the corresponding earnings function.
#include <iostream.h> class Employee{
public:
Employee (char*, char*);
char* GetFirstName();
char* GetLastName();
virtual double WeeklyEarnings() = 0;
virtual void Print() = 0;
private:
char* FirstName;
char* LastName;
};Employee::Employee(char* first, char* last){
FirstName = new char[strlen(first) + 1];
strcpy(FirstName,first);
LastName = new char[strlen(last) + 1];
strcpy(LastName, last);
}
char* Employee::GetFirstName(){return FirstName;}
char* Employee::GetLastName() {return LastName;}
void Employee::Print(){
cout << FirstName << ' ' << LastName;
}
The public member functions includes a constructor that takes the first and last name as arguments, functions that return first and lastname, a pure virtual earnings function and another pure virtual print function.
Class Manager is derived from the base class Employee with public inheritance.
Another concrete class 'SalesPerson' is derived from the class 'Employee'.
class Manager: public Employee{
public:
Manager (char*, char*, double);
void SetWeeklySalary(double);
virtual double WeeklyEarnings();
virtual void Print();
private:
double WeeklySalary;
};Manager::Manager(char* first, char* last, double salary)
:Employee(first, last){
SetWeeklySalary(salary);
}
void Manager::SetWeeklySalary(double salary){
WeeklySalary = salary;
}
double Manager::WeeklyEarnings(){
return WeeklySalary;
}
void Manager::Print(){
cout << endl << "Manager : " ;
Employee::Print();
}
Class 'HourlyWorker' is also derived from the base class Employee.
class SalesPerson:public Employee{
public:
SalesPerson(char*, char*, double, double, int);
void SetWeeklySalary(double);
void SetCommission (double);
void SetItemQuantity(int);
virtual double WeeklyEarnings();
virtual void Print();
private:
double Salary;
double Commission;
int Quantity;
};SalesPerson::SalesPerson(char* first,char* last,double sal,double com,int qty)
:Employee(first, last){
SetWeeklySalary(sal);
SetCommission(com);
SetItemQuantity(qty);
}void SalesPerson::SetWeeklySalary(double sal){Salary = S;}
void SalesPerson::SetCommission(double com){Commission = C;}
void SalesPerson::SetItemQuantity(int qty){Quantity = Q;}
double SalesPerson::WeeklyEarnings(){
return Salary + Commission*Quantity;
}
void SalesPerson::Print(){
cout << endl << "Sales person : ";
Employee::Print();
}
class HourlyWorker:public Employee{
public:
HourlyWorker(char*, char*, double, double);
void SetWage (double);
void SetHours(double);
virtual double WeeklyEarnings();
virtual void Print();
private:
double Wage;
double Hours;
};HourlyWorker::HourlyWorker(char* first, char* last, double wage, double hrs)
:Employee(first, last){
SetWage(wage); SetHours(hrs);
}
void HourlyWorker::SetWage(double W){Wage = W;}
void HourlyWorker::SetHours(double Hworked){Hours = Hworked;}
double HourlyWorker::WeeklyEarnings(){
if (Hours <= 40)
return Wage*Hours;
else
return 40*Wage + (Hours - 40)*Wage*1.5 ;
}
void HourlyWorker::Print(){
cout << endl << "Hourly worker : ";
Employee::Print();
}
A simple main program is as follows:.
int main(void){
int wait;
Manager M("John", "Smith", 800.00);
M.Print();
cout << " earned $" << M.WeeklyEarnings()<<endl;
SalesPerson S("Sue", "Jones", 200.0, 3.0, 150);
S.Print();
cout << " earned $" << S.WeeklyEarnings()<<endl;
HourlyWorker H("Karen", "Price ", 13.75, 40);
H.Print();
cout << " earned $" << H.WeeklyEarnings()<<endl;
cin >> wait;
return 0;
}The output of the above program is:
Manager : John Smith earned $800
Sales person : Sue Jones earned $650
Hourly worker : Karen Price earned $550References:
1. Deitel & Deitel, 'C++ How to program', second edition, Prentice Hall.
[ Introduction to OOP ] [ Encapsulation ] [ Objects ] [ More on Objects ] [ Abstract Data Types ] [ Inheritance ] [ Abstract Classes ] [ Templates ]