You are on page 1of 10

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

You might also like