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
|
# Задачи - ООП, Седмица 8, 11.04.2024
*Този файл е копие на задачите от: [syndamia.com/teaching/oop-2023/week8](https://syndamia.com/teaching/oop-2023/week8)*
## Преговорни
### Задача 1 - Голяма петица
Имплементирайте клас `StreetList`, който запазва имената на улици (низове с произволна дължина) в динамичен масив.
Може да се добавят нови имена в края на списъка, като съответния (вътрешен) масив трябва да се уголеми.
Имплементирайте голяма петица за класа.
### Задача 2 - Файлове и класове
Имплементирайте клас `Person`, който запазва трите имена (низове с произволна дължина) и идентификационния номер (цяло неотрицателно число) на човек.
Имплементирайте голяма петица.
Имплементирайте методи `SaveText` и `LoadText`, които съответно записват и четат (тоест член-данните стават равни на тези от файла) данните си в/от **текстови** файл с подадено име.
Аналогично имплементирайте `SaveBinary` и `LoadBinary`, които работят с **двоични** файлове.
## Лесни
### Задача 3
Имплементирайте шаблонната структура `Pair`, която приема два типа и запазва по една стойност от всеки тип.
### Задача 4
Имплементирайте клас `FloatArray`, който съдържа списък с числа с плаваща запетая.
Може да добавяте нови числа в края на този списък.
Имплементирйате голяма петица.
Имплементирайте оператори:
- += и +, които конкатенират два FloatArray-я. += вмъква елементите от десния масив в края на левия, + връща нов масив в който първо са елементите от левия масив и след тях са тези от десния.
- += и +, които приемат FloatArray и число (с плаваща запетая) и го прибавят към всеки елемент на FloatArray-я
- [], които връщат референция към елементът на подадения индекс. При невалиден хвърлят грешка.
- == и !=, които сравняват два FloatArray-я покомпонентно.
Ако се различават по брой елементи или ако имат две различни стойности на еднакъв индекс, тогава не са равни.
- <<, който вмъква всички стойности в подадения поток, разделени с шпация
- >>, който презаписва всички стойности, разделени с шпация, четейки от подадени поток
### Задача 5
Имплементирайте класът и неговите оператори от предходната задача като темплейтен (шаблонен) клас с име `DynamicArray`.
Очевидно шаблонния тип определя типа на списъка с елементи.
### Задача 6
Имплементирайте клас `NumberInput`, който запазва целочислена стойност.
В конструктора се подава минимална и максимална възможна стойност, след това (все още в конструктора) се изкарва на екрана съответно съобщение и се приема потребителски вход.
Ако той не е валиден или е извън подадения обхват, трябва да хвърлите грешка.
В main създайте обект от този клас.
Ако се хвърли грешка, прихванете я, изкарайте на екрана съответното съобщение и пробвайте пак.
Това се повтаря докато обекта не е успешно създаден, след което изкарвате въведената стойност по две.
### Задача 7
Имплементирайте клас `UserError`, чиято употреба е да се хвърля като грешка.
За тази цел нека да запазва два низа, които се приемат в конструктора: името на клас и името на член-данната.
Имплементирайте голяма петица и оператор<<, който изкарва съобщение с информация за класа и член-данната в подадения поток.
Следете бройката на създадени `UserError` инстанции в самия клас (статична променлива) и имплементирате нужната (статична) член-функция, която връща този брой.
Преобразувайте последната задача, така че да хвърля грешка от този клас.
В края на програмата изкарайте колко грешки са се хвърлили **използвайки статичните членове на UserError**.
## Трудни задачи
### Задача 8
Имплементирайте шаблонен клас `UserInput`, който запазва стойност от подадения тип.
Ако типа е указател, тогава заделяте динамична памет за един такъв елемент.
За проверка на типа използвайте [partial template specialization](https://en.cppreference.com/w/cpp/language/partial_specialization).
В шаблона (`template <...>`) се приема указател към валидираща функция, която приема стойността от съответния тип и връща булева стойност.
В конструктора се приема от входа нужната стойност и ако стойността е неуспешно приета или валидиращата функция върне false, тогава хвърляте грешка.
Ако типа е указател, не забравяйте да освободите паметта.
В класа следете статично за броя пъти когато е хвърлена грешка.
### Задача 9
&:important В тази задача се изикват помощни класове, прочетете цялото условие преди имплементиране!
Имплементирайте шаблонен клас `Dictionary`, който запазва два динамично-заделени масива: първия е със стойност от подадения тип, втория е с низове.
Низовете ще се използват за индексиране, вместо числа.
Разбира се, очаквайте да може да се уразмерява.
Имплементирайте голяма петица.
Имплементирайте оператор:
- <<=, който вмъква всички стойности от десния `Dictionary` в левия
- [], който приема низ и връща референция "към" стойността.
Ако няма записана стойност на съответния индекс, тогава връщате референция в която може да се запише стойност.
- [], който приема число, което се конвертира до низ и работи както предходния оператор
- [], който приема низове (или числа), разделени със запетая и връща "масив" само с тези стойности
- delete, който приема стойност, върната от оператор[] и "премахва" съответната стойност от `Dictionary`
- префиксен++, префиксен+ и префиксен-, които ще се използват за итериране.
- ++ връща инкрементира индекса на сегашната стойност.
Ако индекса е равен на броя запазени стойности, тогава става нула.
По подразбиране индекса е броя.
Връща true ако след инкрементиране индекса не е броя.
- + връща референция към стойността на сегашния индекс
- - връща сегашния (низов) индекс
- ->, такъв че можем да правим `a->(&func1)->(&func2)` и `a->[&func3]->[&func4]`.
Върху всяка двойка индекс-стойност се прилагат &func1 и &func2 (приемат индекс и стойност като параметри), които връщат нова стойност, заместваща сегашната.
&func3, &func4 аналогично приемат индекс и стойност, но връщат нов индекс.
В края на задачата трябва да можете да правите:
```cpp
int doubleUp(const char* index, int value) {
return value * 2;
}
int sumIndexValue(const char* index, int value) {
return atoi(index) + value;
}
const char* indToName(const char* index, int value) {
if (strcmp(index, "2")) {
return "two";
}
return index;
}
int main() {
Dictionary<int> a;
a["first"] = 8;
a[2] = 13;
a[89] = -68;
Dictionary<int> b;
b["wow"] = 99;
b["nth"] = 773;
a <<= b;
/* някакъв тип */ two = a["first", 2];
delete a["wow"];
a->(&doubleUp)->(&sumIndexValue)->[&indToName];
while (++a) {
std::cout << +a << " at " << -a << ",";
/* Ще изкара на конзолата:
* 16 at first,52 at two,-12104 at 89,1546 at nth,
*/
}
}
```
|