Polymorphism Problems with switch statement Programmer may forget to test all possible cases in a switch. Tracking this down can be time consuming and error prone Solution - use virtual functions (polymorphism) Virtual functions and polymorphic programming can eliminate the need for switch Design and implement systems that are more easily extensible Programs written to generically process objects of all existing classes in a hierarchy Polymorphism Ability for objects of different classes to respond differently to the same function call Base-class pointer (or reference) calls a virtual function - C++ chooses the correct overridden function in object Dynamic binding (late binding ) as opposite to early (static) binding Object's type not needed when compiling virtual functions Accommodate new classes that have been added after compilation Important for ISV s (Independent Software Vendors) who do not wish to reveal source code to their customers Virtual functions The keyword virtual is a function specifier that provides a mechanism to dynamically select at runtime the appropriate member function from among base and derived class functions (polymorphism=many forms ). A base-class pointer (reference) to a derived class object will call the correct draw function If a derived class does not define a virtual function it is inherited from the base class There are two types of virtual functions: virtual double area(); // normal virtual virtual double area() =0; // pure virtual
An example class Instrument { void play() const {cout<< "Instrument::play"<<endl; char* what() const {return"instrument"; class Wind : public Instrument { void play() const {cout<< Wind::play"<<endl; char* what() const {return Wind"; void go(instrument& i) { i.play(); // binding during compilation... Instrument instrument; Wind wind; go(instrument); // play from class Instrument not surprising go(wind); // play from class Instrument why? An example Now using virtual function class Instrument { virtual void play() const {cout<< "Instrument::graj"<<endl; virtual char* what() const {return"instrument"; class Wind : public Instrument { void play() const {cout<< Wind::play"<<endl; char* what() const {return Wind"; void go(instrument& i) { i.play(); Instrument instrument; Wind ourwind; Instrument *demo; demo= &instrument; demo->play(); demo = &ourwind; demo->play(); Instrument instrument; Wind ourwind; Instrument &demo1 = instrument; demo1.play(); Instrument &demo2 = ourwind; demo2.play(); An example Using pointers // play from class Instrument // play from class Wind Using reference // play from class Instrument // play from class Wind
VTABLE Small problem Access specifier from class for which pointer is defined is used class basic { virtual void fun( ); class derived : public basic { virtual void fun( ); basic *pointer1; derived *pointer2; pointer1->fun( ); // O.K. pointer2->fun( ); //? Collection class Point {... virtual void draw(); class Circle: public Point {... virtual void draw(); class Collection { protected: Point ** arr; int size; Collection(int n); void draw() void insert (Point *p, int i); void Collection:draw() { for(int i=0;i<size;i++) if (arr[i]!= 0) arr[i] -> draw();
Abstract classes A pure virtual function is one whose body is undefined. virtual void printname() = 0; derived classes must implement the pure virtual functions (else they will be abstract too!) A pure virtual function is used to defer the implementation decision of the function. A class that has at least one pure virtual function is called an abstract class (normal classes are sometimes called concrete classes). Abstraction is just a design mechanism - a way of deferring design decisions. Abstract classes Typically: the base class in a hierarchy of classes is an abstract class. (Its only there to help the designer start the hierarchy - an abstract class might often contain some data declarations and maybe some methods, but it is never intended to actually be instantiated) An abstract class cannot be used to declare objects (cannot be instantiated). An abstract class can be used to declare pointers that can access objects derived from the abstract base class. Abstract classes //definition of the abstract base class class TwoD { //this is an abstract class virtual double area() const { return 0.0; //pure virtual member function virtual void printname()const = 0; By having any pure virtual member function, this class is declared as abstract.
Virtual - constructors and destructors? Constructors are always dynamic (don t need virtual.) Destructors should be declared virtual (if you delete a derived class through a base pointer.) There can be significant problems if you don t declare destructors virtual and you try to delete through the base pointer. (The wrong memory can be freed up if your classes use malloc or new etc ) We will return to this issue. Overloading & virtual functions Virtual functions provide another way to overload names, and hence another way to provide a form of polymorphism. The same types Binding Overloaded functions never Compilation time Virtual functions always runtime Summary A pure virtual function is a function whose body is undefined. A class having a pure virtual member function is an abstract class. An abstract base class defines the interface for its derived classes but cannot itself be used to declare objects. Polymorphism - the ability for objects of different classes related by inheritance to respond differently to the same message (function call). We can use more elaborate combinations of the access modifier when deriving classes from base classes.
Abstract class class Shape { virtual double area() const { return 0.0; virtual double volume() const { return 0.0; // pure virtual functions overridden in derived classes virtual void printshapename() const = 0; virtual void print() const = 0; Class Point class Point : public Shape { Point( int = 0, int = 0 ); // default constructor void setpoint( int, int ); int getx() const { return x; int gety() const { return y; virtual void printshapename() const { cout << "Point: "; virtual void print() const; private: int x, y; // x and y coordinates of Point Point::Point( int a, int b ) { setpoint( a, b ); void Point::setPoint( int a, int b ) { x = a; y = b; void Point::print() const { cout << '[' << x << ", " << y << ']';
Class Circle class Circle : public Point { Circle( double r = 0.0, int x = 0, int y = 0 ); void setradius( double ); double getradius() const; virtual double area() const; virtual void printshapename() const { cout << "Circle: "; virtual void print() const; private: double radius; // radius of Circle Circle::Circle( double r, int a, int b ) : Point( a, b ) // call base-class constructor {setradius( r ); void Circle::setRadius( double r ) { radius = r > 0? r : 0; double Circle::getRadius() const { return radius; double Circle::area() const { return 3.14159 * radius * radius; void Circle::print() const { Point::print(); cout << "; Radius = " << radius; Class Cylinder class Cylinder : public Circle { // default constructor Cylinder( double h = 0.0, double r = 0.0, int x = 0, int y = 0 ); void setheight( double ); double getheight(); virtual double area() const; virtual double volume() const; virtual void printshapename() const { cout << "Cylinder: "; virtual void print() const; private: double height; // height of Cylinder
Cylinder::Cylinder( double h, double r, int x, int y ) : Circle( r, x, y ) // call base-class constructor { setheight( h ); void Cylinder::setHeight( double h ) { height = h > 0? h : 0; double Cylinder::getHeight() { return height; double Cylinder::area() const { // surface area of Cylinder return 2 * Circle::area() + 2 * 3.14159 * getradius() * height; double Cylinder::volume() const { return Circle::area() * height; void Cylinder::print() const { Circle::print(); cout << "; Height = " << height;