19
1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

Embed Size (px)

Citation preview

Page 1: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

1

Data Structures - CSCI 102

CS102C++ Polymorphism

Prof Tejada

Page 2: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

3

Data Structures - CSCI 102

PolymorphismWhat is polymorphism?

The ability of an object of one type to appear and beused like an object of a different type

Remember our Shape and Triangle classes?Based on inheritance, Triange Is-A Shape so...We can actually pass Triangles around as Shapes!

Triangle t(5,5,15,20);Shape tval = t;Shape &tref = t;Shape *tptr = &t;Shape *tptr2 = new Triangle(1,2,55,62);

You can write very advanced code with polymorphismWrite algorithms & frameworks that manipulate base classCan even write code for subclasses that hasn’t

been realized or designed!

Page 3: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

So what does this code do?

4

Data Structures - CSCI 102

Polymorphism

Triangle t(5,5,15,20);t.print();

Shape tval = t;tval.print();Shape &tref = t;tref.print();Shape *tptr = &t;tptr->print();

It should call the Triangle object’s overloaded print method,right? Does it?

Page 4: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

Even though we can pass around a Triangle as a Shape, itdoesn’t help if we can’t make it call Triangle’s overloadedmethods

5

Data Structures - CSCI 102

Early/Static/Compile-Time Binding

When your code is compiled, the compiler directlyassociates a function call with a memory location tomake function calls a fast lookup

Why does this happen?

Isn’t there some way to tell the compiler to wait untilrun-time to figure out what version of the "print()" functionit should call?

When you compiler sees "s.print()", it immediatelyassociates it with the Shape class

Page 5: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

6space)

Data Structures - CSCI 102

Virtual FunctionsTells the C++ to wait until the code runs to figure out whatversion of a method it should actually call

The keyword virtual tells C++ to find the "most-derived"version of a method (a.k.a. the one farthest down theinheritance tree that’s still relevant)

How is it used?Just add the keyword virtual to the beginning of anyfunction prototype in your classTechnically, you only have to add virtual to thesuperclass method, but it’s good style if you add it to allof the functions that are affected by it

