270 likes | 557 Views
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
E N D
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 type-specific 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, boolisSalaried); boolgetSalaried( ) const; float pay(float hoursWorked) const; protected: bool salaried; };
cManager class cManager::cManager(string theName, float thePayRate, boolisSalaried) : cEmployee(theName, thePayRate) { salaried = isSalaried; } boolcManager::getSalaried( ) const { return salaried; } float cManager::pay(float hoursWorked) const { if (salaried) return payRate; /* else */ return Employee::pay(hoursWorked); }
Using cEmployee & cManager objects • These cEmployee and cManagerclasses can be used as follows • Recall that a cManagerhas 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) cEmployeeempl("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 cEmployee cManager cManager cSupervior cSupervisor
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(inti = 0; i < 3; i++) { cout << animals[i]->name << ": " << animals[i]->talk() << endl; delete animals[i]; } return 0; }