diff --git a/Zpracované Otázky.md b/Zpracované Otázky.md index 987c085..f34ff02 100644 --- a/Zpracované Otázky.md +++ b/Zpracované Otázky.md @@ -59,11 +59,110 @@ Poznámka: Příklady jsou zjednodušené a ne vždy jsou 100% syntakticky práv - Jaký je rozdíl mezi mělkou a hlubokou kopií? # 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 + +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? -### Jak a kdy se volá konstruktor a destruktor? -### Jaký je rozdíl mezi objektem alokovaným v zásobníku a objektem dynamicky alokovaným na haldě? -### Jaký je rozdíl mezi operátory `delete` a `delete[]`? +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 +``` ### Jaká je návratová hodnota destruktoru? ### Co je třeba zajistit při dynamické alokaci? Uveďte příklad. ### Co je to výjimka a k čemu je dobrá? Uveďte příklad.