CSE 332: C++Polymorphism
Overview of C++ Polymorphism
⢠Two main kinds of types in C++: native and user-defined
â âUserâ defined types: declared classes, structs, unions
⢠including types provided by the C++ standard libraries
â Native types are âbuilt inâ to the C++ language itself: int, long, float, âŚ
â A typedef creates a new type name for another type (type aliasing)
⢠Public inheritance creates sub-types
â Inheritance only applies to user-defined classes (and structs)
â A publicly derived class is-a subtype of its base class
â Known as âinheritance polymorphismâ
⢠Template parameters also induce a subtype relation
â Known as âinterface polymorphismâ
â Weâll cover how this works in depth, in later sessions
⢠Liskov Substitution Principle (for both kinds of polymorphism)
â if S is a subtype of T, then wherever you need a T you can use an S
2.
CSE 332: C++Polymorphism
⢠Inheritance polymorphism depends on public virtual
member functions in C++
â Base class declares a member function virtual
â Derived class overrides the base classâs definition of the function
⢠Private or protected inheritance creates a form of
encapsulation
â Does not create a substitutable sub-type
â A privately derived class wraps its base class
â The class form of the Adapter Pattern uses this technique
C++ Polymorphism, Continued
3.
CSE 332: C++Polymorphism
Static vs. Dynamic Type
⢠The type of a variable is known
statically (at compile time),
based on its declaration
int i; int * p;
Fish f; Mammal m;
Fish * fp = &f;
⢠However, actual types of
objects aliased by references &
pointers to base classes vary
dynamically (at run-time)
Fish f; Mammal m;
Animal * ap = &f;
ap = &m;
Animal & ar = get_animal();
Animal
Fish Mammal
⢠A base class and its derived
classes form a set of types
type(*ap) ď {Animal, Fish,
Mammal}
typeset(*fp) ď typeset(*ap)
⢠Each type set is open
â More subclasses can be added
4.
CSE 332: C++Polymorphism
Forms of Inheritance
⢠Derived class inherits from base class
⢠Public Inheritance (âis aâ)
â Public part of base class remains public
â Protected part of base class remains protected
⢠Protected Inheritance (âcontains aâ)
â Public part of base class becomes protected
â Protected part of base class remains protected
⢠Private Inheritance (âcontains aâ)
â Public part of base class becomes private
â Protected part of base class becomes private
5.
CSE 332: C++Polymorphism
Public, Protected, Private Inheritance
class A {
public:
int i;
protected:
int j;
private:
int k;
};
Class B : public A {
// ...
};
Class C : protected A {
// ...
};
Class D : private A {
// ...
};
⢠Class A declares 3 variables
â i is public to all users of class A
â j is protected. It can only be used by methods
in class A or its derived classes (+ friends)
â k is private. It can only be used by methods in
class A (+ friends)
⢠Class B uses public inheritance from A
â i remains public to all users of class B
â j remains protected. It can be used by methods
in class B or its derived classes
⢠Class C uses protected inheritance from A
â i becomes protected in C, so the only users of
class C that can access i are the methods of class C
â j remains protected. It can be used by methods
in class C or its derived classes
⢠Class D uses private inheritance from A
â i and j become private in D, so only methods of
class D can access them.
6.
CSE 332: C++Polymorphism
Class and Member Construction Order
class A {
public:
A(int i) :m_i(i) {
cout << "Aâ << endl;}
~A() {cout<<"~A"<<endl;}
private:
int m_i;
};
class B : public A {
public:
B(int i, int j)
: A(i), m_j(j) {
cout << âBâ << endl;}
~B() {cout << â~Bâ << endl;}
private:
int m_j;
};
int main (int, char *[]) {
B b(2,3);
return 0;
};
⢠In the main function, the B
constructor is called on object b
â Passes in integer values 2 and 3
⢠B constructor calls A constructor
â passes value 2 to A constructor via
base/member initialization list
⢠A constructor initializes m_i
â with the passed value 2
⢠Body of A constructor runs
â Outputs âAâ
⢠B constructor initializes m_j
â with passed value 3
⢠Body of B constructor runs
â outputs âBâ
7.
CSE 332: C++Polymorphism
Class and Member Destruction Order
class A {
public:
A(int i) :m_i(i) {
cout << "Aâ << endl;}
~A() {cout<<"~A"<<endl;}
private:
int m_i;
};
class B : public A {
public:
B(int i, int j) :A(i), m_j(j) {
cout << âBâ << endl;}
~B() {cout << â~Bâ << endl;}
private:
int m_j;
};
int main (int, char *[]) {
B b(2,3);
return 0;
};
⢠B destructor called on object b in main
⢠Body of B destructor runs
â outputs â~Bâ
⢠B destructor calls âdestructorâ of m_j
â int is a built-in type, so itâs a no-op
⢠B destructor calls A destructor
⢠Body of A destructor runs
â outputs â~Aâ
⢠A destructor calls âdestructorâ of m_i
â again a no-op
⢠Compare orders of construction and
destruction of base, members, body
â at the level of each class, order of steps
is reversed in constructor vs. destructor
â ctor: base class, members, body
â dtor: body, members, base class
8.
CSE 332: C++Polymorphism
Virtual Functions
class A {
public:
A () {cout<<" A";}
virtual ~A () {cout<<" ~A";}
virtual f(int);
};
class B : public A {
public:
B () :A() {cout<<" B";}
virtual ~B() {cout<<" ~B";}
virtual f(int) override; //C++11
};
int main (int, char *[]) {
// prints "A B"
A *ap = new B;
// prints "~B ~A" : would only
// print "~A" if non-virtual
delete ap;
return 0;
};
⢠Used to support polymorphism
with pointers and references
⢠Declared virtual in a base class
⢠Can override in derived class
â Overriding only happens when
signatures are the same
â Otherwise it just overloads the
function or operator name
⢠More about overloading next lecture
⢠Ensures derived class function
definition is resolved dynamically
â E.g., that destructors farther down the
hierarchy get called
⢠Use final (C++11) to prevent
overriding of a virtual method
⢠Use override (C++11) in
derived class to ensure that the
signatures match (error if not)
9.
CSE 332: C++Polymorphism
Virtual Functions
class A {
public:
void x() {cout<<"A::x";};
virtual void y() {cout<<"A::y";};
};
class B : public A {
public:
void x() {cout<<"B::x";};
virtual void y() {cout<<"B::y";};
};
int main () {
B b;
A *ap = &b; B *bp = &b;
b.x (); // prints "B::x"
b.y (); // prints "B::y"
bp->x (); // prints "B::x"
bp->y (); // prints "B::y"
ap->x (); // prints "A::x"
ap->y (); // prints "B::y"
return 0;
};
⢠Only matter with pointer or reference
â Calls on object itself resolved statically
â E.g., b.y();
⢠Look first at pointer/reference type
â If non-virtual there, resolve statically
⢠E.g., ap->x();
â If virtual there, resolve dynamically
⢠E.g., ap->y();
⢠Note that virtual keyword need not be
repeated in derived classes
â But itâs good style to do so
⢠Caller can force static resolution of a
virtual function via scope operator
â E.g., ap->A::y(); prints âA::yâ
10.
CSE 332: C++Polymorphism
Potential Problem: Class Slicing
⢠Catch derived exception types by reference
⢠Also pass derived types by reference
⢠Otherwise a temporary variable is created
â Loses original exceptionâs âdynamic typeâ
â Results in âthe class slicing problemâ where only the
base class parts and not derived class parts copy
11.
CSE 332: C++Polymorphism
Pure Virtual Functions
class A {
public:
virtual void x() = 0;
virtual void y() = 0;
};
class B : public A {
public:
virtual void x();
};
class C : public B {
public:
virtual void y();
};
int main () {
A * ap = new C;
ap->x ();
ap->y ();
delete ap;
return 0;
};
⢠A is an abstract (base) class
â Similar to an interface in Java
â Declares pure virtual functions (=0)
â May also have non-virtual methods, as well
as virtual methods that are not pure virtual
⢠Derived classes override pure virtual
methods
â B overrides x(), C overrides y()
⢠Canât instantiate an abstract class
â class that declares pure virtual functions
â or inherits ones that are not overridden
â A and B are abstract, can create a C
⢠Can still have a pointer or reference to
an abstract class type
â Useful for polymorphism
12.
CSE 332: C++Polymorphism
Design with Pure Virtual Functions
⢠Pure virtual functions let us
specify interfaces
appropriately
â But let us defer
implementation decisions
until later (subclasses)
⢠As the type hierarchy is
extended, pure virtual
functions are replaced
â By virtual functions that fill in
(and may override) the
implementation details
â Key idea: refinement
Animal
move()=0
Fish
swim()
Mammal
walk()
move()
move()
Bird
Penguin
waddle()
move()
swim()
Sparrow
walk()
move()
fly()
13.
CSE 332: C++Polymorphism
Summary: Tips on Inheritance Polymorphism
⢠A key tension
â Push common code and variables up into base classes
â Make base classes as general as possible
⢠Use abstract base classes to declare interfaces
⢠Use public inheritance to make sets of polymorphic types
⢠Use private or protected inheritance only for encapsulation
⢠Inheritance polymorphism depends on dynamic typing
â Use a base-class pointer (or reference) if you want inheritance
polymorphism of the objects pointed to (or referenced)
â Use virtual member functions for dynamic overriding
⢠Even though you donât have to, label each inherited virtual
(and pure virtual) method âvirtualâ in derived classes
⢠Use final (C++11) to prevent overriding of a virtual method
⢠Use override (C++11) to make sure signatures match