Files
PPC/Zpracované Otázky.md
2026-04-05 23:38:49 +02:00

622 lines
29 KiB
Markdown

Poznámka: Příklady jsou zjednodušené a ne vždy jsou 100% syntakticky právně (nechci vždy psát int main(void)... etc.)
# Principy objektového programování
### Jaký je rozdíl mezi třídou a objektem?
**Třída je šablona pro vytváření objektů**. Typicky napíšu třídu a pak z ní inicializuju její objekty, které až poté v kódu využívám.
```cpp
class Trida
{
public:
int cislo;
// tady jsou funkce a promenne
};
int main(void)
{
Trida objekt;
objekt.cislo = 10;
}
```
### Jak je určena viditelnost členských proměnných a metod?
- public -> přístup možný odkudkoli z programu
- protected -> přístup je možný ze třidy nebo z podtříd (dědičnost)
- private -> pouze funkce uvnitř objektu (třídy) můžou přistupovat ke členu s touto viditelností
```cpp
class Trida
{
public:
int a;
private:
int b;
protected:
int c;
};
int main(void)
{
}
```
### Jaký je rozdíl mezi členskými metodami (a proměnnými) třídy a objektu?
Třída může obsahovat i metody typu `static` to jsou **členské metody**. Pokud ze třidy inicializuju objekt, tyto metody se do objektu nepředají. Nejlepší způsob jak je zavolat je přes jejich třídu `Mojetrida::metoda();`
### Jaký je rozdíl mezi klíčovými slovy protected a private?
- **private** -> přístupné **POUZE** uvnitř třídy, zděděná třída (a její objekty) nemá přístup k k proměnné původní třídy s protected
- **protected** -> vlastně je to jako private (tedy z kódu nemůžu měnit tuto proměnnou/metodu ve třidě), ale s tím rozdílem, že pokud vytvořím podtřídu (pomocí dědění) a z ní vytvořím objekt, tak jeho metody můžou přistupovat k protected členům objektů původní třídy
### Co je polymorfismus a jak je ho dosaženo?
**Polymorfismus** je koncept, kdy jeden interface (třeba metoda) lze univerzálně použít pro více datových typů.
Toho se dosáhne pomocí více různých implementací.
Například můžu mít virtuální metodu `Draw()` v bázové třídě `Shape` a tuto metodu zdědí její potomci `Triangle` a `Square`. Implementace `Draw()` je v obou třídách jiná, ale u obou stačí zavolat `Draw()` a objekt se vykreslí.
Dále můžu dosáhnout polymorfismu pomocí přetěžování funkcí, kdy vytvořím víc funkcí se se stejným jménem, ale jiným typem.
Obvykle tím ale je spíš míněno to, že zděděné třídy od bázové třídy mají stejné chování (a ten iterface). Takže Když zdědím od `Vozidlo` -> `Tank`,`Formule`,`Tatrovka`, tak přece to jsou jiné třídy a mají jiný obsah, ale zdědí stejný typ ovládání. Např se všechny budou ovládat pomocí `.otoc_volant()`, `.zmackni_plyn()`, `.zmackni_brzdu()`, etc. (a nechci slyšet nic o tom, že tank může mít tradičně ovládací páky)
### Co je to bázová třída a čím se vyznačuje?
Bázová třída třída je třída, z které se dědí. (ano notář sepíše vůli a potomci dostanou každý svojí část).
Bázová třída má nějaké vlastní datové typy a vlastní metody. Pokud jsou tyto metody a typy `public` nebo `protected`, tak je zdědí dědící třída.
Bázová třída může nebo nemusí obsahovat třeba virtuální metody nebo může nebo nemusí být plně virtuální.
**Prostě je to třída z které někdo dědí, to je všechno.**
### Uveďte příklad deklarace plně virtuální metody?
[geeks for geeks](https://www.geeksforgeeks.org/cpp/pure-virtual-functions-and-abstract-classes/)
**Plně virtuální metoda**, nebo někdy také **abstraktní metoda**, je metoda, co nemá vlastní implementaci v bázové třídě. To znamená, že je pouze naznačená její existence, ale není v ní žádný kód. Očekává se, že se kód dopíše ve zděděné třídě.
Pokud třída obsahuje takovou metodu, nelze z ní vytvářet instance (objekty).
Plně virtuální metoda je se píše ve tvaru `virtual typ jmeno() = 0;` Př:
```cpp
//sorry moc si nepamatuju, co kde cepujou...
class Hospoda {
public:
virtual void nacepuj() = 0; // plne virtualni metoda
};
class Nadrazka : public Hospoda {
public:
void draw() override {cout << "Staropramen\n";}
};
class Nadrazka : public Hospoda {
public:
void draw() override {cout << "Plzeň\n";}
};
class Nadrazka : public Hospoda {
public:
void draw() override {cout << "Kozel\n";}
};
```
### Co je to implicitní konstuktor?
Máme dva termíny co se obecně pletou a to **defaultní** konstruktor a **implicitní konstruktor**. Defaultní konstruktor je konstruktor, co nemá žádné argumenty a nás vlastně v této otázce nezajímá.
**Implicitní konstruktor** je konstruktor, který si kompilátor sám doplní, když ho nedodá uživatel. Obvykle pouze vytvoří proměnné, které ale pak nejsou inicializovany, takže mají náhodné hodnoty.
**Implicitní kopírovací konstruktor** je kopírovací konstruktor, který vytvoří kompilátor, když ho nedodá uživatel. Většinou jedna ku jedné vytvoří kopie hodnot prvků, což je problematické třeba u ukazatelů. Může se pak stát, že 2 prvky po zkopírování budou mít stejné pole (stejnou adresu na ukazately) a můžou si ho sami přepisovat. Dále se pak může stát, že když se zníčí jeden objekt, uvolní pole, které první objekt používá... to se řeší vlastním kopírovacím konstruktorem viz. další otázka
btw, to je tzv. mělká kopie
### Co je to kopírovací konstruktor?
Abychom řešili problém s mělkým kopírováním **implicitního kopírovacího konstruktoru** (viz. předchozí otázka), tam můžeme vytvořit vlastní kopírovací konstruktor, který udělá tzv. hlubokou kopii. Tedy umí vytvořit třeba nové ukazatele pro nový kopírovaný prvek. **Ten si musíme napsat manuálně takto:**
```cpp
Class A
{
public:
int* a;
A(int number) {a = new int(number);} //normální konstruktor
A(const &A other) {a = new int(*other.data)} //kopírovací konstruktor
//vracím objekt s novým ukazatelem u a
}
```
### Jaké jsou možnosti dědění? Uveďte příklady.
Celé je to o tom, jak se změní viditelnost členů.
Máme **3 typy dědění**:
- **public**
- **private**
- **protected**
**Public dědění:**
```cpp
class B : public A {};
```
Zde třída A dostane všechny části zděditelné části třídy B úplně stejně, jako je měla třída A.
Tedy jde hlavně o to, jak se změní public a protected atributy. Tady:
public -> public
protected -> protected
**Protected dědění:**
```cpp
class B : protected A {};
```
Zde se všechny zděditelné prvky změní na protected Tedy
public -> protected
protected -> protected
**Private dědění:**
```cpp
class B : private A {};
```
Zde se všechny zděditelné prvky změní na private. Tedy:
public -> protected
protected -> private
### Co je to virtuální dědění a k čemu je dobré?
Je to způsob řešení problému tzv. diamantového dědění (či obdobné situace, viz. obrázek). V podstatě jde o to, že **dědění umožňuje přebírat vlastnosti víc tříd najednou** (ne pouze jedné), což pak může vyústit v situace, kde se snažím vytvořit potomek z dvou a více tříd, kde **mají některé společného předchůdce** (někde v jejich rodokmeni.)
![](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Diamond_inheritance.svg/500px-Diamond_inheritance.svg.png)
To by normálně skončilo tak, že by byla nevyřešená situace, která by mohla vyhodit chybu v případě, kdy bych se ze třídy `D` pokoušel přistoupit ke zděděnému členu z bázové třídy `A`. Kompilátor si není jistý zda si vybrat cestu přes `B` nebo přes `C`.
Řeším to přes virtuální dědění:
```cpp
//priklad z wikipedia.org na toto téma
class Animal {
public:
virtual ~Animal() = default;
virtual void eat() {}
};
class Mammal: virtual public Animal { //virutalni dědění
public:
virtual void breathe() {}
};
class WingedAnimal: virtual public Animal { //virtuální dědění
public:
virtual void flap() {}
};
//zdědí obě vlastnosti bez duplikace
class Bat: public Mammal, public WingedAnimal {};
```
### Které vlastnosti rodiče potomek nedědí?
- **konstruktory a destruktory**
- **privátní členy**
- **funkce přetěžování operátorů**
- statické členy (jdou zavolat, ale neexistuje kopie, kinda nieche)
### Co je to přetížení? Uveďte příklad (několik řádek kódu, ze kterých bude zřejmé, o co jde).
Přetížení je, když má více funkcí stejné jméno, ale jiné chování. Využívá se to, když potřebujeme napsat jednu funkci pro více různých argumentů.
Přetěžovat jdou:
- funkce
- operátory
Přetěžování funkcí je hlavně stejné jméno, ale jiná funkce dle jejich argumentů
```cpp
bool is_not_zero(int x)
{
return(x != 0)
}
bool is_not_zero(char x)
{
return(x != 0)
}
bool is_not_zero(bool x)
{
return(x != 0)
}
bool is_not_zero(Std::string x)
{
return(x != '0')
}
```
Přetěžování argumentů je vysvětleno v jiné otázce v sekci Programování v C++ (a mimojiné jsem to vysvětlil v dokumentu v repu, co jsem na to téma vytvořil)
### Jaký je rozdíl mezi přepsáním (override) a přetížením (overload)?
Pomocí obou technik lze docílit, aby jedna funkce měla různé implementace.
**Přetížení**:
Při přetěžování vytvořím víc funkcí se stejným jménem a kompilátor se rozhodne jakou spustí dle dodaných argumentů
**Přepisování**:
Je koncept implementace polymorfismu, kdy v zájmu udržení stejného rozhraní (názvů metod u různých tříd), přepíšu u jednotlivých tříd, které metodu zdědily metody, tak je se mi u konkrétní třídy hodí
### Co je vazba typu kompozice? Uveďte příklad (několik řádek kódu, ze kterých bude zřejmé, o co jde).
Kompozice je, když objekt vlastní jiný objekt. Když zanikne celek, zanikne i část:
```cpp
class FEL {};
class FIT {};
class FS {};
class CVUT
{
public
FEL fel; //objekt cvut vlastni svoje fakulty
FIT fit; //patri k nemu a kdyz neni CVUT nejsou ani fakulty
FS fs;
//funkce co s temito objekty interaguji...
}
```
### Co je vazba typu asociace? Uveďte přiklad (několik řádek kódu, ze kterých bude zřejmé, o co jde).
Asociace je slabší vztah než kompozice. Objekt pouze odkazuje na jiný objekt (třeba přes pointer), ale nevlastní ho. Když původní objekt přestane existovat, asociovaný objekt může existovat dál.
```cpp
class Ucitel
{
public:
void uc() {}
};
class Student
{
private:
Ucitel* ucitel; // asociace
public:
//nejaky konstruktor priradi ucitle..
void studuj() {ucitel->uc();}
};
```
### Co reprezentuje klíčové slovo this?
`this` reprezentuje ukazatel na aktuální objekt/třídu (v metodách uvnitř třídy). Používání `this` není povinné, ale je to užitečné například pokud se **lokální proměnná a prvek třídy jmenují stejně**, nebo pokud chci třeba vracet ukazatel na objekt, čo objekt samotný: `*this`
`this` taky ulehčuje předání všech členů třídy/objektu lambda funkci
### Jaký je rozdíl mezi referencí a ukazatelem?
Reference je podobná ukazateli, ale je omezenější ve funkčnosti pro bezpečnost práce.
V podstatě je podobná konstantnímu ukazateli. Není možné změnit, na co reference ukazuje a dokonce nemůže existovat prázdná reference, nebo reference ukazující na `nullptr`. Referenci není třeba dereferencovat, chová se jako původní proměnná.
```cpp
int a = 1;
int b = 2;
int* p = &a; #ukazatel ukazuje na a
p = &b; # ukazatel ukazuje na b
int& r = a; #reference ukazuje na a
r = b; #reference nabírá hodnoty b, teď a = b
# a = b; je ekvivalentní
```
viz dokument, co jsem na to udělal ve stejném repu
### Jaký je rozdíl mezi mělkou a hlubokou kopií?
Mělká 1:1 zkopíruje obsah dvou objektů, structů, etc.
To může být problém třeba když mám nějakou dynamicky alokovanou paměť na ukazately. Protože se ukazatel zkopírují taky (jelikož ukazatel je číslo reprezentují číselnou adresu v paměti), tak to skončí tak, že **kopie objektu ukazuje na stejnou paměť jako původní objekt**. Takže si můžou paměť přepisovat, nebo může dojít k dvojitému uvolnění, nebo přístupu po uvolnění.
Hluboká kopie **zajišťuje zcela novou část paměti pro kopii. Ukazatele mají nyní vlastní unikátní adresy, ale zkopíruji do nich hodnotu v původní paměti.**
například na to můžu vytvořit kopírovací konstruktor...
# Programování v C++
### 1) Napište příklad načteni hodnoty typu int ze standarního vstupu pomocí proudového operátoru. Jak lze ošetřit správnost vstupu?
```cpp
#include <iostream>
int main(void)
{
int x;
if(std::cin >> x)
{
std::cout << "ok";
}
else
{
std::cout << "chyba";
}
}
```
Tenhle příklad načte hodnotu pomocí `std::cin >> x`, kde `x` je proměnná a `std::cin` je standardní input stream.
`std::cin >> x` vrací hodnotu `true` pokud je vše v pořádku a `false` pokud ne. Pokud se načte něco jiného jak číslo, tak třeba vrací false.
Kokrétněji `std::cin` má několik stavových bitů a to **fail** -> který je nastavený, když se něco pokazí (například špatný převod na typ -> string na int, etc.), **eof** -> který je nastavený, když je konec input streamu, **bad** -> který je nastavený, když se opravdu něco pokazí.
Když přečtu poslední znak, automaticky se nastaví eof bit a ten můžu zkontrolova pomocí `std::cin.eof() == true`. Složitější je, když se něco pokazí. To může být např. při špatném převodu nebo, když čtu po konci streamu a **je třeba to opravit**.
Nejprve je třeba nastavit `std::cin.clear()`, což vynuluje bity, takže můžu pokračovat ve čtení. To ale nestačí. Nezpracovaný text zůstane uložený v bufferu a přečte se znova příště. To jde vyřešit pomocí funkce `std::cin.ignore(int, char)`, kde int je počet znaků, co to vymaže a char je znak, kterým to končí, například `std::cin.ignore(1000, '\n')` vymaže 1000 znaků do konce řádky.
Btw `if(std::cin >> x)` vlastně vrací `if(!std::cin.fail())`
### 2) Jak se v C++ provádí přetížení operátoru? Uveďte příklad.
Přetěžování operátorů je implementace fungování znaků operátorů jako `+`, `-`, `>`, etc. pro objekty tříd, co napíšu.
Jsou dva způsoby jak to udělat. Buď na to napíšu funkci uvnitř třídy, pro kterou to chci implementovat, nebo na to napíšu samostatnou funkci mimo.
Používám na to speciální název funkce `operator`, ke které napíšu, jaký operátor řeším
Příklad uvnitř třídy:
```cpp
class Number
{
public:
int n;
Number(int set_n) {n = set_n;}
Number operator+(const Number &numA) //reference na objekt napravo od +
{
return Number(this->n + numA.n)
}
};
int main(void)
{
Number a(10);
Number b(20);
Number c = a + b;
}
```
Nebo mimo třídu to může vypadat například takto:
```cpp
Number operator+(const Vec& a, const Vec& b)
{
return Vec{a.x + b.x};
}
```
Btw, reference se používají, protože nekopírovat hodnoty, ale jenom na ně ukazovat, je šetrnější.
**Na tohle téma jsem udělal samostatný dokument na githubu (Přetěžování operátorů)**
### 3) Jaké operátory nelze v C++ přetížit?
Přetěžovat nelze operátory:
- `.`
- `::`
- `?:`
- `sizeof`
- `typeid`
Většinou to je proto, protože jsou v syntaxi tak důležité, že by to mohlo udělat nejasnosti v tom, jak by to měl vůbec kompilátor překládat. (Má tečku řešit jako člen, nebo jako něco úplně jiného... etc.) **Ty operátory totiž už většinou mají funkční účel předtím, než jsou přetížené a to u operátorů, co jdou přetížit neplatí.**
Na tohle téma jsem zpracoval mimochodem dokument na githubu.
### 4) Jak a kdy se volá konstruktor a destruktor?
Konstruktor se zavolá při vytvoření objektu. Můžu do něj dát jako argument hodnoty, které chci třeba využít při inicializaci.
Mám dva typa alokace objektů, které se dělají jinak. Jedna je statická a druhá je dynamická.
Staticky alokuju objektu takto: `Trida objekt(...);` a dynamicky pomocí **new**: `Trida* objekt = new Trida;`. Je v tom zásadní rozdíl v životnosti objektu. -> viz další otázka:
Destruktor se u statického objektu zavolá sám, když se dojde ke konci scopu (bloku kódu, funkce, etc...). Nemusím ho volat a ani bych neměl.
U dynamického objektu ho musím zavolat manuálně pomocí `delete objekt;` nebo v případě pole objektů pomocí `delete[] pole_objektu;`
Pozn: klasický dynamický objekt se řeší pomocí ukazatele na objekt a dereference
### 5) Jaký je rozdíl mezi objektem alokovaným v zásobníku a objektem dynamicky alokovaným na haldě?
- Statické objekty se automaticky zníčí, když opustí scope -> blok, funkci, etc.
- Dynamické objekty zůstávají v paměti, než jsou zničeny pomocí delete
Používají se často alternativy, například smart pointer -> drží pointer v objektu a když se zníčí, zníčí i dynamický objekt.
### 6) Jaký je rozdíl mezi operátory `delete` a `delete[]`?
- `delete` se používá pro uvolňování dynamického objektu
- `delete[]` se používá pro uvolňování pole objektů
```cpp
Trida* objekty = new Trida[7];
delete[] objekty; //uvolni cele pole objektu
```
### 7) Jaká je návratová hodnota destruktoru?
Destruktor nemá návratovou hodnotu. Jako u funkce void se z něj dá vrátit pomocí `return;`
### 8) Co je třeba zajistit při dynamické alokaci? Uveďte příklad.
Při dynamické alokaci si hlavně musím dávat pozor na to, že mám nad pamětí nonstop kontrolu (například nikde neztratím ukazatel na ní) a že ji správně dealokuju (nedojde k úniku paměti).
V moderním C++ to ale tolik řešit nemusím. Většinou použiju tzv. **smart pointer**. který automaticky dealokuje objekt, když skončí scope.
```cpp
#include <memory> //tohle je na smart ukazatele
#include <vector>
struct Node {int value;};
void main(void){
auto p = std::make_unique<Node>(); // alokace
} //po konci main automatické uvolnění
```
### 9) Co je to výjimka a k čemu je dobrá? Uveďte příklad.
Výjimky umožňuje kontrolovat chod programu a popasovat se s nečekanými chybami. Primárně jsou míněny pro řešení problémů, které programátor nemůže tak dobře ovlivnit, jako například práci se zdroji (třeba soubor) nebo množství dynamické paměti.
Výjimky existují všeho různého druhu, zde je příklad kódu:
```cpp
try
{
#nějaký kod
}
//catch("Text") {} //nedává smysl, nechytá se hodnota, ale typ
catch(const std::bad_alloc& e) {} //vyjímka špatné alokace
catch(int) {} //chytí všechny integery - které manuálně vyhodím
catch(std::exception) {} //chytí všechny chyby (věci typu chyba)
catch(...) {} //chytí úplně všechno - i to co manuálně vyhodím
```
**Mám na tohle téma samostatný dokument, kde toto téma zpracovávám.**
### 10) Kolik výjimek je možné v programu ošetřit?
Tbh, nechápu tuhle otázku
- Typů výjimek je hodně a kdyžtak si můžu vlastní dopsat.
- výjimek může program za běhu ošetřit neomezeně
- **Najednou (v jeden moment) je možné ošetřit pouze jednu výjimku. Pokud se jich objeví více (například z destruktorů), tak se pogram ukončí přes std::terminate**
### 11) Co je to generická funkce?
Generická funkce je funkce, která umí přijímat či vracet libovolný datový typ. je to šikovná alternativa k přetěžování funkcí.
K tomu používám `template <typename T>`, kde `T` reprezentuje libovoloný datový typ (to je moje pojmenování, ale jmenovat se to může jak chce, T se používá často...).
Příklad i s funkcí:
```cpp
template <typename T>
T secti(T a, T b)
{
return a + b;
}
```
Zde sčítám nějaké 2 obecné datové typy.
### 12) Jak lze vytvořit explicitní instanci generické funkce? K čemu je to dobré? - DOCELA MIZERNĚ
[stackoverflow](https://stackoverflow.com/questions/2351148/explicit-template-instantiation-when-is-it-used#2351622)
Explicitní instance je způsob, jak předem donutit kompilátor vytvořit šablonu - instanci generické funkce, než je použita.
```cpp
template int secti<int>(int, int);
```
Ono to údajně umožní zrychlit kompilaci protože tomu řeknu, ať to vytvoří tu int verzi předem.
Normálně bych do `.h` souboru napsal:
```
template <typename T>
T secti(T a, T b);
```
ale můžu místo toho do `cpp` souboru napsat:
```cpp
template <typename T>
T secti(T a, T b) {
return a + b;
}
template int secti<int>(int, int); // explicitní instance
```
kde se vytvoří verze s intem samostatně předem a pak místo toho, aby to kompilátor řešil 10x zrovna, když to potřebuje, tak to prostě zkopíruje.
Also to umožní fungování je některým typům?
Takže:
- umožní použití jen několik typů, které si určím
- zrychlý to kompilaci
### 13) Jak jsou obvykle parametrizovány šablony tříd?
### 14) V čem spočívá problém vícenásobného dědění? Jak je možné tomuto problému zabránit?
### 15) Co je to zapouzdření a čemu je dobré?
### 16) Jak lze využít implicitní hodnoty argumentu funkce? Uveďte příklad.
### 17) Jaký je rozdíl mezi deklarací třídy pomocí class a struct?
### 18) Co je to konverzní konstruktor?
### 19) Jaký je rozdíl mezi statickou a dynamickou vazbou?
### 20) Jaký je význam klíčového slova auto? Lze ho použít vždy?
### 21) Co přesouvací (move) kontruktor?
### 22) Co je pravidlo tří (rule of three)?
### 23) Jaký je tvar definice lambda funkce v C++? Uveďte příklad a popište, co funkce dělá.
# STL kontejnery
### 1) Co je to kontejner?
Kontejnery jsou datové struktury určené k ukládání kolekce dat (hodnot) a k manipulaci s nimi. Například to je `vector`, který funguje jako dynamické pole.
Máme různé typy kontejnerů - sekvenční asociativní (a pak údajně neseřazený asociativní a adaptery pro jiné ovládání existujících kontejnerů, ale to raději neřešme). Viz. další otázka.
Hlavní smysl kontejnerů je ulehčit práci při programovaní. Je to často již implementované řešení, které se v kódu jednoduše používá, nebo je to rada, jak si takové řešení udělat. Je to vrstva abstrakce.
### 2) Jaký je rozdíl mezi sekvenčními a asociativními kontejnery? Uveďte příklad.
**Sekvenční kontejnery** pracují s daty nezávisle na jejich hodnotě. To je míněno tak, že třeba data ukládají dle pořadí, ve kterém do kontejneru přišli a data mají unikátní index. Je to například `std::vector` a `std::list`
**Asociativní kontejnery** řeší data většinou dle nějakého klíče, který je k nim přiřazen. Například `std::map`. Data jsou pak seřazena tak, aby bylo například efektivní vyhledávání a místo indexu mají právě na vyhledání klíč.
- `std::map` - data seřazeny dle porovnávací funkce
- `std::unordered_map` - data neseřazeny a hledány dle jejich hashe
### 3) Jaké jsou klíčové vlastnosti kontejneru std::vector?
**Vector** je prakticky **dynamické** **pole** s podobnými vlastnostmi jako jeho implementace v C++, akorát to celé někdo implementoval v třídě s funkcemi za nás.
- Data jsou seřazeny za sebou dle jejich velikosti v paměti. (tedy 5 prvek int o velikosty 4 byty je na 17-20 bytu)
- Vyhledávání konkrétního prvku je O(1) -> dopočítám hned z velikosti a pozice
- přidání/odstranění na konec - O(1)
- Odstranění a přidání je kamkoli - O(n) -> vyžaduje přesun všech prvků v poli
- pole má hodnotu velikosti (kolik zabírá bytů prvky) a kapacity (kolik bytů si dynamicky rezervuje). Kapacita musí být větší než velikost, jinak je třeba přealokovat
- adresy prvků nejsou stabilní kvůli realokaci
`std::vector<int> kontejner1`;
### 4) Jaké jsou klíčové vlastnosti kontejneru std::map?
Ukládá si pro každý prvek 2 hodnoty a to **klíč a hodnotu**. Všechny prvky jsou seřazené podle klíče a jeho porovnávací funkce, který zajišťuje operace o O(log n). Seřazení může třeba být binární strom.
Kontejner umožňuje vymyslet a vložit vlastní porovnávací funkci v šabloně.
### 5) Jaké jsou klíčové vlastnosti kontejneru std::list?
List je kontejner, který vlastně není moc odlišný od toho, co by člověk čekl (pokud si to pamatuje).
Data jsou uložena každá ve vlastní buňce v paměti. Každá buňka umožňuje přístup k dalšímu a předchozímu prvku (pamatuji se jejich ukazatele).
- proto je každá buňka bezpečně samostatně uložena v paměti nezávisle na ostatních buňkách
- Je jednoduché přidávat/odebírat na známé pozice prvky - O(1) -> stačí změnit ukazatele v buňkách předchozí a další buňky (říká se tomu často uzel).
- Hledání prvku na n-té pozice je obtížné, je třeba projít všechny prvky, které k němu vedou - O(n)
- vhodné pro potřebu čistého rychléhi přidávání a mazaání prvků, ale nevhodné pro rychlý náhodný přístup
`std::list<int> L;`
### 6) Jakého datového typu může být klíč kontejneru std::map?
Klíč `std::map` může být kteréhokoli typu, který je možná porovnávat pomocí řazení (má operátor `>` a `<`). Nebo je možné dodat vlastní porovnávací funkci (komparátor).
### 7) Co je třeba zajistit v případě, že klíčem v kontejneru std::map je strukturovaný datový typ (např. naše vlastní třída)?
- buď je třeba zajistit, aby objekty třídy byly porovnatelné pomocí `>` a `<` například pomocí přetěžování operátorů
- nebo je možné sepsat vlastní comparator (vlastní porovnávací funkci)
### 8) Jaký je význam datového typu std::pair?
`std::pair` je datový typ, který umí ukládat 2 prvky libovolného typu
```cpp
pair<int, string> p = {1, "ahoj"};
p.first = 7;
p.second = "krkavců";
```
vhodné je se i podívat na operaci vzájemného porovnávání párů
### 9) Co je to iterátor? Uveďte příklad.
Iterátor je třída, která je spojená s určitým kontejnerem. Úkol prvků této třídy je jednoduchý a to umožnění jednoduché procházení prvky kontejneru.
Iterátor by tedy měl být dereferencovatelný -> dereferencí `*it` získáme hodnotu nynějšího prvku, jako by to byl ukazatel. Dále přičtením `++it` získáme další prvek kontejneru. Iterátoru přiřadíme hodnotu pomocí funkcá `.begin()` -> hodnota prvního iterátoru, a zjišťujeme konec kontejneru pomocí `.end()`.
Příklad:
```cpp
std::vector<int> pole = {1, 2, 3};
std::vector<int>::iterator it = pole.begin();
for(std::vector<int>::iterator it = pole.begin(); it != pole.end(); ++i)
{
std::cout << *it << std::endl;
}
```
### 10) Jaký je rozdíl mezi konstantním a nekonstantním iterátorem?
- Pomocí **nekontantního** iterátoru můžu měnit hodnotu prvku, na který ukazuje.
- Hodnotu prvku na který ukazuje **konstantní** iterátor měnit nemůžu.
- Potřebuji změnit typ iterátoru a také používám speciální funkci
```cpp
std::vector<int> pole = {1, 2, 3};
std::vector<int>::iterator it = pole.begin();
std::vector<int>::const_iterator cit = pole.cbegin(); //vlastni funkce
*it = 10; //můžu
*cit = 20; //nesmim, je to const...
```
### 11) Co všechno je třeba zajistit pro vytvoření vlastního iterátoru?
- iterátor musí mít dereferenci -> lze získat hodnotu jeho prvku
- lze přičítat takto `++it`
- lze odčítat takto `--it'
- lze porovnávat `==` a `!=` -> hlavně pro `.begin()` a `.end()`
zbytek podle kontejneru a kontextu (a podle toho, jak je vlastně vůbec myšlena tato otázka)
- je třeba mít `end` a `begin`, konstruktor u kontejneru etc...
### 12) Co je range-for cyklus? Uveďte příklad.
Je to specifický zápis `for` loop, který umžňuje iterovat všemi prvkami kontejneru.
```cpp
std::vector<int> pole = {1, 2, 3};
for (auto &i : pole)
{
i++;
}
```
V tomto kódu se projedou všehny hodnoty vektoru a přičte se k ním jedna.
`for (auto &i : pole)` -> napravo je název pole, nalevo je hodnotu prvku, používá se auto s referencí, aby se fyzicky nekopíroval každý prvek a bylo to nezávislé na typu.
prvek `i` pak reprezentuje aktuálně prvek iterace, tedy nabere hodnotu každého prvku pole
**Obdobně lze udělat loop i pro iteraci listem**.
### 13) Uveďte příklad použití algoritmu sort (deklarujte vektor libovolného datového typu, vložte do něj data a vektor seřaďte).
```cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {5, 2, 9, 1, 7};
std::sort(v.begin(), v.end());
for (const auto& x : v)
{
std::cout << x << " ";
}
return 0;
}
```
Sort porovná prvky podle jejich operárů `<` a `>`, funguje univerzálně u všech typů, pokud mají porovnávání definované.
U stringů to třeba porovnává lexikograficky.
Jinak je třeba definovat `>` `<` pomocí přetěžování operátorů a nebo dodat vlastní porovnávací funkci. -> `std::sort(v.begin(), v.end(), comparator)` -> kde comparator je porovnávací funkce
# Praktické programování (Qt a související)
- Co je to event-driven programování?
- Jaký je rozdíl mezi událostí a signálem?
- Uveďtě příklady událostí v Qt a jejich využití.
- Popište systém signálů a slotů, uveďte příklad propojení.
- Jakým způsobem lze vytvořit v Qt okno a v něm vykreslit grafickou komponentu?
- Jak lze měnit grafickou podobu jednotlivých Qt komponent?
- Co se časovač (QTimer), k čemu je dobrý a jak se používá?
- Co si představujete pod pojmem MVC?
- Jaký je rozdíl mezi UDP a TCP transportní vrstvou?
- Co je to REST rozhraní?
# Otázky proč
- proč píšu kopírovací konstruktor a nepřetěžuju operátor =?
-