2021/8/8 Polymorphism | Abstract Base Classes
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html 1/9
ICT Home Outline Timeline Notes IPC Notes MySeneca Workshops Assignments Instructor
Software
Development
OOP244
Part E – Polymorphism
Abstract Base Classes
Design polymorphic objects to amplify the reusability of code
Introduce pure virtual functions
Demonstrate a unit test of an interface
“Program to an interface, not an implementation”
(Gamma, Helm, Johnson, Vlissides, 1994).
Pure Virtual Function | Abstract Base Class | Array of Pointers | Unit Testing | Summary | Exercises
Object-oriented languages use interfaces to define the single identifier to multiple meanings that polymorphism provides.
Separating the interface from its various implementations promotes low coupling between the client code and an object’s class
hierarchy. The interface specifies what any object in the hierarchy offers to a client, while each implementation specifies how the
interface provides what it has offered to its clients. This separation of concerns is central to software engineering. The interface
effectively hides the hierarchy from its clients. We can upgrade the hierarchy by adding derived classes without having to change
the client code. We can upgrade the client code without having to change the hierarchy.
C++ supports the distinction between an interface and its implementations through abstract and concrete classes. An abstract class
is a base class that defines an interface, while a concrete class is a derived class that implements that interface. The abstract class
identifies the member functions that the class hierarchy exposes to its clients and is the gateway to testing the derived classes in its
own inheritance hierarchy. Each concrete class gives a specific meaning to the interface.
This chapter describes pure virtual functions, which are the principal components of an abstract base class. The chapter shows
how to define an abstract class and use it with an array of pointers in client code. This chapter concludes with an example of a
unit test on an abstract base class.
PURE VIRTUAL FUNCTION
The principal component of an abstract base class is a pure virtual member function. Pure refers to the lack of any implementation
detail. That is, a pure virtual function is a signature without a definition. The client code only requires access to the signature.
Declaration
The declaration of a pure virtual function takes the form
virtual Type identifier(parameters) = 0;
The assignment to 0 identifies the virtual function as pure. A pure function must be a virtual member function.
Example
We define the pure virtual function for the signature display(std::ostream&) const using
virtual void display(std::ostream&) const = 0;
Implementations
A pure virtual member function typically has multiple definitions within its hierarchy. Each definition has the same signature as
the pure virtual function but a different meaning. That is, it provides the client with the implementation that suits a specific
dynamic type.
Welcome
Notes
Welcome to OO
Object Terminology
Modular Programming
Types Overloading
Dynamic Memory
Member Functions
Construction
Current Object
Member Operators
Class + Resources
Helper Functions
Input Output
Derived Classes
Derived Functions
Virtual Functions
Abstract Classes
Templates
Polymorphism
I/O Refinements
D C + Resources
Standards
Bibliography
Library Functions
ASCII Sequence
Operator Precedence
C++ and C
Workshops
Assignments
Handouts
Practice
Resources
https://ict.senecac.on.ca/
https://ict.senecacollege.ca/~oop244/index.html
http://www.senecacollege.ca/ssos/findwithoutsemester/oop244/sict
https://ict.senecacollege.ca/~oop244/pages/timeline.html
https://ict.senecacollege.ca/~oop244/pages/content/index.html
https://scs.senecac.on.ca/~ipc144/pages/content/index.html
https://my.senecacollege.ca/webapps/portal/frameset.jsp
https://ict.senecacollege.ca/~oop244/dynamic/workshops/index.html
https://ict.senecacollege.ca/~oop244/pages/assignments/index.html
https://ict.senecacollege.ca/~oop244/pages/instructors/index.html
https://ict.senecacollege.ca/~oop244/pages/content/abstr_p.html
https://ict.senecacollege.ca/~oop244/pages/welco.html
https://ict.senecacollege.ca/~oop244/pages/content/index.html
https://ict.senecacollege.ca/~oop244/pages/content/langu.html
https://ict.senecacollege.ca/~oop244/pages/content/objec.html
https://ict.senecacollege.ca/~oop244/pages/content/compi.html
https://ict.senecacollege.ca/~oop244/pages/content/rudim.html
https://ict.senecacollege.ca/~oop244/pages/content/dynam.html
https://ict.senecacollege.ca/~oop244/pages/content/cppst.html
https://ict.senecacollege.ca/~oop244/pages/content/ctors.html
https://ict.senecacollege.ca/~oop244/pages/content/membe.html
https://ict.senecacollege.ca/~oop244/pages/content/overl.html
https://ict.senecacollege.ca/~oop244/pages/content/deepc.html
https://ict.senecacollege.ca/~oop244/pages/content/nonme.html
https://ict.senecacollege.ca/~oop244/pages/content/custo.html
https://ict.senecacollege.ca/~oop244/pages/content/inher.html
https://ict.senecacollege.ca/~oop244/pages/content/dfunc.html
https://ict.senecacollege.ca/~oop244/pages/content/inclu.html
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html
https://ict.senecacollege.ca/~oop244/pages/content/param.html
https://ict.senecacollege.ca/~oop244/pages/content/adhoc.html
https://ict.senecacollege.ca/~oop244/pages/content/basic.html
https://ict.senecacollege.ca/~oop244/pages/content/dclas.html
https://ict.senecacollege.ca/~oop244/pages/content/ansis.html
https://ict.senecacollege.ca/~oop244/pages/content/bibli.html
https://ict.senecacollege.ca/~oop244/pages/content/libraries.html
https://ict.senecacollege.ca/~oop244/pages/content/ascii.html
https://ict.senecacollege.ca/~oop244/pages/content/prece.html
https://ict.senecacollege.ca/~oop244/pages/content/c_cpp.html
https://ict.senecacollege.ca/~oop244/dynamic/workshops/index.html
https://ict.senecacollege.ca/~oop244/pages/assignments/index.html
https://ict.senecacollege.ca/~oop244/pages/handouts/index.html
https://ict.senecacollege.ca/~oop244/pages/practice/index.html
https://ict.senecacollege.ca/~oop244/pages/resources/index.html
2021/8/8 Polymorphism | Abstract Base Classes
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html 2/9
Note that the separation between the client and the hierarchy’s implementation is crisp. The client code does not need any access
to the variety of implementations available within the hierarchy. The implementation code has no access to the client codes that
use the hierarchy.
ABSTRACT CLASSES
An abstract class is a class that contains or inherits a pure virtual function. Because the class provides no implementation(s) for its
pure virtual function(s), the compiler cannot instantiate the class. Any attempt to create an instance of an abstract base class
generates a compiler error.
Definition
The definition of any abstract base class contains or inherits at least one pure virtual member function. The class definition
contains the declaration of the pure virtual function. We call an abstract base class without any data members a pure interface.
Example
Let us define an abstract base class named iPerson for our Person hierarchy and use this class to expose the hierarchy’s
display() function to any client code.
The iPerson.h header file defines our abstract class:
// Abstract Base Class for the Person Hierarchy
// iPerson.h
#include
class iPerson {
public:
virtual void display(std::ostream&) const = 0;
};
We derive our Person hierarchy from this interface. The header file that defines our Person and Student class includes the
header file that defines our abstract base class:
2021/8/8 Polymorphism | Abstract Base Classes
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html 3/9
// Late Binding
// Student.h
#include
#include “iPerson.h”
const int NC = 30;
const int NG = 20;
class Person : public iPerson {
char name[NC+1];
public:
Person();
Person(const char*);
void display(std::ostream&) const;
};
class Student : public Person {
int no;
float grade[NG];
int ng;
public:
Student();
Student(int);
Student(const char*, int, const float*, int);
void display(std::ostream&) const;
};
The class definitions for the Person and Student classes inform the compiler that each concrete class implements its own
version of the display() member function.
ARRAY OF POINTERS
A systematic technique for accessing objects of different dynamic type within the same hierarchy is through an array of pointers of
their static type. The executable code dereferences each pointer at run time based on its object’s dynamic type.
Person Example
The following code demonstrates the use of an array of pointers to Person objects. The objects pointed to by the array elements
may be of differing dynamic type, but are of the same static type. The CreatePerson() global function creates a Person
object and returns its address.
Client Code
The following client code manages Person objects through the array of pointers p. The output generated for the input provided
is listed on the right:
// Array of Pointers
// array_of_pointers.cpp
#include
#include “iPerson.h”
const int NP = 5;
int main() {
iPerson* p[NP];
for (int i = 0; i < NP; i++)
p[i] = nullptr;
int n = 0;
bool quit = false;
do {
iPerson* ptemp = CreatePerson();
if (ptemp != nullptr) {
p[n++] = ptemp;
} else {
quit = true;
}
} while(n < NP && !quit);
Type (0,1,2) : 1
Name: Jane Doe
Type (0,1,2) : 2
Name: Harry
Student Number : 1234
Number of Grades : 3
Grade 1 : 45.6
Grade 2 : 67.8
Grade 3 : 89.5
Type (0,1,2) : 0
2021/8/8 Polymorphism | Abstract Base Classes
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html 4/9
for (int j = 0; j < n; j++) {
p[j]->display(std::cout);
std::cout << std::endl;
}
for (int j = 0; j < n; j++)
delete p[j];
}
Jane Doe
Harry 1234:
45.60
67.80
89.50
Interface
The interface to a Person object includes the prototype for a global function that creates the object:
// Abstract Base Class for the Person Hierarchy
// iPerson.h
#include
class iPerson {
public:
virtual void display(std::ostream&) const = 0;
};
iPerson* CreatePerson();
Concrete Class Definitions
The concrete class definitions specify the various implementations of the iPerson interface:
// Person and Student Concrete Classes
// Student.h
#include “iPerson.h”
const int NC = 30;
const int NG = 20;
class Person : public iPerson {
char name[NC+1];
public:
Person();
Person(const char*);
void display(std::ostream&) const;
};
class Student : public Person {
int no;
float grade[NG];
int ng;
public:
Student();
Student(int);
Student(const char*, int, const float*, int);
void display(std::ostream&) const;
};
iPerson* CreatePerson();
The prototype for CreatePerson() is repeated for documentation.
Implementations
Each concrete class that declares the display() member function in its definition defines its own version of the display()
function. The implementation file also defines the global CreatePerson() function:
// Person Hierarchy – Implementation
// person.cpp
#include
#include
2021/8/8 Polymorphism | Abstract Base Classes
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html 5/9
#include “Student.h”
Person::Person() {
name[0] = ‘\0’;
}
Person::Person(const char* nm) {
std::strncpy(name, nm, NC);
name[NC] = ‘\0’;
}
void Person::display(std::ostream& os) const {
os << name << ' ';
}
Student::Student() {
no = 0;
ng = 0;
}
Student::Student(int n) {
*this = Student("", n, nullptr, 0);
}
Student::Student(const char* nm, int sn, const float* g, int ng_) : Person(nm) {
bool valid = sn > 0 && g != nullptr && ng_ >= 0;
if (valid)
for (int i = 0; i < ng_ && valid; i++)
valid = g[i] >= 0.0f && g[i] <= 100.0f;
if (valid) {
// accept the client's data
no = sn;
ng = ng_ < NG ? ng_ : NG;
for (int i = 0; i < ng; i++)
grade[i] = g[i];
} else {
*this = Student();
}
}
void Student::display(std::ostream& os) const {
if (no > 0) {
Person::display(os);
os << no << ":\n";
os.setf(std::ios::fixed);
os.precision(2);
for (int i = 0; i < ng; i++) {
os.width(6);
os << grade[i] << std::endl;
}
os.unsetf(std::ios::fixed);
os.precision(6);
} else {
os << "no data available" << std::endl;
}
}
iPerson* CreatePerson() {
iPerson* p = nullptr;
int type, no, ng;
float grade[NG];
char name[NC+1];
bool repeat;
do {
std::cout << "Type (0,1,2) : ";
std::cin >> type;
std::cin.ignore();
repeat = false;
switch(type) {
case 0:
break;
case 1:
2021/8/8 Polymorphism | Abstract Base Classes
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html 6/9
std::cout << "Name: ";
std::cin.getline(name, NC+1);
p = new Person(name);
break;
case 2:
std::cout << "Name: ";
std::cin.getline(name, NC+1);
std::cout << "Student Number : ";
std::cin >> no;
std::cout << "Number of Grades : ";
std::cin >> ng;
if (ng > NG) ng = NG;
for (int i = 0; i < ng; i++) {
std::cout << "Grade " << i + 1 << " : ";
std::cin >> grade[i];
std::cin.ignore();
}
p = new Student(name, no, grade, ng);
break;
default:
repeat = true;
std::cout << "Invalid type. Try again\n";
}
} while(repeat);
return p;
}
Multiple definitions would be unnecessary if the definitions of display() were identical.
UNIT TESTS ON AN INTERFACE
Good programming practice suggests that we code unit tests for an interface rather than a specific implementation. This practice
requires that the interface does not change during the life cycle of the software. With a constant interface we can perform unit
tests at every upgrade throughout an object's lifecycle without changing the test code.
Example
To illustrate a unit test on the interface of a hierarchy, consider a module of Sorter classes. The number of implementations
changes throughout the life cycle.
The Sorter module contains all of the implemented algorithms. The interface and the tester module remain unchanged. With
every upgrade to the Sorter module, we execute the unit tester on the interface.
Sorter Module
Each Sorter class sorts in a different way. The interface to the hierarchy exposes the sort() and name() member functions
of each class.
The header file for the interface contains:
// Sorter Interface
// iSorter.h
class iSorter {
public:
virtual void sort(float*, int) = 0;
virtual const char* name() const = 0;
};
iSorter* CreateSorter(int);
int noOfSorters();
The header file for the Sorter concrete classes contains:
// Sorter Concrete Classes
// Sorter.h
2021/8/8 Polymorphism | Abstract Base Classes
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html 7/9
#include "iSorter.h"
class SelectionSorter : public iSorter {
public:
void sort(float*, int);
const char* name() const;
};
class BubbleSorter : public iSorter {
public:
void sort(float*, int);
const char* name() const;
};
iSorter* CreateSorter(int);
int noOfSorters();
The implementation file for the Sorter module defines the sort() and name() member functions for the
SelectionSorter class and the BubbleSorter class as well as the global CreateSorter() and noOfSorters()
functions:
// Sorter Hierarchy - Implementation
// Sorter.cpp
#include "Sorter.h"
void SelectionSorter::sort(float* a, int n) {
int i, j, max;
float temp;
for (i = 0; i < n - 1; i++) {
max = i;
for (j = i + 1; j < n; j++)
if (a[max] > a[j])
max = j;
temp = a[max];
a[max] = a[i];
a[i] = temp;
}
}
const char* SelectionSorter::name() const {
return “Selection Sorter”;
}
void BubbleSorter::sort(float* a, int n) {
int i, j;
float temp;
for (i = n – 1; i > 0; i–) {
for (j = 0; j < i; j++) {
if (a[j] > a[j+1]) {
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
const char* BubbleSorter::name() const {
return “Bubble Sorter”;
}
iSorter* CreateSorter(int i) {
iSorter* sorter = nullptr;
switch (i) {
case 0:
sorter = new SelectionSorter();
break;
case 1:
sorter = new BubbleSorter();
2021/8/8 Polymorphism | Abstract Base Classes
https://ict.senecacollege.ca/~oop244/pages/content/abstr.html 8/9
break;
}
return sorter;
}
int noOfSorters() {
return 2;
}
Unit Tester
The unit tester generates the test data and reports the test results:
// Test Main for the iSorter Interface
// Test_Main.cpp
#include
#include
#include “iSorter.h”
void populate(float* a, int n) {
srand(time(nullptr));
float f = 1.0f / RAND_MAX;
for (int i = 0; i < n; i++)
a[i] = rand() * f;
}
void test(iSorter* sorter, float* a, int n) {
sorter->sort(a, n);
bool sorted = true;
for (int i = 0; i < n - 1; i++)
if (a[i] > a[i+1]) sorted = false;
if (sorted)
std::cout << sorter->name()
<< " is sorted" << std::endl;
else
std::cout << sorter->name()
<< " is not sorted" << std::endl;
}
int main() {
int n;
std::cout << "Enter no of elements : ";
std::cin >> n;
float* array = new float[n];
for (int i = 0; i < noOfSorters(); i++) { iSorter* sorter = CreateSorter(i); populate(array, n); test(sorter, array, n); delete sorter; } delete [] array; } Enter no of elements : 200 Selection Sorter is sorted Bubble Sorter is sorted Note that we do not need to change this test code if we derive another class from the iSorter interface. SUMMARY a pure virtual function is a member function declaration without an implementation an abstract base class contains or inherits at least one pure virtual function an interface is an abstract base class with no data members good programming practice performs unit tests on an interface rather than any specific implementation EXERCISES 2021/8/8 Polymorphism | Abstract Base Classes https://ict.senecacollege.ca/~oop244/pages/content/abstr.html 9/9 Complete the Handout on Abstract Base Classes Complete the Workshop on Pure Virtual Functions print this page Top Previous: Virtual Functions Next: Templates ICT Home Outline Timeline Notes IPC Notes MySeneca Workshops Assignments Instructor Designed by Chris Szalwinski Copying From This Site Last Modified: 05/20/2017 11:50 https://ict.senecacollege.ca/~oop244/pages/handouts/h17.html https://ict.senecacollege.ca/~oop244/pages/workshops/w9.html https://ict.senecacollege.ca/~oop244/pages/content/abstr_p.html https://ict.senecacollege.ca/~oop244/pages/content/inclu.html https://ict.senecacollege.ca/~oop244/pages/content/param.html https://ict.senecac.on.ca/ https://ict.senecacollege.ca/~oop244/index.html http://www.senecacollege.ca/ssos/findwithoutsemester/oop244/sict https://ict.senecacollege.ca/~oop244/pages/timeline.html https://ict.senecacollege.ca/~oop244/pages/content/index.html https://scs.senecac.on.ca/~ipc144/pages/content/index.html https://my.senecacollege.ca/webapps/portal/frameset.jsp https://ict.senecacollege.ca/~oop244/dynamic/workshops/index.html https://ict.senecacollege.ca/~oop244/pages/assignments/index.html https://ict.senecacollege.ca/~oop244/pages/instructors/index.html https://ict.senecacollege.ca/~oop244/pages/copyright.html http://creativecommons.org/licenses/by/2.5/ca/