Top Banner
Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class Functions from Derived-Class Objects 10.2.2 Aiming Derived-Class Pointers at Base-Class Objects 10.2.3 Derived-Class Member-Function Calls via Base-Class Pointers 10.2.4 Virtual Functions 10.3 Polymorphism Examples 10.4 Type Fields and switch Structures 10.5 Abstract Classes 10.6 Case Study: Inheriting Interface and Implementation 10.7 Polymorphism, Virtual Functions and Dynamic Binding “Under the Hood” 10.8 Virtual Destructors
71

Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

Dec 22, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

Object-Oriented Programming: Polymorphism

Outline10.1 Introduction10.2 Relationships Among Objects in an Inheritance Hierarchy

10.2.1 Invoking Base-Class Functions from Derived-Class Objects

10.2.2 Aiming Derived-Class Pointers at Base-Class Objects

10.2.3 Derived-Class Member-Function Calls via Base-Class Pointers

10.2.4 Virtual Functions10.3 Polymorphism Examples10.4 Type Fields and switch Structures10.5 Abstract Classes10.6 Case Study: Inheriting Interface and Implementation10.7 Polymorphism, Virtual Functions and Dynamic Binding “Under the Hood”10.8 Virtual Destructors

Page 2: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.1 Introduction

• Polymorphism– “Program in the general”

– Treat objects in same class hierarchy as if all base class

– Virtual functions and dynamic binding• Will explain how polymorphism works

– Makes programs extensible• New classes added easily, can still be processed

• In our examples– Use abstract base class Shape

• Defines common interface (functionality)• Point, Circle and Cylinder inherit from Shape

– Class Employee for a natural example

Page 3: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.2 Relationships Among Objects in an Inheritance Hierarchy

• Previously (Section 9.4),– Circle inherited from Point– Manipulated Point and Circle objects using member

functions

• Now– Invoke functions using base-class/derived-class pointers

– Introduce virtual functions

• Key concept– Derived-class object can be treated as base-class object

• “is-a” relationship

• Base class is not a derived class object

Page 4: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.2.1 Invoking Base-Class Functions from Derived-Class Objects

• Aim pointers (base, derived) at objects (base, derived)– Base pointer aimed at base object

– Derived pointer aimed at derived object• Both straightforward

– Base pointer aimed at derived object• “is a” relationship

– Circle “is a” Point• Will invoke base class functions

– Function call depends on the class of the pointer/handle• Does not depend on object to which it points

• With virtual functions, this can be changed (more later)

Page 5: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

Polymorphism

Polymorphism permits the same function name to invoke one response in objects of a base class and another response in objects of a derived class. This was illustrated by the “print” member function in the point/circle/cylinder class. Since it printed differently for each class.

Page 6: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

