220 likes | 357 Vues
This lecture on Object-Oriented Software Development delves into the principles of inheritance and polymorphism, essential concepts in software design. It covers the basics of inheritance, including creating derived classes from base classes, accessing protected data, and managing constructors. The lecture also introduces polymorphism, explaining how derived classes can redefine base class methods, enabling dynamic method binding. Examples, like how specific classes such as Manager and Employee interact, illustrate these concepts practically. Join us to enhance your understanding of these foundational principles in OOP.
E N D
ECE 264Object-Oriented Software Development Instructor: Dr. Honggang Wang Spring 2013 Lecture 18: More on inheritance and Polymorphism
Lecture outline • Announcements / reminders • Monday Session(April 15) re-scheduled to April 17, Wednesday; Due April 19, Friday, by 5:00 pm • Project Demonstration: April 25 and April 30 • Today • Review inheritance basics • Inheritance examples • Polymorphism ECE 264: Lecture 18
Reviewing inheritance • Can take existing code base and • Produce specialized version • Example: Square is a more specific Rectangle • Add extensions • Example: Manager class we discussed last time adds extra data/functionality to Employee • Existing class: base class • New class: derived class • Reuses data/functions from base class • Inherits (almost) everything • Access permissions for base class members set in base class • Any class can be a base class can have hierarchy • Base class can have multiple derived classes ECE 264: Lecture 18
Constructors and Inheritance • Default constructor for a base class is called automatically in the derived class constructor • Ex: Manager() calls Employee() • Will actually traverse inheritance hierarchy, starting at lowest class • If a derived class needs the parameterized constructor of a base class, it must explicitly invoke it in an initialization list • Manager::Manager(string theName, float thePayRate, bool isSalaried): Employee(theName, thePayRate) { salaried = isSalaried; } ECE 264: Lecture 18
Inheritance: Manager methods • How would you write the Manager pay function? • Here’s where we encounter access, reuse issues • Would like to: • Return payRate if salaried • Call Employee function if not salaried ECE 264: Lecture 18
Protected data • Problem: Manager pay function can’t access private data in Employee class • Solution: third type of access specifier: protected • Protected data in a class can be directly accessed by • Functions within that class • Functions within derived classes of that class • Still effectively private data to outside world ECE 264: Lecture 18
Solution: Manager pay function float Manager::pay(float hrsWorked) { if (salaried) return payRate; else return Employee::pay(hrsWorked); } • If Employee data declared protected, not private, can directly access it in Manager function • Explicitly call Employee version of pay function ECE 264: Lecture 18
Inheritance syntax class BClass { protected: int var1; private: int var2; public: BClass(); BClass(int v1, int v2); int sum(); }; class DClass : public BClass { private: int var3; public: DClass(); Dclass(int v1, int v2, int v3); int sum3(); }; • DClass inherits from BClass • Has same data members, functions • Can add additional data • May not have access • protected data are accessible to derived classes • Still private to outside world ECE 264: Lecture 18
Inheritance example class BClass { protected: int var1; private: int var2; public: BClass(); BClass(int v1, int v2); int sum(); }; class DClass : public BClass { private: int var3; public: DClass(); Dclass(int v1, int v2, int v3); int sum3(); }; • What statements in the program below cause errors? int main() { BClass b1(2,3); DClass d1(3,4,5); int a = b1.sum(); int b = d1.sum(); int c = d1.var1; int d = d1.sum3(); int e = b1.sum3(); return 0; } ECE 264: Lecture 18
Polymorphism • Polymorphism: Code/operations behave differently in different contexts • One example: operator overloading • Inheritance-based polymorphism in form of virtual functions • Add virtual to function declaration in .h file • Why use virtual functions? • One benefit of inheritance: code reuse • Another benefit: Can write generic code that works for (hopefully) many specific cases • Take advantage of fact that derived class “is an” object of base class type (with extra/more specific functions) • Virtual functions enable this second benefit ECE 264: Lecture 18
Virtual functions • For example, a base class Animal could have a virtual function eat. • Derived class Fish would implement eat() differently than derived class Wolf • but you can invoke eat() on any class instance referred to as Animal, and get the eat() behavior of the specific derived class • This allows a programmer to process a list of objects of class Animal, telling each in turn to eat (by calling eat()). ECE 264: Lecture 18
Static binding • All methods are, by default, non-virtual methods. Binding of method call is determined by static type of calling object. Example: Employee e1(“John Smith”, 20); Manager m1(“Bob Jones”, 1500, true); e1 = m1; e1.pay(40); //Calls pay() defined in //Employee ECE 264: Lecture 18
Object pointers & inheritance • Dynamic binding: determine type of object at runtime • With inheritance, pointer to base class supports objects of: • Base class type • Derived class type • Pointers also support dynamic binding! • Allows us to write general code using base class pointers ECE 264: Lecture 18
Static vs. dynamic binding • Methods default to non-virtual type of object determines method called • With virtual method, can use dynamic binding if using pointers or references Example: Employee e1(“John Smith”, 20; Manager m1(“Bob Jones”, 1500, true); Employee *ePtr; e1 = m1; ePtr = &m1; e1.pay(40); // Calls pay() defined in // Employee ePtr->pay(40); // Calls pay() defined in // Manager ECE 264: Lecture 18
References and virtual methods • Remember: passing arguments by reference essentially passes pointer • Can use virtual methods on references • Example: float payAnyone(Employee &e, float h) { return e.pay(h); } int main() { Employee e1(“John Smith”, 20; Manager m1(“Bob Jones”, 1500, true); payAnyone(e1, 40); // Calls pay() defined in // Employee payAnyone(m1, 40); // Calls pay() defined in // Manager return 0; } ECE 264: Lecture 18
Virtual functions and member functions • Calling one member function inside another implicitly uses pointers (and therefore dynamic binding) • If f1 is a function of class C • Calling f1 in another class C function is equivalent to: this->f1(); • Example: assume both Employee & Manager have virtual function printPay(float hoursWorked) void Employee::print(float hoursWorked) { cout << “Name: “ << name << endl; cout << “Pay rate: “ << payRate << endl; printPay(hoursWorked); // Uses dynamic // binding; will call // Manager version in // Manager objects } ECE 264: Lecture 18
Destructors and virtual functions • If a class has virtual functions, the destructor should be virtual • Often use pointers with dynamic allocation: Employee *ePtr; char eType = ‘e’; while (eType != ‘x’) { cin >> eType; if (eType == ‘e’) ePtr = new Employee(“John Smith”, 20); else if (eType == ‘m’) ePtr = new Manager(“Bob Jones”, 1500, true); if (ePtr != NULL) ePtr->print(40); delete ePtr; // Needs virtual destructors to ensure // either ~Employee() or ~Manager() is // called correctly ePtr = NULL; } ECE 264: Lecture 18
Example (functions in red are virtual) If we have: Employee e1(“Bob”,25); Manager m1(“Jim”, 40, true); Employee *ePtr; Manager *mPtr; e1 = m1; ePtr = &m1; mPtr = &m1; Which statements are legal? Which function version gets called (for virtual functions)? e1.isSalaried(); m1.getName(); e1.pay(40); ePtr->pay(40); mPtr->print(40); e1.printPay(40); ECE 264: Lecture 18
Example solution If we have: Employee e1(“Bob”,25); Manager m1(“Jim”, 40, true); Employee* ePtr; Manager *mPtr; e1 = m1; ePtr = &m1; mPtr = &m1; Which statements are legal? Which function version gets called (for virtual functions)? e1.isSalaried(); ILLEGAL m1.getName(); calls Manager.getName() e1.pay(40); calls Employee.pay(40) ePtr->pay(40); calls Manager.pay(40) mPtr->print(40); calls Employee.print(40), which calls Manager.printPay(40) e1.printPay(40); calls Employee.printPay(40) ECE 264: Lecture 18
Exam 2 • Average Score: 85 • STD: 8 • Solutions will be uploaded today ECE 264: Lecture 18
Final notes • Next time • Abstract Classes • Acknowledgements: this lecture borrows heavily from lecture slides provided with the following texts: • Deitel & Deitel, C++ How to Program, 8th ed. • Etter & Ingber, Engineering Problem Solving with C++, 2nd ed. ECE 264: Lecture 18