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
|
# Статично и динамично свързване. Виртуални функции. Полиморфизъм. Абстрактни класове.
#### Статично и динамично свързване. Виртуални функции.
Пример за **статично** свързване:
```c++
#include <iostream>
using namespace std;
struct A
{
void f() const
{
std::cout << "A::f()" << std::endl;
}
};
struct B : public A
{
void f() const
{
std::cout << "B::f()" << std::endl;
}
};
int main()
{
B* bPtr = new B();
A* aPtr = bPtr;
bPtr->f(); // B::f()
aPtr->f(); // A::f()
delete bPtr;
}
```
- **Статично** свързване - изборът на функцията, която трябва да се изпълни става **по време на компилация**.
- **Динамично** свързване – изборът на функцията, която трябва да се изпълни става **по време на изпълнение на програмата**.
```c++
#include <iostream>
using namespace std;
struct A
{
virtual void f() const
{
std::cout << "A::f()" << std::endl;
}
};
struct B : public A
{
void f() const
{
std::cout << "B::f()" << std::endl;
}
};
struct C : public A
{
void f() const
{
std::cout << "C::f()" << std::endl;
}
};
int main()
{
A* ptrs[3];
A obj1;
B obj2;
C obj3;
ptrs[0] = &obj1;
ptrs[1] = &obj2;
ptrs[2] = &obj3;
ptrs[0]->f(); // A::f()
ptrs[1]->f(); // B::f()
ptrs[2]->f(); // C::f()
}
```
#### Полиморфизъм
Едни и същи действия се реализират по различен начин в
зависимост от обектите, върху които се прилагат.
- Действията се наричат полиморфни.
- Реализира се чрез виртуални функции.
- Класовете, върху които ще се прилага, трябва да имат общ родител или прародител, т.е. да са наследници на един и същ клас.
- В класа се дефинира виртуален метод, съответстващ на полиморфното действие.
- Всеки клас предефинира или не виртуалния метод.
- Активирането става чрез указател към базов клас, на който може да се присвоят адресите на обекти на който и да е от базовите класове от йерархията
**Важно!** При полиморфна йерархия ще изтриваме обектите чрез указатели от базовия клас. За да се извикват правилните деструкори задължително **деструкторът на базовият клас** трябва е деклариран като виртуален!
```c++
#include<iostream>
struct Animal
{
virtual void sayHello() const
{
std::cout << "Hello, I am a random animal" << std::endl;
}
virtual ~Animal(){} //!!!
};
struct Dog : public Animal
{
void sayHello() const override
{
std::cout << "Hello, I am a dog!" << std::endl;
}
};
struct Cat : public Animal
{
void sayHello() const override
{
std::cout << "Hello, I am a cat!" << std::endl;
}
};
struct Mouse : public Animal
{
};
int main()
{
Animal** animals = new Animal*[3];
animals[0] = new Dog();
animals[1] = new Cat();
animals[2] = new Mouse();
//from base-class pointer
animals[0]->sayHello(); // Hello, I am a dog!
animals[1]->sayHello(); // Hello, I am a cat!
animals[2]->sayHello(); // Hello, I am a random animal!
delete animals[0], animals[1], animals[2];
delete[] animals;
}
```
#### Абстрактен клас
- Чисто виртуална функция (**pure virtual function**) - вруална функция без тяло.
- Клас е **абстрактен**, ако в него има поне една **чисто виртуална функция**.
Тогава класът е предназначен единствено за наследяване и няма да може да създаваме обекти от него.
Така във всеки наследник ще трябва да се разпише имплементация на функцията. Ако някой наследник няма собствена имплементация, то и той става абстрактен клас.
```c++
#include<iostream>
struct Animal
{
virtual void sayHello() const = 0;
virtual ~Animal(){} //!!!
};
struct Dog : public Animal
{
void sayHello() const override
{
std::cout << "Hello, I am a dog!" << std::endl;
}
};
struct Cat : public Animal
{
void sayHello() const override
{
std::cout << "Hello, I am a cat!" << std::endl;
}
};
struct Mouse : public Animal
{
void sayHello() const override
{
std::cout << "Hello, I am a mouse!" << std::endl;
}
};
struct PrehistoricAnimal : public Animal
{};
int main()
{
// Animal* pa1 = new Animal(); No! Animal is an abstract class!
// Animal* pa2 = new PrehistoricAnimal(); No! PrehistoricAnimal is also an abstract class!
Animal** animals = new Animal*[3];
animals[0] = new Dog();
animals[1] = new Cat();
animals[2] = new Mouse();
//from base-class pointer
animals[0]->sayHello(); // Hello, I am a dog!
animals[1]->sayHello(); // Hello, I am a cat!
animals[2]->sayHello(); // Hello, I am a mouse!
delete animals[0], animals[1], animals[2];
delete[] animals;
}
```
|