class One{ protected: float a; public: One(float = 2); float f1(float); float f2(float); };One::One(float val){ a = val;}float One::f1(float num){ //divides by two

return(num/2);}float One::f2(float num){ //square function return( pow(f1(num),2) ); }

class Two : public One{ public: float f1(float); };float Two::f1(float num){ //divides by three

return(num/3); }

int main(){ One object_1; Two object_2; // call f2() using a base class object call

cout << ”base call ” << object_1.f2(12); // call f2() using a derived class object call

cout << ”derived call is << object_2.f2(12); return 0;}

Base call is 36derived call is 36

This still calls class One::f1and not class Two:: f1

Page 7: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

class One{ protected: float a; public: One(float = 2); float f1(float); float f2(float); };One::One(float val){ a = val;}float One::f1(float num){ //divides by two

return(num/2);}float One::f2(float num){ //square function return( pow(f1(num),2) ); }

class Two : public One{ public: float f1(float); };float Two::f1(float num){ //divides by three

return(num/3); }

int main(){ One object_1; Two object_2; // call f2() using a base class object call

cout << ”base call ” << object_1.f2(12); // call f2() using a derived class object call

cout << ”derived call is << object_2.f2(12); return 0;}

Page 8: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

Virtual Functions

In the previous example, the base class f2()

will always call the base class version of f1() rather than the derived classes override version.

----->want to have the capability to determine which function should be invoked at run time based upon the object type making the call ---->DYNAMIC BINDING vs STATIC BINDING

Page 9: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

Virtual Function

Virtual function specification tells the compiler to create a pointer to a function, but not fill in the value until the function is actually called. Then at run time and based on the object making the call, the appropriate function address is used.

Page 10: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

class One{ protected: float a; public: One(float = 2); virtual float f1(float); float f2(float); };One::One(float val){ a = val;}float One::f1(float num){ return(num/2);}float One::f2(float num){ //square function return( pow(f1(num),2) ); }

class Two : public One{ public: virtual float f1(float); };float Two::f1(float num){ return(num/3); }

int main(){ One object_1; Two object_2; // call f2() using a base class object call

cout << ”base call ” << object_1.f2(12); // call f2() using a derived class object call

cout << ”derived call is << object_2.f2(12); return 0;}

Base call is 36derived call is 16

Page 11: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

Point/Circle/Cylinder Class

All redefine the print function to print different things…..

void Point::print() const { cout << '[' << getX() << ", " << getY() << ']'; } // end function print

void Circle::print() const { cout << "center = "; Point::print(); // invoke Point's print functioncout << "; radius = " << getRadius(); } // end function print

Page 12: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_05.cpp(1 of 3)

1 // Fig. 10.5: fig10_05.cpp

2 // Aiming base-class and derived-class pointers at base-class

3 // and derived-class objects, respectively.4 #include <iostream>5 6 using std::cout;7 using std::endl;8 using std::fixed;9 10 #include <iomanip>11 12 using std::setprecision;13 14 #include "point.h" // Point class definition15 #include "circle.h" // Circle class definition16

17 int main()

18 {19 Point point( 30, 50 );20 Point *pointPtr = 0; // base-class pointer21 22 Circle circle( 120, 89, 2.7 );23 Circle *circlePtr = 0; // derived-class pointer24

Page 13: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_05.cpp(2 of 3)

25 // set floating-point numeric formatting

26 cout << fixed << setprecision( 2 );

27 28 // output objects point and circle29 cout << "Print point and circle objects:"30 << "\nPoint: ";31 point.print(); // invokes Point's print32 cout << "\nCircle: ";33 circle.print(); // invokes Circle's print35 // aim base-class pointer at base-class object and print36 pointPtr = &point; 37 cout << "\n\nCalling print with base-class pointer to " 38 << "\nbase-class object invokes base-class print "39 << "function:\n";40 pointPtr->print(); // invokes Point's print 42 // aim derived-class pointer at derived-class object43 // and print 44 circlePtr = &circle; 45 cout << "\n\nCalling print with derived-class pointer to "46 << "\nderived-class object invokes derived-class "47 << "print function:\n";48 circlePtr->print(); // invokes Circle's print49

Use objects and pointers to call the print function. The pointers and objects are of the same class, so the proper print function is called.

Page 14: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_05.cpp(3 of 3)

50 // aim base-class pointer at derived-class object and print

51 pointPtr = &circle;

52 cout << "\n\nCalling print with base-class pointer to " 53 << "derived-class object\ninvokes base-class print "54 << "function on that derived-class object:\n";55 pointPtr->print(); // invokes Point's print56 cout << endl;57 58 return 0;59 60 } // end main

Aiming a base-class pointer at a derived object is allowed (the Circle “is a” Point). However, it calls Point’s print function, determined by the pointer type. virtual functions allow us to change this.

Page 15: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_05.cppoutput (1 of 1)

Print point and circle objects:

Point: [30, 50]

Circle: center = [120, 89]; radius = 2.70

 

Calling print with base-class pointer to

base-class object invokes base-class print function:

[30, 50]

 

Calling print with derived-class pointer to

derived-class object invokes derived-class print function:

center = [120, 89]; radius = 2.70

 

Calling print with base-class pointer to derived-class object

invokes base-class print function on that derived-class object:

[120, 89]

Page 16: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.2.2 Aiming Derived-Class Pointers at Base-Class Objects

• Previous example– Aimed base-class pointer at derived object

• Circle “is a” Point

• Aim a derived-class pointer at a base-class object– Compiler error

• No “is a” relationship• Point is not a Circle• Circle has data/functions that Point does not

– setRadius (defined in Circle) not defined in Point

– Can cast base-object’s address to derived-class pointer• Called downcasting (more in 10.9)

• Allows derived-class functionality

Page 17: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_06.cpp(1 of 1)

fig10_06.cppoutput (1 of 1)

1 // Fig. 10.6: fig10_06.cpp2 // Aiming a derived-class pointer at a base-class object.3 #include "point.h" // Point class definition4 #include "circle.h" // Circle class definition5

6 int main()

7 {8 Point point( 30, 50 ); 9 Circle *circlePtr = 0; 10 11 // aim derived-class pointer at base-class object 12 circlePtr = &point; // Error: a Point is not a Circle13 14 return 0;15 16 } // end main

C:\cpphtp4\examples\ch10\fig10_06\Fig10_06.cpp(12) : error C2440:

'=' : cannot convert from 'class Point *' to 'class Circle *'

Types pointed to are unrelated; conversion requires

reinterpret_cast, C-style cast or function-style cast

Page 18: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.2.3 Derived-Class Member-Function Calls via Base-Class

Pointers• Handle (pointer/reference)

– Base-pointer can aim at derived-object• But can only call base-class functions

– Calling derived-class functions is a compiler error• Functions not defined in base-class

• Common theme– Data type of pointer/reference determines functions it can

call

Page 19: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_07.cpp(1 of 2)

1 // Fig. 10.7: fig10_07.cpp2 // Attempting to invoke derived-class-only member functions3 // through a base-class pointer.4 #include "point.h" // Point class definition5 #include "circle.h" // Circle class definition6 7 int main()8 {9 Point *pointPtr = 0;10 Circle circle( 120, 89, 2.7 );11 12 // aim base-class pointer at derived-class object13 pointPtr = &circle;14 15 // invoke base-class member functions on derived-class16 // object through base-class pointer17 int x = pointPtr->getX();18 int y = pointPtr->getY();19 pointPtr->setX( 10 );20 pointPtr->setY( 10 );21 pointPtr->print();22

Page 20: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_07.cpp(2 of 2)

23 // attempt to invoke derived-class-only member functions24 // on derived-class object through base-class pointer 25 double radius = pointPtr->getRadius(); 26 pointPtr->setRadius( 33.33 ); 27 double diameter = pointPtr->getDiameter(); 28 double circumference = pointPtr->getCircumference(); 29 double area = pointPtr->getArea(); 30 31 return 0;32 33 } // end main

These functions are only defined in Circle. However, pointPtr is of class Point.

Page 21: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_07.cppoutput (1 of 1)

C:\cpphtp4\examples\ch10\fig10_07\fig10_07.cpp(25) : error C2039: 'getRadius' : is not a member of 'Point'

C:\cpphtp4\examples\ch10\fig10_07\point.h(6) :

see declaration of 'Point'

 

C:\cpphtp4\examples\ch10\fig10_07\fig10_07.cpp(26) : error C2039: 'setRadius' : is not a member of 'Point'

C:\cpphtp4\examples\ch10\fig10_07\point.h(6) :

see declaration of 'Point'

 

C:\cpphtp4\examples\ch10\fig10_07\fig10_07.cpp(27) : error C2039: 'getDiameter' : is not a member of 'Point'

C:\cpphtp4\examples\ch10\fig10_07\point.h(6) :

see declaration of 'Point'

 

C:\cpphtp4\examples\ch10\fig10_07\fig10_07.cpp(28) : error C2039: 'getCircumference' : is not a member of 'Point'

C:\cpphtp4\examples\ch10\fig10_07\point.h(6) :

see declaration of 'Point'

 

C:\cpphtp4\examples\ch10\fig10_07\fig10_07.cpp(29) : error C2039: 'getArea' : is not a member of 'Point'

C:\cpphtp4\examples\ch10\fig10_07\point.h(6) :

see declaration of 'Point'

Page 22: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.2.4 Virtual Functions

• Typically, pointer-class determines functions• virtual functions

– Object (not pointer) determines function called

• Why useful?– Suppose Circle, Triangle, Rectangle derived from Shape

• Each has own draw function

– To draw any shape• Have base class Shape pointer, call draw• Program determines proper draw function at run time

(dynamically)

• Treat all shapes generically

Page 23: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.2.4 Virtual Functions

• Declare draw as virtual in base class– Override draw in each derived class

• Like redefining, but new function must have same signature

– If function declared virtual, can only be overridden• virtual void draw() const;• Once declared virtual, virtual in all derived classes

– Good practice to explicitly declare virtual

• Dynamic binding– Choose proper function to call at run time

– Only (!) occurs off pointer handles• If function called from object, uses that object’s definition

(static binding)

Page 24: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.2.4 Virtual Functions

• Example– Redo Point, Circle example with virtual functions

– Base-class pointer to derived-class object• Will call derived-class function

Page 25: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

point.h (1 of 1)

1 // Fig. 10.8: point.h2 // Point class definition represents an x-y coordinate pair.3 #ifndef POINT_H4 #define POINT_H5 6 class Point {7

8 public:

9 Point( int = 0, int = 0 ); // default constructor10 11 void setX( int ); // set x in coordinate pair12 int getX() const; // return x from coordinate pair13 14 void setY( int ); // set y in coordinate pair15 int getY() const; // return y from coordinate pair16 17 virtual void print() const; // output Point object18 19 private: 20 int x; // x part of coordinate pair21 int y; // y part of coordinate pair22 23 }; // end class Point24 25 #endif

Print declared virtual. It will be virtual in all derived classes.

Page 26: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

circle.h (1 of 1)

1 // Fig. 10.9: circle.h2 // Circle class contains x-y coordinate pair and radius.3 #ifndef CIRCLE_H4 #define CIRCLE_H5 6 #include "point.h" // Point class definition7 8 class Circle : public Point {9 10 public:11 12 // default constructor13 Circle( int = 0, int = 0, double = 0.0 ); 14 15 void setRadius( double ); // set radius16 double getRadius() const; // return radius17 18 double getDiameter() const; // return diameter19 double getCircumference() const; // return circumference20 double getArea() const; // return area21

22 virtual void print() const; // output Circle object23 24 private: 25 double radius; // Circle's radius26 27 }; // end class Circle28 29 #endif

Page 27: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_10.cpp(1 of 3)

1 // Fig. 10.10: fig10_10.cpp2 // Introducing polymorphism, virtual functions and dynamic3 // binding.4 #include <iostream>5 6 using std::cout;7 using std::endl;8 using std::fixed;9 10 #include <iomanip>11 12 using std::setprecision;13 14 #include "point.h" // Point class definition15 #include "circle.h" // Circle class definition16 17 int main()18 {19 Point point( 30, 50 );20 Point *pointPtr = 0;21 22 Circle circle( 120, 89, 2.7 );23 Circle *circlePtr = 0; 24

Page 28: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_10.cpp(2 of 3)

25 // set floating-point numeric formatting26 cout << fixed << setprecision( 2 );27 28 // output objects point and circle using static binding29 cout << "Invoking print function on point and circle "30 << "\nobjects with static binding "31 << "\n\nPoint: ";32 point.print(); // static binding33 cout << "\nCircle: ";34 circle.print(); // static binding35 36 // output objects point and circle using dynamic binding37 cout << "\n\nInvoking print function on point and circle "38 << "\nobjects with dynamic binding";39 40 // aim base-class pointer at base-class object and print41 pointPtr = &point; 42 cout << "\n\nCalling virtual function print with base-class"43 << "\npointer to base-class object"44 << "\ninvokes base-class print function:\n";45 pointPtr->print();46

Page 29: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_10.cpp(3 of 3)

47 // aim derived-class pointer at derived-class48 // object and print 49 circlePtr = &circle; 50 cout << "\n\nCalling virtual function print with "51 << "\nderived-class pointer to derived-class object "52 << "\ninvokes derived-class print function:\n";53 circlePtr->print();54 55 // aim base-class pointer at derived-class object and print56 pointPtr = &circle; 57 cout << "\n\nCalling virtual function print with base-class"58 << "\npointer to derived-class object "59 << "\ninvokes derived-class print function:\n";60 pointPtr->print(); // polymorphism: invokes circle's print61 cout << endl;62 63 return 0;64 65 } // end main

At run time, the program determines that pointPtr is aiming at a Circle object, and calls Circle’s print function. This is an example of polymorphism.

Page 30: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_10.cppoutput (1 of 1)

Invoking print function on point and circle

objects with static binding

 

Point: [30, 50]

Circle: Center = [120, 89]; Radius = 2.70

 

Invoking print function on point and circle

objects with dynamic binding

 

Calling virtual function print with base-class

pointer to base-class object

invokes base-class print function:

[30, 50]

 

Calling virtual function print with

derived-class pointer to derived-class object

invokes derived-class print function:

Center = [120, 89]; Radius = 2.70

 

Calling virtual function print with base-class

pointer to derived-class object

invokes derived-class print function:

Center = [120, 89]; Radius = 2.70

Page 31: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.2.4 Virtual Functions

• Polymorphism– Same message, “print”, given to many objects

• All through a base pointer

– Message takes on “many forms”

• Summary– Base-pointer to base-object, derived-pointer to derived

• Straightforward

– Base-pointer to derived object• Can only call base-class functions

– Derived-pointer to base-object• Compiler error

• Allowed if explicit cast made (more in section 10.9)

Page 32: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.3 Polymorphism Examples

• Examples– Suppose Rectangle derives from Quadrilateral

• Rectangle more specific Quadrilateral• Any operation on Quadrilateral can be done on Rectangle (i.e., perimeter, area)

• Suppose designing video game– Base class SpaceObject

• Derived Martian, SpaceShip, LaserBeam• Base function draw

– To refresh screen• Screen manager has vector of base-class pointers to objects

• Send draw message to each object

• Same message has “many forms” of results

Page 33: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.3 Polymorphism Examples

• Video game example, continued– Easy to add class Mercurian

• Inherits from SpaceObject• Provides own definition for draw

– Screen manager does not need to change code• Calls draw regardless of object’s type• Mercurian objects “plug right in”

• Polymorphism– Command many objects without knowing type

– Extensible programs• Add classes easily

Page 34: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.4 Type Fields and switch Structures

• One way to determine object's class– Give base class an attribute

• shapeType in class Shape

– Use switch to call proper print function

• Many problems– May forget to test for case in switch– If add/remove a class, must update switch structures

• Time consuming and error prone

• Better to use polymorphism– Less branching logic, simpler programs, less debugging

Page 35: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.5 Abstract Classes

• Abstract classes – Sole purpose: to be a base class (called abstract base classes)

– Incomplete• Derived classes fill in "missing pieces"

– Cannot make objects from abstract class• However, can have pointers and references

• Concrete classes– Can instantiate objects

– Implement all functions they define

– Provide specifics

Page 36: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.5 Abstract Classes

• Abstract classes not required, but helpful• To make a class abstract

– Need one or more "pure" virtual functions• Declare function with initializer of 0

virtual void draw() const = 0;

– Regular virtual functions• Have implementations, overriding is optional

– Pure virtual functions• No implementation, must be overridden

– Abstract classes can have data and concrete functions• Required to have one or more pure virtual functions

Page 37: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.5 Abstract Classes

• Abstract base class pointers– Useful for polymorphism

• Application example– Abstract class Shape

• Defines draw as pure virtual function

– Circle, Triangle, Rectangle derived from Shape• Each must implement draw

– Screen manager knows that each object can draw itself

• Iterators (more Chapter 21)– Walk through elements in vector/array

– Use base-class pointer to send draw message to each

Page 38: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.6 Case Study: Inheriting Interface and Implementation

• Make abstract base class Shape– Pure virtual functions (must be implemented)

• getName, print• Default implementation does not make sense

– Virtual functions (may be redefined)• getArea, getVolume

– Initially return 0.0• If not redefined, uses base class definition

– Derive classes Point, Circle, Cylinder

Page 39: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.6 Case Study: Inheriting Interface and Implementation

0.0 0.0 = 0 = 0

0.0 0.0 "Point" [x,y]

r2 0.0 "Circle" center=[x,y]; radius=r

2r2 +2rh r2h "Cylinder"center=[x,y]; radius=r; height=h

getArea printgetNamegetVolume

Shape

Point

Circle

Cylinder

Page 40: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

shape.h (1 of 1)

1 // Fig. 10.12: shape.h2 // Shape abstract-base-class definition.3 #ifndef SHAPE_H4 #define SHAPE_H5 6 #include <string> // C++ standard string class7 8 using std::string;9 10 class Shape {11 12 public:13 14 // virtual function that returns shape area15 virtual double getArea() const;16 17 // virtual function that returns shape volume18 virtual double getVolume() const;19 20 // pure virtual functions; overridden in derived classes21 virtual string getName() const = 0; // return shape name22 virtual void print() const = 0; // output shape 23 24 }; // end class Shape25 26 #endif

Virtual and pure virtual functions.

Page 41: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

shape.cpp (1 of 1)

1 // Fig. 10.13: shape.cpp2 // Shape class member-function definitions.3 #include <iostream>4 5 using std::cout;6 7 #include "shape.h" // Shape class definition8 9 // return area of shape; 0.0 by default10 double getArea() const11 {12 return 0.0;13 14 } // end function getArea15 16 // return volume of shape; 0.0 by default17 double getVolume() const18 {19 return 0.0;20 21 } // end function getVolume

Page 42: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

point.h (1 of 2)

1 // Fig. 10.14: point.h2 // Point class definition represents an x-y coordinate pair.3 #ifndef POINT_H4 #define POINT_H5 6 #include "shape.h" // Shape class definition7 8 class Point : public Shape {9 10 public:11 Point( int = 0, int = 0 ); // default constructor12 13 void setX( int ); // set x in coordinate pair14 int getX() const; // return x from coordinate pair15 16 void setY( int ); // set y in coordinate pair17 int getY() const; // return y from coordinate pair18 19 // return name of shape (i.e., "Point" )20 virtual string getName() const; 21 22 virtual void print() const; // output Point object23

Point only redefines getName and print, since getArea and getVolume are zero (it can use the default implementation).

Page 43: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

point.h (2 of 2)

24 private: 25 int x; // x part of coordinate pair26 int y; // y part of coordinate pair27 28 }; // end class Point29 30 #endif

Page 44: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

point.cpp (1 of 3)

1 // Fig. 10.15: point.cpp2 // Point class member-function definitions.3 #include <iostream>4 5 using std::cout;6 7 #include "point.h" // Point class definition8 9 // default constructor10 Point::Point( int xValue, int yValue )11 : x( xValue ), y( yValue )12 {13 // empty body 14 15 } // end Point constructor16 17 // set x in coordinate pair18 void Point::setX( int xValue )19 {20 x = xValue; // no need for validation21 22 } // end function setX23

Page 45: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

point.cpp (2 of 3)

24 // return x from coordinate pair25 int Point::getX() const26 {27 return x;28 29 } // end function getX30 31 // set y in coordinate pair32 void Point::setY( int yValue )33 {34 y = yValue; // no need for validation35 36 } // end function setY37 38 // return y from coordinate pair39 int Point::getY() const40 {41 return y;42 43 } // end function getY44

Page 46: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

point.cpp (3 of 3)

45 // override pure virtual function getName: return name of Point46 string Point::getName() const47 {48 return "Point";49 50 } // end function getName51 52 // override pure virtual function print: output Point object53 void Point::print() const54 {55 cout << '[' << getX() << ", " << getY() << ']';56 57 } // end function print

Must override pure virtual functions getName and print.

Page 47: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

circle.h (1 of 2)

1 // Fig. 10.16: circle.h2 // Circle class contains x-y coordinate pair and radius.3 #ifndef CIRCLE_H4 #define CIRCLE_H5 6 #include "point.h" // Point class definition7 8 class Circle : public Point {9 10 public:11 12 // default constructor13 Circle( int = 0, int = 0, double = 0.0 ); 14 15 void setRadius( double ); // set radius16 double getRadius() const; // return radius17 18 double getDiameter() const; // return diameter19 double getCircumference() const; // return circumference20 virtual double getArea() const; // return area21 22 // return name of shape (i.e., "Circle")23 virtual string getName() const; 24 25 virtual void print() const; // output Circle object

Page 48: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

circle.h (2 of 2)

26 27 private: 28 double radius; // Circle's radius29 30 }; // end class Circle31 32 #endif

Page 49: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

circle.cpp (1 of 3)

1 // Fig. 10.17: circle.cpp2 // Circle class member-function definitions.3 #include <iostream> 4 5 using std::cout;6 7 #include "circle.h" // Circle class definition8 9 // default constructor10 Circle::Circle( int xValue, int yValue, double radiusValue )11 : Point( xValue, yValue ) // call base-class constructor12 {13 setRadius( radiusValue );14 15 } // end Circle constructor16 17 // set radius 18 void Circle::setRadius( double radiusValue )19 {20 radius = ( radiusValue < 0.0 ? 0.0 : radiusValue );21 22 } // end function setRadius23

Page 50: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

circle.cpp (2 of 3)

24 // return radius 25 double Circle::getRadius() const26 {27 return radius;28 29 } // end function getRadius30 31 // calculate and return diameter32 double Circle::getDiameter() const33 {34 return 2 * getRadius();35 36 } // end function getDiameter37 38 // calculate and return circumference39 double Circle::getCircumference() const40 {41 return 3.14159 * getDiameter();42 43 } // end function getCircumference44

Page 51: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

circle.cpp (3 of 3)

45 // override virtual function getArea: return area of Circle46 double Circle::getArea() const47 {48 return 3.14159 * getRadius() * getRadius();49 50 } // end function getArea51 52 // override virutual function getName: return name of Circle53 string Circle::getName() const54 {55 return "Circle";56 57 } // end function getName58 59 // override virtual function print: output Circle object60 void Circle::print() const61 {62 cout << "center is ";63 Point::print(); // invoke Point's print function64 cout << "; radius is " << getRadius();65 66 } // end function print

Override getArea because it now applies to Circle.

Page 52: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

cylinder.h (1 of 2)

1 // Fig. 10.18: cylinder.h2 // Cylinder class inherits from class Circle.3 #ifndef CYLINDER_H4 #define CYLINDER_H5 6 #include "circle.h" // Circle class definition7 8 class Cylinder : public Circle {9 10 public:11 12 // default constructor13 Cylinder( int = 0, int = 0, double = 0.0, double = 0.0 ); 14 15 void setHeight( double ); // set Cylinder's height16 double getHeight() const; // return Cylinder's height17 18 virtual double getArea() const; // return Cylinder's area 19 virtual double getVolume() const; // return Cylinder's volume20

Page 53: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

cylinder.h (2 of 2)

21 // return name of shape (i.e., "Cylinder" )22 virtual string getName() const; 23 24 virtual void print() const; // output Cylinder25 26 private:27 double height; // Cylinder's height28 29 }; // end class Cylinder30 31 #endif

Page 54: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

cylinder.cpp(1 of 3)

1 // Fig. 10.19: cylinder.cpp2 // Cylinder class inherits from class Circle.3 #include <iostream>4 5 using std::cout;6 7 #include "cylinder.h" // Cylinder class definition8 9 // default constructor10 Cylinder::Cylinder( int xValue, int yValue, double radiusValue, 11 double heightValue ) 12 : Circle( xValue, yValue, radiusValue )13 {14 setHeight( heightValue );15 16 } // end Cylinder constructor17 18 // set Cylinder's height19 void Cylinder::setHeight( double heightValue )20 {21 height = ( heightValue < 0.0 ? 0.0 : heightValue );22 23 } // end function setHeight

Page 55: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

cylinder.cpp(2 of 3)

24 25 // get Cylinder's height26 double Cylinder::getHeight() const27 {28 return height;29 30 } // end function getHeight31 32 // override virtual function getArea: return Cylinder area33 double Cylinder::getArea() const34 {35 return 2 * Circle::getArea() + // code reuse36 getCircumference() * getHeight();37 38 } // end function getArea39 40 // override virtual function getVolume: return Cylinder volume41 double Cylinder::getVolume() const42 {43 return Circle::getArea() * getHeight(); // code reuse44 45 } // end function getVolume46

Page 56: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

cylinder.cpp(3 of 3)

47 // override virtual function getName: return name of Cylinder48 string Cylinder::getName() const49 {50 return "Cylinder";51 52 } // end function getName53 54 // output Cylinder object55 void Cylinder::print() const56 {57 Circle::print(); // code reuse58 cout << "; height is " << getHeight();59 60 } // end function print

Page 57: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_20.cpp(1 of 5)

1 // Fig. 10.20: fig10_20.cpp2 // Driver for shape, point, circle, cylinder hierarchy.3 #include <iostream>4 5 using std::cout;6 using std::endl;7 using std::fixed;8 9 #include <iomanip>10 11 using std::setprecision;12 13 #include <vector>14 15 using std::vector;16 17 #include "shape.h" // Shape class definition18 #include "point.h" // Point class definition 19 #include "circle.h" // Circle class definition 20 #include "cylinder.h" // Cylinder class definition21 22 void virtualViaPointer( const Shape * ); 23 void virtualViaReference( const Shape & );24

Page 58: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_20.cpp(2 of 5)

25 int main()26 {27 // set floating-point number format28 cout << fixed << setprecision( 2 );29 30 Point point( 7, 11 ); // create a Point31 Circle circle( 22, 8, 3.5 ); // create a Circle32 Cylinder cylinder( 10, 10, 3.3, 10 ); // create a Cylinder33 34 cout << point.getName() << ": "; // static binding35 point.print(); // static binding36 cout << '\n';37 38 cout << circle.getName() << ": "; // static binding39 circle.print(); // static binding40 cout << '\n';41 42 cout << cylinder.getName() << ": "; // static binding43 cylinder.print(); // static binding44 cout << "\n\n";45

Page 59: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_20.cpp(3 of 5)

46 // create vector of three base-class pointers47 vector< Shape * > shapeVector( 3 ); 48 49 // aim shapeVector[0] at derived-class Point object50 shapeVector[ 0 ] = &point; 51 52 // aim shapeVector[1] at derived-class Circle object53 shapeVector[ 1 ] = &circle; 54 55 // aim shapeVector[2] at derived-class Cylinder object56 shapeVector[ 2 ] = &cylinder; 57 58 // loop through shapeVector and call virtualViaPointer59 // to print the shape name, attributes, area and volume 60 // of each object using dynamic binding61 cout << "\nVirtual function calls made off "62 << "base-class pointers:\n\n";63 64 for ( int i = 0; i < shapeVector.size(); i++ ) 65 virtualViaPointer( shapeVector[ i ] ); 66

Create a vector of generic Shape pointers, and aim them at various objects.

Function virtualViaPointer calls the virtual functions (print, getName, etc.) using the base-class pointers.

The types are dynamically bound at run-time.

Page 60: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_20.cpp(4 of 5)

67 // loop through shapeVector and call virtualViaReference68 // to print the shape name, attributes, area and volume 69 // of each object using dynamic binding70 cout << "\nVirtual function calls made off "71 << "base-class references:\n\n";72 73 for ( int j = 0; j < shapeVector.size(); j++ ) 74 virtualViaReference( *shapeVector[ j ] ); 75 76 return 0;77 78 } // end main79 80 // make virtual function calls off a base-class pointer81 // using dynamic binding 82 void virtualViaPointer( const Shape *baseClassPtr ) 83 { 84 cout << baseClassPtr->getName() << ": "; 85 86 baseClassPtr->print(); 87 88 cout << "\narea is " << baseClassPtr->getArea() 89 << "\nvolume is " << baseClassPtr->getVolume() 90 << "\n\n"; 91 92 } // end function virtualViaPointer 93

Use references instead of pointers, for the same effect.

Call virtual functions; the proper class function will be called at run-time.

Page 61: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_20.cpp(5 of 5)

94 // make virtual function calls off a base-class reference 95 // using dynamic binding 96 void virtualViaReference( const Shape &baseClassRef ) 97 { 98 cout << baseClassRef.getName() << ": "; 99 100 baseClassRef.print(); 101 102 cout << "\narea is " << baseClassRef.getArea() 103 << "\nvolume is " << baseClassRef.getVolume() << "\n\n";104 105 } // end function virtualViaReference

Page 62: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_20.cppoutput (1 of 2)

Point: [7, 11]

Circle: center is [22, 8]; radius is 3.50

Cylinder: center is [10, 10]; radius is 3.30; height is 10.00

 

 

Virtual function calls made off base-class pointers:

 

Point: [7, 11]

area is 0.00

volume is 0.00

 

Circle: center is [22, 8]; radius is 3.50

area is 38.48

volume is 0.00

 

Cylinder: center is [10, 10]; radius is 3.30; height is 10.00

area is 275.77

volume is 342.12

 

 

 

Page 63: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

fig10_20.cppoutput (2 of 2)

Virtual function calls made off base-class references:

 

Point: [7, 11]

area is 0.00

volume is 0.00

Circle: center is [22, 8]; radius is 3.50

area is 38.48

volume is 0.00

 

Cylinder: center is [10, 10]; radius is 3.30; height is 10.00

area is 275.77

volume is 342.12

Page 64: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.7 Polymorphism, Virtual Functions and Dynamic Binding

“Under the Hood”• Polymorphism has overhead

– Not used in STL (Standard Template Library) to optimize performance

• virtual function table (vtable)– Every class with a virtual function has a vtable

– For every virtual function, vtable has pointer to the proper function

– If derived class has same function as base class• Function pointer aims at base-class function

– Detailed explanation in Fig. 10.21

Page 65: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

10.8 Virtual Destructors

• Base class pointer to derived object– If destroyed using delete, behavior unspecified

• Simple fix– Declare base-class destructor virtual

• Makes derived-class destructors virtual

– Now, when delete used appropriate destructor called

• When derived-class object destroyed– Derived-class destructor executes first

– Base-class destructor executes afterwards

• Constructors cannot be virtual

Page 66: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

Another example

• Class shape (xorigin, yorigin, color)• Line (xdestination, ydestination)• circle, (radius)• text (text)

• Menu will print all of the different objects

Page 67: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

Another example of virtual functions

typedef double Coord;

enum Color {Co_red, Co_green, Co_blue};

class Shape {

protected:

Coord xorig;

Coord yorig;

Color co;

public:

Shape(Coord x, Coord y, Color c) : xorig(x), yorig(y), co(c) {}

virtual ~Shape() {}

virtual void draw() = 0; // pure virtual draw() function

};

Page 68: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

class Line : public Shape {

protected:

Coord xdest;

Coord ydest; /* Additional data members needed only for Lines. */

public:

Line(Coord x, Coord y, Color c, Coord xd, Coord yd) : xdest(xd),

ydest(yd), Shape(x, y, c) {} // constructor with base initialization

~Line() {cout << "~Line\n";} // virtual destructor void draw() // virtual draw function

{ cout << "Line" << "(";

cout << xorig << ", " << yorig << ", " << int(co);

cout << ", " << xdest << ", " << ydest; cout << ")\n";

}

};

Page 69: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

class Circle : public Shape {

protected:

Coord rad; // radius of circle

public:

Circle(Coord x, Coord y, Color c, Coord r) : rad(r), Shape(x, y, c) {}

~Circle() {cout << "~Circle\n";} // virtual destructor

void draw() {

cout << "Circle" << "(";

cout << xorig << ", " << yorig << ", " << int(co);

cout << ", " << rad; cout << ")\n";

}

};

Page 70: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

class Text : public Shape {

protected:

char* str; // copy of string

public:

Text(Coord x, Coord y, Color c, const char* s) : Shape(x, y, c)

{ str = new char[strlen(s) + 1];

//assert(str)

strcpy(str, s);

}

~Text() { delete [] str; cout << "~Text\n"; }

void draw() {

cout << "Text" << "(";

cout << xorig << ", " << yorig << ", " << int(co);

cout << ", " << str; cout << ")\n";

}

};

Page 71: Object-Oriented Programming: Polymorphism Outline 10.1 Introduction 10.2 Relationships Among Objects in an Inheritance Hierarchy 10.2.1 Invoking Base-Class.

int main() {

const int N = 5; int i;

Shape* sptrs[N];

sptrs[0] = new Line(0.1, 0.1, Co_blue, 0.4, 0.5);

sptrs[1] = new Line(0.3, 0.2, Co_red, 0.9, 0.75);

sptrs[2] = new Circle(0.5, 0.5, Co_green, 0.3);

sptrs[3] = new Text(0.7, 0.4, Co_blue, "Howdy!");

sptrs[4] = new Circle(0.3, 0.3, Co_red, 0.1);

for (i = 0; i < N; i++) sptrs[i]->draw();

for (i = 0; i < N; i++) delete sptrs[i];

return 0; }

Line(0.1, 0.1, 2, 0.4, 0.5)

Line(0.3, 0.2, 0, 0.9, 0.75)

Circle(0.5, 0.5, 1, 0.3)

Text(0.7, 0.4, 2, Howdy!)

Circle(0.3, 0.3, 0, 0.1)

~Line

~Line

~Circle

~Text

~Circle