31
Polymorphism From now on we will use g++!

Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

  • View
    212

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

PolymorphismFrom now on we will use g++!

Page 2: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Example (revisited)

Goal:

• Graphics package

• Handle drawing of different shapes

• Maintain list of shapes

Page 3: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Solution #1

class Shape {public:

enum Type { e_square, e_circle, e_triangle };Shape( Type t, Point center, double width, double height);void draw();double area();…

private:Type m_type;Point m_center;…

};

Page 4: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Solution #1

• This solution gives a nice “wrapping” to the solution we consider in C. (switch command)

Pros:• Simple, directCons:• Adding new shapes requires changing all

procedures that deal with shape.• Require fat interface in order to support all kinds

of shapes.• No type checking. Unsafe!

Page 5: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Solution #2 – different classes

class Square {

public:

void draw();

double area();

};

class Circle {

public:

void draw();

double area();

};

Page 6: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Solution #2 – Discussion

• Each shape has its own implementation

• We can easily add new shapes

However,

• Shapes are different types

• One cannot view them as part of the same class

Page 7: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Solution #3 - Inheritanceclass Shape {public:

void draw();double area();…

};class Square: public Shape

{public:

void draw();double area();…

};

class Circle: public Shape {

public:…void draw();double area();…

};

Page 8: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Solution #3

Now we can write code such as:

Shape* myShapes[2];

myShapes[0] = new Circle();

myShapes[1] = new Square();

What will happen when we callmyShapes[0]->draw();

Lets test … see shapes.cpp.

Page 9: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

What is going on?

When we write:Circle circle;circle.draw();

The compiler calls Circle::draw();

When we write:Shape* p = new Circle();p->draw();

The compiler calls Shape::draw()

Why? *p has type Shape

Page 10: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Class Hierarchyclass Base {public:

…void foo();void bar();…

};

class Derived: public Base{public:

…void bar();…

};

Derived obj;

obj.foo();

• Calls Base::foo()• Derived does not

implement this method

obj.bar();

• Calls Derived::bar()• Two implementations, the

more specific is used

Page 11: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Inheritance & Overloading

• Derived inherits the method foo() from Base. – The inherited class is using methods of the

base class

• Derived overloads the implementation of bar().– This mechanism allows an inherited class to

specialize the implementation.

Page 12: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Static resolution

• How does the compiler determine which method to call?

Static Resolution:

• Based on the type of the variable.– Not the type of the object!

• The compiler finds the most specific implementation of the method, and calls it.

Page 13: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Static resolution Example

Circle* circle = new Circle(1,1,2);

Square* square = new Square(2,2,1);

Shape* myShapes[2];

myShapes[0] = circle;

myShapes[1] = square;

circle->draw(); // Calls Circle::draw()

square->draw(); // Calls Square::draw()

myShapes[0]->draw(); // Calls Shape::draw()

myShapes[1]->draw(); // Calls Shape::draw()

Page 14: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Dynamic Resolution

• This is clearly not what we want to do in this example.

• A more desirable here solution,

Dynamic resolution (Polymorphism):

• Based on the type of the object.

• Determined at run time.

[Java Like!]

Page 15: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Dynamic Resolution Cont

• The virtual keyword states that the method can be overloaded in a dynamic manner.

class Base {public:

…virtual void bar();…

}

class Derived: public Base {public:

…virtual void bar();…

}

Page 16: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Solution #4: dynamic resolution

• Returning to the shapes example, using virtual methods gives the desired result

• See Shapes- virtual.cpp

Page 17: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Virtual Methods

• Class Base defines a virtual method foo() • The resolution of foo() is dynamic in all

subclasses of Base.– If the subclass Derived overloads foo(), then Derived::foo() is called

– If not, Base::foo() is called

[See nested.cpp]

Page 18: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Underneath the Hood: Inheritance

class Base {…

private:double m_x;int m_a;

};class Derived : public Base {…

private:double m_z;

};

class Base a;

class Derived b;

m_x

m_a

m_z

m_x

m_a

a:

