-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path05-polymorphism.tex
More file actions
253 lines (236 loc) · 6.71 KB
/
05-polymorphism.tex
File metadata and controls
253 lines (236 loc) · 6.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
\input{definitions}
\begin{document}
\title{Polymorphism}
\subtitle{Object behavior in different contexts}
\date{\today}
\author{Florian Warg, Max Staff}
\maketitle
\begin{frame}[fragile]
\frametitle{What is polymorphism?}
\begin{itemize}
\item polymorphism is the ability of an object to take on many forms
\item if an object passes more than 1 "is-a" tests, it is considered polymorphic
\item i.e. if a class is derived from another class, its objects are polymorphic
\item \includegraphics{img/polymorph-animal-cat}
\item objects of "Cat" are polymorphic because they are of type "Cat" and "Animal"
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Polymorphism in C++}
\begin{itemize}
\item polymorphism only works with reference types (in all languages)
\begin{lstlisting}[numbers=none]
Cat felix;
felix.purr();
Animal& alsoFelix = felix;
alsoFelix.purr(); // error
felix.getSize(); // OK
\end{lstlisting}
\item felix is a cat and also an animal
\item i.e. felix is polymorphic
\item we can treat felix as a generic animal instead of a cat by using references or pointers
\item now only the "animal" interface is exposed
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Implicit reference casts}
\begin{itemize}
\item the compiler can implicitly cast a reference to a parent-type reference
\item this allows functions to accept multiple types
\begin{lstlisting}[numbers=none]
void printSize(const Animal& animal) {
cout << animal.getSize();
}
Cat felix;
printSize(felix); // OK
\end{lstlisting}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Different behavior}
\begin{itemize}
\item what happens when Cat has a method with the same name
\begin{lstlisting}[numbers=none]
class Animal {
public:
void makeSound() {
cout << "Animal::makeSound()\n"; }
};
class Cat : public Animal {
public:
void makeSound() {
cout << "Cat::makeSound()\n"; }
};
Cat felix;
Animal& alsoFelix = felix;
felix.makeSound(); // Cat::makeSound()
alsoFelix.makeSound(); // Animal::makeSound()
\end{lstlisting}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Overriding methods}
\begin{itemize}
\item a child class can override a method of its parent
\item a method is overridable if it is virtual
\item use \lstinline{override} keyword for compiler checks
\begin{lstlisting}[numbers=none]
class Animal {
public:
virtual void makeSound();
};
class Cat : public Animal {
public:
void makeSound() override {
cout << "Cat::makeSound()\n"; }
};
Cat felix;
Animal& alsoFelix = felix;
felix.makeSound(); // Cat::makeSound()
alsoFelix.makeSound(); // Cat::makeSound()
\end{lstlisting}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Lifetime of basic objects}
\begin{itemize}
\begin{lstlisting}[numbers=none]
struct A {
int i;
string str;
};
\end{lstlisting}
\item construct i
\item construct str
\item call \lstinline{A()}
\item call \lstinline{~A()}
\item destruct str
\item destruct i
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Lifetime with inheritance}
\begin{itemize}
\begin{lstlisting}[numbers=none]
struct A { /* ... */ };
struct B : public A {
int i;
string str;
};
\end{lstlisting}
\item construct A
\item construct i
\item construct str
\item call \lstinline{B()}
\item call \lstinline{~B()}
\item destruct str
\item destruct i
\item destruct A
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{new and delete}
\begin{itemize}
\item consider this primitive implementation of a delete function
\begin{lstlisting}[numbers=none]
delete(T* ptr) {
ptr->~T();
free(ptr);
}
class Parent {};
class Child : public Parent {};
Parent* p = new Child();
delete(p); // what happens here?
\end{lstlisting}
\item our defined delete function behaves like the real keyword
\item since p points to a Parent object, only the parent dtor is invoked
\item we already know how to fix this (-> virtual functions)
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{No more implicit memory leaks}
\begin{itemize}
\begin{lstlisting}[numbers=none]
class Parent {
public:
virtual ~Parent() = default;
};
class Child : public Parent {};
Parent* p = new Child();
delete p;
\end{lstlisting}
\item now the child dtor overrides the parent dtor
\item make sure to have a virtual destructor if you want to derive from a class
\item introducing virtual functions comes with an overhead
\item each class needs a vtable, objects need a vtable pointer
\item when calling functions, virtual dispatch is needed
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Pure virtual functions}
\begin{itemize}
\item pure virtual functions are incomplete virtual functions
\item the implementation has to be provided by a derived class by overriding
\begin{lstlisting}[numbers=none]
struct Parent {
virtual void implementMe() = 0;
};
struct Child : public Parent {
void implementMe() override {
cout << "implemented by child\n";
}
};
\end{lstlisting}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Abstract classes - 1}
\begin{itemize}
\item classes are abstract if they contain at least 1 pure virtual function
\item abstract classes cannot be instantiated
\item however pointers and references are allowed
\begin{lstlisting}[numbers=none]
/* ... */
struct Parent;
struct Child;
Parent p; // error - Parent is abstract
Child c; // ok
Parent& alsoC = c;
alsoC.implementMe();
\end{lstlisting}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Abstract classes - 2}
\begin{itemize}
\item classes can also be made abstract by having a pure virtual destructor
\item however, since every class needs a dtor, we still have to provide one
\begin{lstlisting}[numbers=none]
class Abstract {
public:
virtual ~Abstract() = 0;
};
Abstract::~Abstract() {}
\end{lstlisting}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Interfaces}
\begin{itemize}
\item interfaces are abstract classes that only contain pure virtual functions
\begin{lstlisting}[numbers=none]
struct IMath {
virtual int max(int a, int b) = 0;
virtual int min(int a, int b) = 0;
virtual int square(int x) = 0;
};
class IntMath : public IMath {
public:
int max(int a, int b) override { /* ... */}
int min(int a, int b) override { /* ... */}
int square(int x) override { /* ... */ }
};
\end{lstlisting}
\end{itemize}
\end{frame}
\end{document}