Programming for MSc Part II
Part 2: OOP in C++
(e) Polymorphism and Abstract Classes
The Is-A Relationship
 A parent class is its childrens smallest common denominator  Every child must have the parents methods and data objects  Every child is a parent, too, as it shares its properties
Example: #include <iostream> class Parent { public: void print (void) { cout << "Parentprint.\n"; } }; class Child : public Parent { }; void print_parent (Parent &p) { p.print (); } int main (void) { Child c; print_parent (c); return 0; }
// Is also a Parent! // Parent::print() is called
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org>
28
Programming for MSc Part II Part 2: OOP in C++  Polymorphism and Abstract Classes
Static method selection
 Normally method calls are resolved at compilation time  How do is-a relationships handle overwritten methods?
Here the method overwritten by Child will not be called, because the function print parent() only knows about the Parent: #include <iostream> class Parent { public: // Defines the default print() method void print (void) { cout << "Parentprint.\n"; } }; class Child : public Parent { public: // Overwrites the parents print() method void print (void) { cout << Childprint.\n"; } }; void print_parent (Parent &p) { p.print (); } int main (void) { Child c; print_parent (c); return 0; }
// Is also a Parent! // Parent::print() is called
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org>
29
Programming for MSc Part II Part 2: OOP in C++  Polymorphism and Abstract Classes
Dynamic Binding
 In C++, for dynamic binding methods are declared virtual  virtual methods are chosen at runtime  A class with virtual methods needs a virtual Destructor!
Example: #include <iostream> using namespace std; class Parent { public: virtual ~Parent (void) {} virtual void print (void) { cout << "Parent::print()\n"; } }; class Child : public Parent { public: virtual ~Child (void) {} virtual void print (void) { cout << "Child::print()\n"; } }; void print_parent (Parent &p) { p.print (); } int main (void) { Child c; print_parent (c); // Child::print() is called, return 0; // because c is a Child and } // print() is virtual
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org> 30
Programming for MSc Part II Part 2: OOP in C++  Polymorphism and Abstract Classes
Polymorphism
 Dynamic Binding is required for Polymorphism  Polymorphism (Greek, having multiple forms) stands for having dierent behaviours for one method name  In the last example, every child has its own print() method
Example: class Motorcycle { public: virtual void print (void) { cout << "MC\n"; } virtual ~Motorcycle {} }; class SidecarCycle : public Motorcycle { public: virtual void print (void) { cout << "SC\n"; } virtual ~SidecarCycle {} }; void print_cycle (Motorcycle &m) { m.print (); } int main (void) { Motorcycle m; SidecarCycle s; print_cycle (m); // Motorcycle::print () print_cycle (s); // SicecarCycle::print () return 0; }
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org> 31
Programming for MSc Part II Part 2: OOP in C++  Polymorphism and Abstract Classes
Abstract Classes
 Sometimes a class does not represent anything real  Still it may make sense to create such a class  All derived classes will inherit its code, thus the code has to be written only once  We call a class that we cannot create objects of Abstract  For example, there is no concrete vehicle, thus the class Vehicle will be abstract  Concrete derived classes, such as Car or Motorcycle may inherit the code for wheels, seats, engines, ...  Another reason is to get consistent behaviour for same things  A wheel will thus always behave the same  Often most of the work goes into the abstract parent class
Abstract Methods
 An abstract class may not know how a method can be implemented  Still that method must be there  An Abstract Method is declared in a base class and must be implemented by all classes derived from it  Why? The (abstract) base class represents the concept while the derived classes are only the implementations
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org>
32
Programming for MSc Part II Part 2: OOP in C++  Polymorphism and Abstract Classes
Example
IntArray
-ar: int -size: int +IntArray(size:int) +~IntArray() -do_size(): int -do_resize(size:int): void -do_at(pos:int): int -do_to(pos:int,val:int): void
IntStack
+isEmpty(): bool +first(): int +insert(value:int): void
IAStack
-nvals: int +IAStack() +~IAStack()
Such a stack could be created with code like this: IntStack stack = new IAStack (); An alternative implementation could be derived from a List class instead of an IntArray. Applications dont have to know how this stack was implemented, they only know about the abstract class IntStack: void get_element (IntStack &stack); For an implementation in C++, the three methods in IntStack have to be declared virtual. They are most likely also abstract.
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org> 33
Programming for MSc Part II Part 2: OOP in C++  Polymorphism and Abstract Classes
Parent classes as Interfaces
 Another application for abstract classes are interfaces  An interface species one or more properties rather than a complete object  Example: A class Printable may contain not more than a print() method  Every class derived from it now has such a print() method  Think how easy it may get to implement printing on a printer for dierent document types!  An interface may not contain any implementation at all!  In the previous example, the IntStack class is an interface
Abstract Classes and Methods in C++
 In C++, a method is abstract if it is declated virtual and initialized to 0, like this: virtual void foo (void) = 0;  In C++, a class containing one or more abstract methods is automatically an abstract class  The C++ compiler does not allow creating objects from abstract classes
Abstract Classes and Methods in OMT Diagrams In OMT diagrams, italic fonts are used for names of abstract classes or methods.
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org> 34
Programming for MSc Part II Part 2: OOP in C++  Polymorphism and Abstract Classes
A longer example: Dierent document types have dierent properties. Still we may want to use them in the same way (e.g. printing). Also some documents contain multimedia elements, like images (found e.g. in HTML or Word documents). /* Part 1: images in documents */ /* classes for images and lists of images */ class Image { // some methods and data objects }; class ImageList { // some methods and data objects }; /* abstract class for objects that contain * one or more images */ class HasImages { protected: ImageList *images; virtual void setImages (void) = 0; public: HasImages (void); virtual ~HasImages (void); bool hasMore (void); Image *next (void); };
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org> 35
Programming for MSc Part II Part 2: OOP in C++  Polymorphism and Abstract Classes
/* Part 2a: printing */ /* interface for documents that can * be printed */ class Printable { public virtual void print (void) = 0; }; /* Part 2b: different document types */ class TextFile : public printable { public: TextFile (char *name); virtual ~TextFile (void); virtual void print (void); }; class HtmlFile : public TextFile, public HasImages { protected: virtual void setImages (void); public: HtmlFile (char *name); virtual ~HtmlFile (void); virtual void print (void); };
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org>
36
Programming for MSc Part II Part 2: OOP in C++  Polymorphism and Abstract Classes
Using versus Inheritance
 Inheriting public methods can be a problem if they dont t into a concept (e.g. array and queue)  A good alternative can be using an object of that class instead  The decision normally depends on what classes are available  Inheritance is more powerful than using  Using makes hiding of properties easier
Using objects in OMT diagrams
ElemStack
-array: ElemArray -nelems: int +ElemStack() +~ElemStack() +first(): Elem +append(e:Elem): void +isEmpty(): bool
ElemArray
-ar: Elem* -size: int +ElemArray(size:int) +~ElemArray() +at(pos:int): Elem +to(pos:int,val:Elem): void +size(): int +resize(size:int): void
Herbert Martin Dietze <herbert@the-little-red-haired-girl.org>
37