Formal Description - Western Connecticut State University

Download Report

Transcript Formal Description - Western Connecticut State University

Polymorphism
Computer Science I
Introduction
 Modern object-oriented (OO) languages provide 3
capabilities which can improve the design, structure
and reusability of code
 encapsulation
 inheritance
 polymorphism
 Note: You should already have some understanding of
the first two concepts before attempting this material.
Polymorphism
 Also called subtype polymorphism
 The ability of one type, A, to appear as and be used like
another type, B
 The purpose of polymorphism is to implement a style
of programming called message-passing, in which objects
of various types define a common interface of
operations for users
Polymorphism & Inheritance
 In strongly typed languages, polymorphism usually
means that type A somehow derives from type B, or
type C implements an interface that represents type B
 In weakly typed languages types are implicitly
polymorphic
Operator overloading (+, -, *, and /)
 Allows polymorphic treatment of the various numerical
types, each of which have different ranges, bit patterns,
and representations
 A common example is the use of the "+" operator
which allows similar or polymorphic treatment of
numbers (addition), strings (concatenation), and lists
(attachment)
Primary Usage
 The ability of objects belonging to different types to
respond to method, field, or property calls of the same
name, each one according to an appropriate typespecific behavior
 The programmer (and the program) does not have to
know the exact type of the object in advance, and so
the exact behavior is determined at run-time
 Also referred to as late binding or dynamic binding
Primary Usage
 Different objects only need to present a compatible
interface to the clients (calling routines)
 There must be public or internal methods, fields,
events, and properties with the same name and the
same parameter sets in all the superclasses, subclasses
and interfaces
Primary Usage
 Object types may be unrelated, but since they share a
common interface, they are often implemented as
subclasses of the same superclass
 Though not required, it is understood that the different
methods will also produce similar results (for example,
returning values of the same type).
Polymorphism is not …
 … the same as method overloading or method overriding
 Polymorphism is only concerned with the application of specific
implementations to an interface or a more generic base class
 Method overloading refers to methods that have the same name
but different signatures inside the same class
 Method overriding is where a subclass replaces the
implementation of one or more of its parent's methods
 Neither method overloading nor method overriding are by
themselves implementations of polymorphism
Example
 2 types of employees as classes in C++
 cEmployee (a generic employee)
 cManager (a manager)
 Include data
 name
 pay rate
 And functionality
 initialize the employee
 get the employee's fields
 calculate the employee's pay
cEmployee class
class cEmployee {
public:
cEmployee(string theName, float
thePayRate);
string getName( ) const;
float getPayRate( ) const;
float pay(float hoursWorked) const;
protected:
string name; float payRate;
};
cEmployee class
cEmployee::cEmployee(string theName, float thePayRate) {
name = theName;
payRate = thePayRate;
}
string cEmployee::getName( ) const {
return name;
}
float cEmployee::getPayRate( ) const {
return payRate;
}
float cEmployee::pay(float hoursWorked) const {
return hoursWorked * payRate;
}
cManager class
class cManager : public cEmployee {
public:
cManager(string theName, float
thePayRate, bool isSalaried);
bool getSalaried( ) const;
float pay(float hoursWorked) const;
protected:
bool salaried;
};
cManager class
cManager::cManager(string theName, float thePayRate,
: cEmployee(theName, thePayRate)
{
salaried = isSalaried;
}
bool cManager::getSalaried( ) const {
return salaried;
}
float cManager::pay(float hoursWorked) const {
if (salaried)
return payRate;
/* else */
return Employee::pay(hoursWorked);
}
bool isSalaried)
Using cEmployee &
cManager objects
 These cEmployee and cManager classes can be used as follows
 Recall that a cManager has all the methods inherited from cEmployee, like
getName(), new versions for those it overrode, like pay(), plus ones it added,
like getSalaried().
#include "employee.h"
#include "manager.h"
// Print out name and pay (based on 40 hours work)
cEmployee empl("John Burke", 25.0);
cout << "Name: " << empl.getName( ) << endl;
cout << "Pay: " << empl.pay(40.0) << endl;
cManager mgr("Jan Kovacs", 1200.0, true);
cout << "Name: " << mgr.getName( ) << endl;
cout << "Pay: " << mgr.pay(40.0) << endl;
cout << "Salaried: " << mgr.getSalaried( ) << endl;
Why public Inheritance
 Often, we want a derived class that is a “kind of” the
base class
 Deriving a class publicly guarantees this
 All public data and methods from the base class remain
public in the derived class
 Everything that was protected in the base class remains
protected in the derived class
 But, things that were private in the base class are not
directly accessible in the derived class
Why public Inheritance
 There is also private and protected inheritance
 But they do not imply the same kind of reuse as public
inheritance
 With private and protected inheritance, we cannot say
that the derived class is a "kind of" the base class
 Private and protected inheritance represent a different
way of reusing a class
 Public inheritance makes writing generic code easier
Pointer to a Base Class
 A base class pointer can point to either an object of the base class or of any
publicly-derived class
cEmployee *emplP;
if (condition1) {
emplP = new cEmployee(...);
} else if (condition2) {
emplP = new cManager(...);
}
 This allows us, for example, to write one set of code to deal with any kind of
employee
cout << "Name: " << emplP->getName();
cout << "Pay rate: " << emplP->getPayRate();
 Note: Typically, one just needs to write different code only to assign the pointer
to the right kind of object, but not to call methods (as above).
Design issues






We can often write better code using polymorphism, i.e., using public inheritance, base class
pointers (or references), and virtual functions
For example, we were able to write generic code to print any employee's pay
The differences are only in how pay is calculated
Using polymorphism to produce good designs takes thought
For example, suppose we add a new kind of employee, a Supervisor, with one of the following
two choices of where to place the new class in the hierarchy
Which class hierarchy would you choose? Why?
cEmployee
cManager
cSupervisor
cEmployee
cManager
cSupervior
Another Example
 If a Dog is commanded to speak(), it may emit a bark,
while if a Pig is asked to speak(), it may respond with
an oink
 Both inherit speak() from Animal; their subclass
methods override the methods of the superclass
(overriding polymorphism)
 Adding a walk method to Animal would give both Pig
and Dog objects the same walk method
Another Example
 Inheritance combined with polymorphism allows class
B to inherit from class A without having to retain all
features of class A
 It can do some of the things that class A does
differently
 The same "verb" can result in different actions as
appropriate for a specific class
 Calling code can issue the same command to their
superclass or interface and get appropriately different
results from each one
The Code
#include <iostream>
#include <string>
using namespace std;
class Animal
{
public:
Animal(const string& name) : name(name) {}
virtual string talk() = 0;
const string name;
};
class Cat : public Animal
{
public: Cat(const string& name) : Animal(name) {}
virtual string talk() { return "Meow!"; }
};
class Dog : public Animal
{
public: Dog(const string& name) :Animal(name) {}
virtual string talk() { return "Arf! Arf!"; }
};
// prints the following:
//
// Missy: Meow!
// Mr. Mistoffelees: Meow!
// Lassie: Arf! Arf!
// int main()
{
Animal* animals[] =
{
new Cat("Missy"),
new Cat("Mr. Mistoffelees"),
new Dog("Lassie")
};
for(int i = 0; i < 3; i++)
{
cout << animals[i]->name << ": " << animals[i]>talk() << endl;
delete animals[i];
}
return 0;
}