Skip to content

Commit 6a14d3c

Browse files
author
J-Ragone
committed
class10
1 parent 36cc688 commit 6a14d3c

File tree

1 file changed

+353
-0
lines changed

1 file changed

+353
-0
lines changed

class10.md

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
Class 10
2+
========
3+
4+
## Order of execution
5+
6+
Base class constructors run even without a constructor for the derived class
7+
8+
Constructors run in the order the members appear in the class
9+
10+
### Base class constructors always run
11+
12+
``` cpp
13+
#include <iostream>
14+
using namespace std;
15+
16+
class Base
17+
{
18+
public:
19+
int j;
20+
21+
Base( ) : j( 3 )
22+
{
23+
}
24+
};
25+
26+
class Derived : public Base
27+
{
28+
public:
29+
int k;
30+
};
31+
32+
int main( )
33+
{
34+
Derived d;
35+
cout << d.j << endl; // j = 3
36+
cout << d.k << endl; // k = junk
37+
}
38+
```
39+
40+
``` sh
41+
% derived.exe
42+
3
43+
-858993460
44+
```
45+
46+
``` cpp
47+
#include <iostream>
48+
using namespace std;
49+
class Base2
50+
{
51+
public:
52+
int i;
53+
Base2( int i ) : i( i )
54+
{
55+
cout << “i = " << i << endl;
56+
}
57+
};
58+
59+
class Base3
60+
{
61+
public:
62+
int j;
63+
Base3( int j ) : j( j )
64+
{
65+
cout << "j = " << j << endl;
66+
}
67+
};
68+
69+
class Derived4 : public Base2, Base3
70+
{
71+
public:
72+
Derived4( int j, int i ) :
73+
Base3( j ), Base2( i )
74+
{
75+
cout << "Derived4" << endl;
76+
}
77+
};
78+
79+
int main( )
80+
{
81+
Derived4 d4( 18, 22 );
82+
}
83+
```
84+
85+
``` sh
86+
% order.exe
87+
i = 22
88+
j = 18
89+
Derived4
90+
```
91+
92+
## Derived types
93+
94+
A derived type is used to represent an ***is a*** relationship
95+
96+
A derived type inherits the member functions and member variables of its parent
97+
98+
### Upcast
99+
100+
Permits an object of a subclass type to be treated as an object of any supercalss type
101+
102+
### Downcast
103+
104+
When a variable of the base calss has a value of the derived class, downcasting is possible, which casts a reference of a base class to one of its derived classes
105+
106+
### Benefits of derived classes
107+
108+
#### Interface inheritence
109+
110+
*Save implementation effort by sharing functions provided by the base class*
111+
112+
We can replace any `Triangle` object in a program with an `Isosceles` object and the program will still work
113+
114+
##### Liskov Substitution Principle
115+
116+
***If S is a subtype of T, then objects of
117+
type T may be replaced with objects
118+
of type S***
119+
120+
***Functions that use pointers to base
121+
classes can use objects of derived
122+
classes without knowing it***
123+
124+
This is upcasting
125+
126+
#### Interface inheritence
127+
128+
*Allow different derived classes to be used interchangeably thorugh the interface provided by a common base class*
129+
130+
### Static type
131+
132+
Often, the compiler can tell which derived type is needed
133+
134+
This is called the *static type*
135+
136+
``` cpp
137+
Triangle t( 3, 4, 5 );
138+
t.print( );
139+
140+
Triangle *t_ptr = &t;
141+
t_ptr->print( );
142+
143+
Isosceles i( 1, 12 );
144+
i.print( );
145+
146+
Isosceles *i_ptr = &i;
147+
i_ptr->print( );
148+
```
149+
150+
``` sh
151+
./a.out
152+
Triangle: a=3, b=4, c=5
153+
Triangle: a=3, b=4, c=5
154+
Isosceles: base=1, leg=12
155+
Isosceles: base=1, leg=12
156+
```
157+
158+
### Dynamic type
159+
160+
Other times, the type is not known until run time
161+
162+
This is called the *dynamic type*
163+
164+
#### Example
165+
166+
``` cpp
167+
Triangle * ask_user( );
168+
169+
int main( )
170+
{
171+
Triangle *t = ask_user( ); //enters "Isosceles"
172+
t->print( );
173+
}
174+
```
175+
176+
The static type of `t` is `Triangle *`
177+
178+
The dynamic type of `t` is `Isosceles *`
179+
180+
#### `new`
181+
182+
To create an object that won't go out of scope when the function returns, we use `new`
183+
184+
``` cpp
185+
Triangle *ask_user( )
186+
{
187+
cout << "Triangle, Isosceles "
188+
"or Equilateral?" << endl;
189+
string s;
190+
cin >> s;
191+
192+
if ( s == "Triangle" )
193+
return new Triangle( 3,4,5 );
194+
if ( s == "Isosceles" )
195+
return new Isosceles( 1,12 );
196+
if ( s == "Equilateral" )
197+
return new Equilateral( 5 );
198+
199+
cout << "Unrecognized shape '"
200+
<< s << "'\n";
201+
exit( 1 ); //crash
202+
}
203+
```
204+
205+
Always safe to upcast, so returning `Isosceles` or `Equilateral` is safe
206+
207+
#### `delete`
208+
209+
Always goes together with `new`
210+
211+
``` cpp
212+
int main( )
213+
{
214+
Triangle *t = ask_user( );
215+
//enters "Isosceles"
216+
t->print( );
217+
delete t;
218+
}
219+
```
220+
221+
``` sh
222+
./a.out
223+
Triangle, Isosceles or Equilateral?
224+
Isosceles
225+
Triangle: a=1 b=12 c=12
226+
```
227+
228+
* `t` can change types at runtime, in other words it is ***polymorphic***
229+
* We can use the ***virtual function*** mechanism in C++ to check the *dynamic type* of `t` at runtime and call the correction version of `print()`
230+
231+
### Polymorphism
232+
233+
*The ability to associate many behaviors with one function name*
234+
235+
A polymorphic type is any type with a virtual function
236+
237+
Virtual functions are the C++ mechanism used to implement polymorphism
238+
239+
#### Example
240+
241+
`virtual` means "check the dynamic type at runtime, then select the correct `print( )` member funciton
242+
243+
`virtual` is inherited so the overridden `print( )` in `Isosceles` and `Equilateral` will automatically become `virtual`
244+
245+
``` cpp
246+
class Triangle
247+
{
248+
virtual void print( ) const
249+
{
250+
:
251+
}
252+
:
253+
};
254+
```
255+
256+
Now the orignal program works correctly
257+
258+
``` sh
259+
./a.out
260+
Triangle, Isosceles or Equilateral? Isosceles
261+
Isosceles: base=1 leg=12
262+
```
263+
264+
#### Exercise
265+
266+
`Rectangle` *is a* `Shape`
267+
268+
``` cpp
269+
class Shape
270+
{
271+
public:
272+
virtual double area( ) const {/*...*/}
273+
virtual void print( ) const {/*...*/}
274+
};
275+
class Triangle : public Shape {/*...*/};
276+
class Rectangle : public Shape {/*...*/};
277+
```
278+
279+
Although our code is perfectly legal C++, `Shape` has no member variables, and something like
280+
281+
``` cpp
282+
Shape s;
283+
s.print( );
284+
```
285+
286+
makes no sense and will not compile!
287+
288+
A shape is an abstract idea, and our shape should only be an interface to ensure that all shapes behave the same way
289+
290+
### Abstract class
291+
292+
You cannot create an instance of an abstract class, which is what we want for a `Shape`
293+
294+
An abstract class will force derived types to all behave the same way
295+
296+
### Pure virtual functions
297+
298+
*Each method is declared a `virtual` function and "Assigns" a 0 to each of these `virtual` functions*
299+
300+
#### Example
301+
302+
``` cpp
303+
class Shape
304+
{
305+
public:
306+
virtual double area( ) const = 0;
307+
void print( ) const = 0;
308+
};
309+
```
310+
311+
* You *can* create a pointer to an abstract class, and then assign the pointer to a *concrete class* derived from the base class
312+
313+
``` cpp
314+
Rectangle r(2,4); //concrete derived type
315+
Shape *s = &r; //OK, Rectangle is a Shape
316+
s->print(); //virtual, so correct version
317+
//of print() is called
318+
```
319+
320+
``` sh
321+
./a.out
322+
Rectangle: a=2 b=4
323+
```
324+
325+
### Factory functions
326+
327+
*Creates objects for another programmer who doesn't need to know their actual types*
328+
329+
``` cpp
330+
//EFFECTS: asks user to select a shape
331+
// returns a pointer to correct object
332+
Shape * ask_user( );
333+
```
334+
335+
`ask_user( )` is an example of a *factory function*
336+
337+
### Upcast
338+
339+
Conversion from `Isosceles` to `Shape` is called an *upcast*
340+
341+
In `ask_user( )`, the type conversion is automatic, an *implicit cast*
342+
343+
### Downcast
344+
345+
*A cast from one type in the class hierarchy to a lower one*
346+
347+
Since `Shape` might not be `Isosceles`, this cas cannot happen automatically
348+
349+
#### `dynamic_cast`
350+
351+
`dynamic_cast<T*>(ptr)` downcasts `ptr` to type `T*`, if possible. Otherwise, it returns 0.
352+
353+
This is usually a symptom of a poor design

0 commit comments

Comments
 (0)