b:Base

Page 19: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Pointing to an Inherited Class

class Derived b;

class Base* p = &b;

• When using *p, we treat b as though it was a Base object

• The compiler cannot know if *p is from a derived class or not.

m_x

m_a

m_z

b:

p:

Page 20: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Implementation of Virtual Methods

Possible approach:• If foo() is a virtual method, then each

object has a pointer to the implementation of foo() that it uses

• Essentially the solution we used in our C implementation

Cost: • Each virtual method requires a pointer

Large number of virtual methods waste of memory

Page 21: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Implementation of Virtual Methods

Alternative solution:

• Each object has a pointer to an array of function pointer

• This array points to the appropriate functions

Cost:

• For each class, we store one table

• Each object contains one field that points to the right table

Page 22: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Exampleclass A { public: virtual void f1(); virtual void f2(); int m_a;};

class B: public A { public: virtual void f1(); virtual void f3(); void f4();

int m_b;};… A a1, a2; B b;

class A { public: virtual void f1(); virtual void f2(); int m_a;};

class B: public A { public: virtual void f1(); virtual void f3(); void f4();

int m_b;};… A a1, a2; B b;

void A::f1{ //...};

void A::f1{ //...};

void A::f2{ //...};

void A::f2{ //...};

void B::f1{ //...};

void B::f1{ //...};

VTBLs

A

B

<vtbl>

m_a

a1:

<vtbl>

m_a

m_b

b:

<vtbl>

m_a

a1:

void B::f3{ //...};

void B::f3{ //...};

f1

f2

f3

f1

f2

Page 23: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Virtual - Recap

• Virtual controls whether to use static or dynamic resolution

• Once a method is virtual, it must remain so throughout the hierarchy

• Calling a virtual method is more expensive than standard calls– Two pointers are “chased” to get to the

address of the function.

Page 24: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Destructors & Inheritance

class Base {public:

~Base();};class Derived : public Base {public:

~Derived();};

Base *p = new Derived;…delete p;

Which destructor is called? [see destruct.cpp]

Page 25: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Virtual Destructor

• Destructor is like any other method

• The example uses static resolution, and hence not the intended destructor is called

• To fix that, we need to declare virtual destructor at the base class!

• See destruct-virt.cpp

• Once you declare virtual destructor, derived class must declare a destructor.

Page 26: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Polymorphism & Inheritance

• C++ allows to use class hierarchy to implement polymorphic code.

Points of care:

• Choice of virtual methods.– Run time considerations efficiency.

• Use of virtual destructor for base class!

Page 27: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Shapes & Sizes

Revisiting our example, we writeclass Shape {public:

…virtual ~Shape(); // virtual destructor

virtual void draw(); // virtual methodvirtual double area(); // also…

};

How do we implement Shape::draw() ?

Page 28: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Inheritance & Abstract Classes

• In this example, we never want to deal with objects of type Shape– Shape serves the role of an interface

• All shapes need to be specific shapes that are instances of derived classes of Shape

• How do we enforce this?Simple mechanism:void Shape::draw(){

assert(false); // we should never call this method}

Page 29: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Abstract Classes

• We can specify that Shape::draw() does not exist

class Shape {public:…virtual ~Shape(); // virtual destructor

virtual void draw() = 0; // pure virtualvirtual double area() = 0; // Also…

};

Page 30: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Abstract Classes

• We cannot create objects of a Pure Virtual class

Shape* p; // legal

Shape s; // illegal

Circle c; // legal

p = &c; // legal

p = new Shape; // illegal

Page 31: Polymorphism From now on we will use g++!. Example (revisited) Goal: Graphics package Handle drawing of different shapes Maintain list of shapes

Virtual Methods - Tips

• If you have virtual methods in a class, always declare its destructor virtual!

• Never call virtual methods during construction and destruction! (invalid object state)

• Use virtual methods Duplicate() and Create() for implementing “virtual constructors”.

• Use pure abstract classes to define interfaces.• Use inheritance with care: Be sure that this is

the appropriate solution.