What Can You Do With An Abstract Class?: Polymorphic Pointer
What Can You Do With An Abstract Class?: Polymorphic Pointer
Abstract Base Class (ABC) What can you do with an ABC? Pure virtual function Multiple inheritance Virtual Base Class Example Private inheritance Restoring the accessibility of privately inherited interface Inherit from a template class
Abstract Class
In the University database program, Person class exists only to serve as a common base class We can strengthen the abstraction by allowing only derived objects of Person to be created (instantiated). Ex.
class Person { public: Person(); Person(char *name, int age); virtual ~Person(); virtual void display() const = 0; private: char *m_name; int *m_age; };
At least one member function should be declared in such way for Person to be an abstract class
Each of the derived class that need to be instantiated must implement its version of the display() virtual function. Otherwise, the derived class is still an abstract class and can not be instantiated. If Undergraduate, Graduate, and Faculty all implement the display(), function, then you can do this
Person *database[3]; // heterogeneous container database[0] = new Undergraduate("Mary", 18); database[1] = new Graduate("Angela", 25, 6000, "Fairview 2250"); database[2] = new Faculty("Sue", 34, "Fairview 2248", "Professor"); for (int i=0; i<3; i++) database[i]->display();
Person is now an example of an abstract class. Any attempt to define a Person object will fail, i.e.
Person teacher; // compilation error error C2259: 'Person' : cannot instantiate abstract class due to following members: warning C4259: 'void __thiscall Person::display(void) const' :pure virtual function was not defined
ForeignStudent
With abstract classes, you can describe multiple interfaces when viewing/using the object in different environments. An interface specifies a particular role (we specify a role with a set of operations) for an object that provides some particular functions to other objects. An ABC is frequently an adjective, Ex. Printable, Persistent, only specify some properties. A class can have many unrelated abstract specifications. We will discuss this language feature in C++ as multiple inheritance. 7
Printable
Observable
WorkThread
8
Multiple Inheritance
Sometimes an object has IS-A relationships to more than one class. In such cases, multiple inheritance may be appropriate. Consider the following two base classes
class Predator { public: Predator(char *prey, char *habitat); ~Predator(); const char *getPrey() const; const char *getHabitat() const; private: char *m_prey; char *m_habitat; };
Pet
class Pet { public: Pet(char *name, char *habitat); ~Pet(); const char *getName() const; const char *getHabitat() const; private: char *m_name; char *m_habitat; };
9
Cat
Cat::Cat(char *name, char *prey, char *habitat) : Predator(prey, habitat), Pet(name, habitat), m_lives(9) { }
Predator getPrey()
Pet getName()
It is necessary to disambiguate which getHabitat() function we want. In this case, either Predator::getHabitat() or Pet::getHabitat() is a possible candidate.
11
Cat
12
Cat
Cat remains almost the same One critical difference: a virtual base class must be initialized by its most derived class (Cat in this case)
Cat::Cat(char *name, char *prey, char *habitat) : Animal(habitat), Predator(prey, habitat), Pet(name, habitat), m_lives(9) { } Predator::Predator(char *prey, char *habitat) : Animal(habitat) { m_prey = new char[strlen(prey)+1]; used only in m_habitat = new char[strlen(habitat)+1]; Predator predator("a", "b"); }
13
A better solution is to create a virtual base class. A virtual base class is included only once in all derived classes. In the case of Cat, all paths from Animal to Cat must be marked as virtual, but only once.
14
Mix-in Inheritance
Multiple inheritance is sometimes used to combine disparate classes into a single abstraction. This is called mix-in inheritance. Many class libraries combine classes so that all derived classes have access to key functionality. Ex. Persistent Printable
Private Inheritance
Private inheritance
class Student { public: Student(); void setData(char *name, int age); int getAge() const; const char *getName() const; private: char *m_name; int *m_age; }; class Graduate: private Student { public: Graduate(char *name, int age, int stipend); int display() const; private: int m_stipend; };
Base class
The IS-A relationship is true only partially. The mix-in concept is easily abused, ex.
Person Undergraduate Graduate Faculty
15
Office
All public members of Student are private to Graduate. Classes derived from Graduate would be unable to access any elements or services from Student. Private inheritance is equivalent to a HAS-A relationship. Outside client code cannot see any trace of the base class from a derived class object.
16
class Graduate: private Student { public: Graduate(char *name, int age, int stipend); int display() const; private: int m_stipend; };
Student::getName;
You want the class to also return the largest element in the array
template <class type> class NewArray: public Array<type> { public: NewArray(int arraySize); type getLargest(); };
Usage
Graduate graduateStudent("Angela", 25, 6000); cout << graduateStudent.getName();
17
18
Usage
void main() { NewArray<double> array(20); array.insertElement(0, 4.6); array.insertElement(5, 12.6); cout << array.getLargest(); } Output 12.6
19