Inheritance & Polymorphism (aka “Object-Oriented Programming”)
description
Transcript of Inheritance & Polymorphism (aka “Object-Oriented Programming”)
![Page 1: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/1.jpg)
• Inheritance
• Initialization & Destruction of Derived Objects
• Protected Members
• Non-public Inheritance
• Virtual Function Implementation
• Virtual Destructors
• Abstract Base Classes and Interfaces
Inheritance & Polymorphism(aka “Object-Oriented Programming”)
![Page 2: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/2.jpg)
Inheritance
• (Public) inheritance implements an “is-a” relationship– access of inherited members doesn’t change– private members of a base class are not
accessible in derived class methods– public inheritance is the default for struct
• Think “substitutability”– a derived object should be able to “stand-in” via a
base pointer– code sharing is just a side effect
• Don’t inherit just for code sharing
![Page 3: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/3.jpg)
• The base class constructor(s) run(s) first– in declaration order, if multiple inheritance– you pass arguments to base class constructors only
through the member initializer list– if the base class has a default constructor, no
explicit initializer is necessary
• Then any member objects are initialized– in declaration order
• Then the derived class constructor runs• Destruction is the reverse of this process
Object InitializationThe Real Story
![Page 4: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/4.jpg)
#include <iostream>using namespace std;
struct A { A() {cout << "A::A()\n";} ~A() {cout << "A::~A()\n";}};
struct B { B() {cout << "B::B()\n";} ~B() {cout << "B::~B()\n";}};
struct C : A { C() {cout << "C::C()\n";} ~C() {cout << "C::~C()\n";} B b;};
int main() { C c;}
A::A()B::B()C::C()C::~C()B::~B()A::~A()
![Page 5: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/5.jpg)
// Using Initializers#include <iostream>using namespace std;
struct A{ A(int i) {cout << "A::A(" << i << ")\n";} ~A() {cout << "A::~A()\n";}};
struct B{ B(int j) {cout << "B::B(" << j << ")\n";} ~B() {cout << "B::~B()\n";}};
struct C : A{ C(int i, int j) : A(i), b(j) { cout << "C::C(" << i << ',' << j << ")\n"; } ~C() {cout << "C::~C()\n";} B b;};
int main(){ C c(1,2);}
![Page 6: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/6.jpg)
A::A(1)B::B(2)C::C(1,2)C::~C()B::~B()A::~A()
![Page 7: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/7.jpg)
• There is a third access specifier - protected– protected members are accessible through
derived objects
• Idiom: Protected Constructors– Used to make a class abstract– An alternative to using pure virtual functions
Protected Members
![Page 8: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/8.jpg)
Non-public Inheritance“Secretly” using an implementation
• Protected Inheritance– Public members in base sub-objects objects are
“downgraded” to protected in derived objects– The base class interface is only exposed to derived
classes
• Private Inheritance– Public and protected members in base sub-objects
objects are “downgraded” to private in derived objects– Known as pure “Implementation Inheritance”
• the interface of the base class is not exposed at all
– Similar to composition, without explicit forwarding
![Page 9: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/9.jpg)
Name Hiding “Gotcha”
• Beware when “overriding” functions in derived classes
• Example: Hide.cpp
![Page 10: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/10.jpg)
Name Lookup Rules
• 1. Find a scope for the name– A class constitutes a scope– A derived class scope is “nested” in the base class’s
scope
• 2. Perform overload resolution in that scope– Pick unambiguous “best fit”
• 3. Check access permission• Examples: Lookup1-3.cpp
![Page 11: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/11.jpg)
A Lookup Oddity?
• Why does the following compile?
#include <iostream>#include <string>
int main(){ std::string s = "hello"; std::cout << s; // Calls std::operator<<(ostream&, const string&); // but I didn’t import or specify it.}
![Page 12: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/12.jpg)
Argument-dependent Lookup (ADL)
• States that when looking for a function, it will search the namespace of the parameter(s) as well
• Since s is in std, it looks in std for operator<<(ostream&, const string&);
• A convenience– “Implicit import”, if you will
• Causes weird problems with templates!
![Page 13: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/13.jpg)
The Goal of OOP
• To treat all objects as base objects• via a pointer-to-base
• But to have their behavior vary automatically• depending on the dynamic type of the object
EmployeeSalariedEmployee
etc.etc.
EmployeeSalariedEmployee
![Page 14: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/14.jpg)
Heterogeneous Collections
int main(){ using namespace std; Employee e("John Hourly",16.50); e.recordTime(52.0); SalariedEmployee e2("Jane Salaried",1125.00); e2.recordTime(1.0); Employee* elist[] = {&e, &e2}; int nemp = sizeof elist / sizeof elist[0]; for (int i = 0; i < nemp; ++i) cout << elist[i]->getName() << " gets " << elist[i]->computePay() << endl;}
John Hourly gets 957Jane Salaried gets 1125
![Page 15: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/15.jpg)
Function Binding
• Determines the code that executes for a functions call
• Static binding occurs at compile time– what we’re used to
• Dynamic binding occurs at run time– what Java and SmallTalk folks are used to– what we want here– determined by the dynamic type of object pointed to
![Page 16: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/16.jpg)
How Virtual Functions Work
vptrnameratetimeWorked
Employee
Employee::computePay()
vtbl for Employee
vptrsalaryGrade
SalariedEmployee
SalariedEmployee::computePay::
vtbl for SalariedEmployee
•Each class has a vtbl (pointers to its virtual functions)•Each object has a vptr (points to its class’s vtbl)
![Page 17: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/17.jpg)
Advantages of Dynamic Binding
• Client code can just deal with the base type (e.g., Employee*)
• Behavior varies transparently according to an object’s dynamic type
• Client code remains unchanged when new derived types are created!
• No “ripple effect” for maintainers
![Page 18: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/18.jpg)
Derived Destructors
• Recall that base class destructors are called automatically when a derived object dies:
struct B{ ~B() {std::cout << "~B\n";}};
struct D : B // public by default{ ~D() {std::cout << "~D\n";}};
int main(){ D d;}
~D~B
![Page 19: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/19.jpg)
Deleting via a Pointer-to-Base
int main(){ B* pb = new D; delete pb;}
~B // Oops! Derived part not destoyed!
![Page 20: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/20.jpg)
Virtual Destructors
• Needed when deleting via a pointer-to-base
struct B{ virtual ~B() {std::cout << "~B\n";}};
int main(){ B* pb = new D; delete pb;}
~D // Fixed!~B
![Page 21: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/21.jpg)
• Destructors can be declared virtual– necessary when a base class pointer or reference refers
to a derived class object– if the destructor is not declared virtual, only the base
class destructor is called– this may cause a memory leak
• Rule: Base classes should always have a virtual destructor
• Rule of Thumb: A class that contains a virtual function should also declare a virtual destructor
Virtual Destructors
![Page 22: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/22.jpg)
Abstract Classes
• Sometimes a base class is just a conceptual entity– a category, or umbrella for related classes– you won’t instantiate any objects of that type
Vehicle
Car Truck Bus
![Page 23: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/23.jpg)
Pure Virtual Functions
• Abstract classes usually have abstract methods:– “Place holder” member functions to be
overridden in derived classes– Don’t need an implementation in the base class
• The presence of such a pure virtual function makes its class abstract
• Append “= 0” to the function’s declaration
![Page 24: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/24.jpg)
Explicit Interfaces
• A grouping of method specifications– Used in COM, CORBA, Java, .NET, good OO design
• Specified with only pure virtual functions in C++• To implement an interface, simply inherit and
provide all member function definitions• The client programs to the interface
– You can change the implementation transparent to the client
• Example: Strategy Design Pattern
![Page 25: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/25.jpg)
Implicit Interfaces
• A set of expected operations– a.k.a. “Duck Typing”
• If they’re there, things just work• If not, compile error• Example: STL Sequences
– Expected interface:• copy constructor• assignment operator• equality operator
• Example: STL Container Adaptors
![Page 26: Inheritance & Polymorphism (aka “Object-Oriented Programming”)](https://reader035.fdocuments.in/reader035/viewer/2022062408/56814437550346895db0d096/html5/thumbnails/26.jpg)
RTTI
• Runtime Type Identification
• The typeid operator– Returns a type_info object– Include <typeinfo>
• Not useful for much– Type name
• For built-in and polymorphic types only