Why not just declare every function virtual?It’s more expensive than normal lookup (time &

Page 6: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

Before we had this:

7

Data Structures - CSCI 102

Virtual Functions

Now we have this instead:

class Shape {...

void print() const;};

class Shape {...

virtual void print() const;};

Page 7: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

It tells C++ that it’s not possible to know what version ofthat particular function to call until run-time

How does the virtual keyword actually work?

8

Data Structures - CSCI 102

Late/Dynamic/Run-Time Binding

The compiler constructs a virtual table for every classthat has a virtual functionEach of these classes stores a hidden pointer to its ownvirtual table

The virtual table provides a run-time lookup for eachclass to know what version of functions to call usingfunction pointers

Page 8: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

If you don’t C++ will only call the superclass destructorand will skip your subclass destructor

If you’re using inheritance, you should ALWAYS make yourbase class’ Destructor virtual

9

Data Structures - CSCI 102

Other "Virtual" Details

Dynamic binding only works for references and pointers!!!Triangle t(5,5,15,20);t.print();

Shape tval = t;tval.print(); //calls Shape’s print()!!!Shape &tref = t;tref.print(); //calls Triangle’s print()Shape *tptr = &t;tptr->print(); //calls Triangle’s print()

Page 9: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

Allows you to reuse a lot of code that works for similarobjects

Why is polymorphism useful?

10

Data Structures - CSCI 102

Polymorphism

Allows you to add new classes to your inheritancehierarchy, but all your existing methods will still workjust fine!

Allows you to construct very sophisticated code that issimple, but powerful

What if we add a new subclass of "Shape"?

Page 10: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

What if there’s a function that the superclass can’t define,but we need the subclasses to define?

11

Data Structures - CSCI 102

Pure Virtual Functions

class Shape {virtual double getArea() const;

};

The problem here is that Shape has no details about how tocalculate an area. Our function would end up lookingsomething like this (not very useful):

double Shape::getArea() const{ return 0; }

Page 11: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

The getArea() function is not meaningful for Shape, but it ismeaningful for all subclasses of Shape

12

Data Structures - CSCI 102

Pure Virtual Functions

Need to make getArea() as a pure virtual functionShape does not need to implement getArea()

All subclasses of shape should be forced to implement adefinition of getArea()class Shape {

virtual double getArea() const = 0;};

Page 12: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

If Shape contains a pure virtual function, it can no longerbe instantiated!

What would happen if you made a Shape object andtried to call getArea()?

What are the consequences of making a function in a classa pure virtual function?

13

Data Structures - CSCI 102

Abstract Base Classes

Shape becomes an abstract base classAny subclass of Shape that doesn’t implement a real

version of getArea() also becomes an abstract base class!If you want to use your derived classes, you MUSToverride the getArea() method

Page 13: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

Here is an example of a function that is implemented usingpolymorphism to maintain flexibility:

14

Data Structures - CSCI 102

Polymorphic Print Function

void printArea(const Shape& s){

cout << "Area = " << s.getArea() << endl;}

What if we decide to add another subclass like Rectangle toour existing inheritance hierarchy?

You won’t need to change printArea()!

Page 14: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

Using the ideas of pure virtual functions and abstract baseclasses you could create a class that has noimplementation at all!

15

Data Structures - CSCI 102

Interface Classes

Very useful for when you want to tell subclasses whatfunctions they must provide, but you don’t want toinfluence their implementation

e.g. "Shape" would become "IShape"

An interface class is a class that contains only pure virtualfunctions

It’s a better/safer way to do multiple inheritance (Javaand C# actually split interface out)

Interface classes usually prefix their name with IActually, it is THE right way to do multiple inheritance

Page 15: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

17

Data Structures - CSCI 102

polymorph_point.h#ifndef POLYMORPH_POINT_H_#define POLYMORPH_POINT_H_

#include <iostream>

class Point{

private:int x;int y;

public:Point(int newx,int newy) : x(newx), y(newy) { }virtual ~Point() { } //A virtual destructor

int getX() const { returnint getY() const { returnvoid setX(int newx) { x =void setY(int newy) { y =

x; }y; }newx; }newy; }

friend std::ostream& operator<<(std::ostream& out,const Point& b);

};

std::ostream& operator<<(std::ostream& out, const Point& b){

out << "(" << b.x << "," << b.y << ")";return out;

}#endif /* POLYMORPH_POINT_H_ */

Page 16: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

18

Data Structures - CSCI 102

polymorph_shape.h#ifndef POLYMORPH_SHAPE_H_#define POLYMORPH_SHAPE_H_

#include "polymorph_point.h"

class Shape{

protected:Point center;

public:Shape(int x,int y): center(x,y){ }//A virtual destructorvirtual ~Shape() { }

Point getCenter() const { return center; }void setCenter(Point p) { center = p; }

//A virtual print functionvirtual void print() const{

std::cout << "Shape located at " << center << std::endl;}

//A pure virtual area calculation functionvirtual double getArea() const = 0;

};

#endif /* POLYMORPH_SHAPE_H_ */

Page 17: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

19

Data Structures - CSCI 102

polymorph_triangle.h#ifndef POLYMORPH_TRIANGLE_H_#define POLYMORPH_TRIANGLE_H_

#include "polymorph_point.h"#include "polymorph_shape.h"

class Triangle : public Shape{

private:int base;int height;

public:Triangle(int b, int h, int x, int y) : Shape(x,y){ base = b; height = h; }

int getBase() const {int getHeight() constvoid setBase(int b) {void setHeight(int h)

return base; }{ return height; }base = b; }{ height = h; }

virtual void print() const{ std::cout << "Triangle located at " << center

<< std::endl; }

virtual double getArea() const{ return(.5*base*height); }

};

#endif /* POLYMORPH_TRIANGLE_H_ */

Page 18: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

20

Data Structures - CSCI 102

polymorph_rectangle.h#ifndef POLYMORPH_RECTANGLE_H_#define POLYMORPH_RECTANGLE_H_

#include "polymorph_point.h"#include "polymorph_shape.h"

class Rectangle : public Shape{

private:int width;int height;

public:Rectangle(int w, int h, int x, int y) : Shape(x,y){ width = w; height = h; }

int getWidth() const { return width; }int getHeight() const { return height; }void setBase(int w) { width = w; }void setHeight(int h) { height = h; }

virtual void print() const{ std::cout << "Rectangle located at " << center

<< std::endl; }

virtual double getArea() const{ return(width*height); }

};

#endif /* POLYMORPH_RECTANGLE_H_ */

Page 19: 1 Data Structures - CSCI 102 CS102 C++ Polymorphism Prof Tejada

Data Structures - CSCI 102

polymorph_main.cpp#include <iostream>#include <string>

#include#include#include#include

"polymorph_point.h""polymorph_shape.h""polymorph_triangle.h""polymorph_rectangle.h"

using namespace std;

void printArea(const Shape& s){

cout << "Area of shape is " << s.getArea() << endl;}

int main(){

Triangle* t = new Triangle(10,10,10,10);printArea(*t);delete t;

Rectangle* r = new Rectangle(10,15,20,25);printArea(*r);delete r;

}

22