Compare commits

...

2 Commits

View File

@@ -1,7 +1,10 @@
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.) 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.)
Mám dost chyb a všímám si jich postupně. Např:
- destruktor nemá `return;` je to speciální syntax jazyka
# Principy objektového programování # Principy objektového programování
### Jaký je rozdíl mezi třídou a objektem? ### 1) 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. **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 ```cpp
class Trida class Trida
@@ -17,32 +20,42 @@ Poznámka: Příklady jsou zjednodušené a ne vždy jsou 100% syntakticky práv
objekt.cislo = 10; objekt.cislo = 10;
} }
``` ```
### Jak je určena viditelnost členských proměnných a metod? ### 2) Jak je určena viditelnost členských proměnných a metod?
- public -> přístup možný odkudkoli z programu - **public** -> přístup možný odkudkoli z programu (ze scope)
- protected -> přístup je možný ze třidy nebo z podtříd (dědičnost) - **protected** -> přístup je možný ze třidy nebo z podtřídy (dědičnost)
- private -> pouze funkce uvnitř objektu (třídy) můžou přistupovat ke členu s touto viditelností - **private** -> pouze funkce uvnitř objektu (třídy) můžou přistupovat ke členu s touto viditelností
```cpp ```cpp
class Trida class Trida
{ {
public: public:
int a; int a;
private:
int b;
protected: protected:
int b;
private:
int c; int c;
}; };
class Podtrida : public Trida {};
int main(void) int main(void)
{ {
Trida objekt;
objekt.a = 10; //muzu
objekt.b = 10; //nemuzu
objekt.c = 10; //nemuzu
Podtrida podobjekt;
podobjekt.a = 10; //muzu
podobjekt.b = 10; //nemuzu
podobjekt.c = 10; //vubec nema
} }
``` ```
### Jaký je rozdíl mezi členskými metodami (a proměnnými) třídy a objektu? ### 3) 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();` 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? ### 4) 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 - **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 - **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? ### 5) 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ů. **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í. Toho se dosáhne pomocí více různých implementací.
@@ -51,12 +64,12 @@ Například můžu mít virtuální metodu `Draw()` v bázové třídě `Shape`
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. 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) 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? ### 6) 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 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á 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 (potomek).
Bázová třída může nebo nemusí obsahovat třeba virtuální metody nebo může nebo nemusí být plně virtuální. 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.** **Prostě je to třída z které někdo dědí, to je všechno.**
### Uveďte příklad deklarace plně virtuální metody? ### 7) Uveďte příklad deklarace plně virtuální metody?
[geeks for geeks](https://www.geeksforgeeks.org/cpp/pure-virtual-functions-and-abstract-classes/) [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ě. **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ě.
@@ -85,14 +98,14 @@ public:
void draw() override {cout << "Kozel\n";} void draw() override {cout << "Kozel\n";}
}; };
``` ```
### Co je to implicitní konstuktor? ### 8) 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á. 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í 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 **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 btw, to je tzv. mělká kopie
### Co je to kopírovací konstruktor? ### 9) 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:** 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 ```cpp
@@ -103,10 +116,12 @@ public:
A(int number) {a = new int(number);} //normální konstruktor A(int number) {a = new int(number);} //normální konstruktor
A(const &A other) {a = new int(*other.data)} //kopírovací konstruktor A(const &A other) {a = new int(*other.data)} //kopírovací konstruktor
//vracím objekt s novým ukazatelem u a //nastavím svému nově vytvořenému objektu hodnoty tak, jak se mi to hodí
} }
``` ```
### Jaké jsou možnosti dědění? Uveďte příklady.
Fungování má podobné jako normální konstruktor. Místo toho, aby vytvořil nový prvek z dodaných argumentů, vezme referenci na jiný objekt jako argument.
### 10) Jaké jsou možnosti dědění? Uveďte příklady.
Celé je to o tom, jak se změní viditelnost členů. Celé je to o tom, jak se změní viditelnost členů.
Máme **3 typy dědění**: Máme **3 typy dědění**:
- **public** - **public**
@@ -137,7 +152,7 @@ class B : private A {};
Zde se všechny zděditelné prvky změní na private. Tedy: Zde se všechny zděditelné prvky změní na private. Tedy:
public -> protected public -> protected
protected -> private protected -> private
### Co je to virtuální dědění a k čemu je dobré? ### 11) 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.) 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) ![](https://upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Diamond_inheritance.svg/500px-Diamond_inheritance.svg.png)
@@ -166,12 +181,12 @@ public:
//zdědí obě vlastnosti bez duplikace //zdědí obě vlastnosti bez duplikace
class Bat: public Mammal, public WingedAnimal {}; class Bat: public Mammal, public WingedAnimal {};
``` ```
### Které vlastnosti rodiče potomek nedědí? ### 12) Které vlastnosti rodiče potomek nedědí?
- **konstruktory a destruktory** - **konstruktory a destruktory**
- **privátní členy** - **privátní členy**
- **funkce přetěžování operátorů** - **`operator=`**
- statické členy (jdou zavolat, ale neexistuje kopie, kinda nieche) - 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). ### 13) 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íž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: Přetěžovat jdou:
- funkce - funkce
@@ -193,13 +208,13 @@ bool is_not_zero(bool x)
} }
bool is_not_zero(Std::string x) bool is_not_zero(Std::string x)
{ {
return(x != '0') 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) 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)? ### 14) 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. Pomocí obou technik lze docílit, aby jedna funkce měla různé implementace.
**Přetížení**: **Přetížení**:
@@ -207,7 +222,7 @@ Při přetěžování vytvořím víc funkcí se stejným jménem a kompilátor
**Přepisování**: **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í 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). ### 15) 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: Kompozice je, když objekt vlastní jiný objekt. Když zanikne celek, zanikne i část:
```cpp ```cpp
class FEL {}; class FEL {};
@@ -224,7 +239,7 @@ public
//funkce co s temito objekty interaguji... //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). ### 16) 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. 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 ```cpp
class Ucitel class Ucitel
@@ -244,10 +259,10 @@ public:
void studuj() {ucitel->uc();} void studuj() {ucitel->uc();}
}; };
``` ```
### Co reprezentuje klíčové slovo this? ### 17) 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` 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 `this` taky ulehčuje předání všech členů třídy/objektu lambda funkci
### Jaký je rozdíl mezi referencí a ukazatelem? ### 18) Jaký je rozdíl mezi referencí a ukazatelem?
Reference je podobná ukazateli, ale je omezenější ve funkčnosti pro bezpečnost práce. 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á. 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á.
@@ -255,15 +270,16 @@ V podstatě je podobná konstantnímu ukazateli. Není možné změnit, na co re
int a = 1; int a = 1;
int b = 2; int b = 2;
int* p = &a; #ukazatel ukazuje na a int* p = &a; //ukazatel ukazuje na a - vytvoření
p = &b; # ukazatel ukazuje na b p = &b; //ukazatel ukazuje na b - změna adresy
int& r = a; #reference ukazuje na a int& r = a; //reference ukazuje na a - vytvoření
r = b; #reference nabírá hodnoty b, teď a = b r = b; //reference nabírá hodnoty b, teď a = b - změna hodnoty ne adresy
# a = b; je ekvivalentní //r = &b //NELEGÁLNÍ
// a = b; je ekvivalentní
``` ```
viz dokument, co jsem na to udělal ve stejném repu viz dokument, co jsem na to udělal ve stejném repu
### Jaký je rozdíl mezi mělkou a hlubokou kopií? ### 19) Jaký je rozdíl mezi mělkou a hlubokou kopií?
Mělká 1:1 zkopíruje obsah dvou objektů, structů, etc. 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í. 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í.
@@ -300,6 +316,8 @@ Nejprve je třeba nastavit `std::cin.clear()`, což vynuluje bity, takže můžu
Btw `if(std::cin >> x)` vlastně vrací `if(!std::cin.fail())` Btw `if(std::cin >> x)` vlastně vrací `if(!std::cin.fail())`
**Prostě zjistím jestli přechdozí operace proběhla v pohodě (dobrý typ/konec streamu ->řadku, souboru) pomocí: `std::cin.fail()`**
### 2) Jak se v C++ provádí přetížení operátoru? Uveďte příklad. ### 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. Přetěžování operátorů je implementace fungování znaků operátorů jako `+`, `-`, `>`, etc. pro objekty tříd, co napíšu.
@@ -333,7 +351,7 @@ Nebo mimo třídu to může vypadat například takto:
```cpp ```cpp
Number operator+(const Vec& a, const Vec& b) Number operator+(const Vec& a, const Vec& b)
{ {
return Vec{a.x + b.x}; return Vec(a.x + b.x);
} }
``` ```
@@ -341,12 +359,15 @@ Btw, reference se používají, protože nekopírovat hodnoty, ale jenom na ně
**Na tohle téma jsem udělal samostatný dokument na githubu (Přetěžování operátorů)** **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? ### 3) Jaké operátory nelze v C++ přetížit?
[geeks for geeks](https://www.geeksforgeeks.org/cpp/what-are-the-operators-that-can-be-and-cannot-be-overloaded-in-cpp/)
Přetěžovat nelze operátory: Přetěžovat nelze operátory:
- `.` - `.` - member dot
- `::` - `::` - scope resolution
- `?:` - `?:` - ternary operator
- `.*` -
- `sizeof` - `sizeof`
- `typeid` - `typeid`
- `(int)` - etc. castovani obecne nejde
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í.** 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í.**
@@ -377,7 +398,8 @@ Trida* objekty = new Trida[7];
delete[] objekty; //uvolni cele pole objektu delete[] objekty; //uvolni cele pole objektu
``` ```
### 7) Jaká je návratová hodnota destruktoru? ### 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;` **Destruktor nemá návratovou hodnotu.**
Ani v něm nepíšu `return` -> je to speciální syntax jazyka
### 8) Co je třeba zajistit při dynamické alokaci? Uveďte příklad. ### 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). 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).
@@ -435,7 +457,7 @@ 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Ě ### 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) [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. Explicitní instance je způsob, jak předem donutit kompilátor vytvořit šablonu - instanci generické funkce, než je použita. Normálně mám šablonu v `.hpp` souboru, **explicitní instanci** mám v `.cpp` souboru.
```cpp ```cpp
template int secti<int>(int, int); template int secti<int>(int, int);
``` ```
@@ -449,32 +471,241 @@ T secti(T a, T b);
ale můžu místo toho do `cpp` souboru napsat: ale můžu místo toho do `cpp` souboru napsat:
```cpp ```cpp
template <typename T> template <typename T> //hpp?
T secti(T a, T b) {
T secti(T a, T b) { //cpp
return a + b; return a + b;
} }
template int secti<int>(int, int); // explicitní instance 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. Takže definuju šablonu v hpp, a v cpp řeknu, jaké přesné šablony pro to využiju.
Also to umožní fungování je některým typům?
Takže: Takže:
- umožní použití jen několik typů, které si určím - umožní použití jen několik typů, které si určím
- zrychlý to kompilaci - zrychlý to kompilaci
### 13) Jak jsou obvykle parametrizovány šablony tříd? ### 13) Jak jsou obvykle parametrizovány šablony tříd? (odpověděl jsem na jinou otázku, genius...)
... dodelat
### 14) V čem spočívá problém vícenásobného dědění? Jak je možné tomuto problému zabránit? ### 14) V čem spočívá problém vícenásobného dědění? Jak je možné tomuto problému zabránit?
Největší problém je tzv. "diamond problem", který už jsem řešil v jedné otázce v OOP. Jde o to, že při dědění po druhé generaci může u vícenásobném dědění (zdědění ze dvou tříd najednou) dojít k dvojitéme zdědění členů z původní bázové třídy (v tomto případě "dědovi"). Zabránit tomu jde pomocí tzv. virtuálního dědění. (viz otázkac v OOP)
### 15) Co je to zapouzdření a čemu je dobré? ### 15) Co je to zapouzdření a čemu je dobré?
Zapouzdření je koncept ochrany vnitřního stavu objektu. Nemusí být žádoucí, aby externí funkce/objekty/kód měli přímí přístup ke členům objektu, proto se implementuje vrstva jejich ochrany.
Dobrý příklad jsou například **gettery** a **settery**. Místo toho, aby se přímo přistupovalo k vnitřní proměnné, tak je vnitřní proměnná `private` a implementuje se sunkce, která je přístupné a umí proměnnou změnit (tzv. **setter**) nebo funkce, která tu proměnnou umí přečíst (tzv. **getter**)
Je to jeden ze základních principů OOP.
### 16) Jak lze využít implicitní hodnoty argumentu funkce? Uveďte příklad. ### 16) Jak lze využít implicitní hodnoty argumentu funkce? Uveďte příklad.
Implicitní hodnota argumentu funkce mi umožňuje při volání nezadávat všechny argumenty a **místo toho použít nějakou předvyplněnou hodnotu**, které se použije, když hodnotu specificky neurčím. Např:
```cpp
int soucet(int a, int b = 0) {return a + b;}
//...
soucet(5, 3); // vraci 8
soucet(5); // vraci 5 (b = 0)
int f(int a = 1, int b); // chyba
```
Je potřeba psát implicitní hodnoty **zprava doleva**. Když vyplňuji hodnoty, tak se totiž vyplňují zleva. Jinak to nebude fungovat, nebylo by jasné, jaké mám být chování vyplňování.
### 17) Jaký je rozdíl mezi deklarací třídy pomocí class a struct? ### 17) Jaký je rozdíl mezi deklarací třídy pomocí class a struct?
### 18) Co je to konverzní konstruktor? [geeks for geeks](https://www.geeksforgeeks.org/cpp/structure-vs-class-in-cpp/)
V podstatě jsou velmi podobné. Hlavní a největší je automatická přístupnost členů (která se nastaví bez explicitního udání). U class je to **private** a struct je to **public**
```cpp
struct A
{
int x; //je public
};
class B
{
int x; //je private
}
```
### 18) Co je to konverzní konstruktor? RADĚJI SE NA TO JEŠTĚ JUKNOUT
Konverzní konstruktor je vlastně normální konstruktor s jedním parametrem, který umožňuje převedení nějakého typu na třídu.
```cpp
class A {
public:
int a
A(int x) {this->a = x;}
};
void f(A obj) {}
f(10); //tady proběhne konverze
```
zajímavé je použití s modifikátorem `explicit`, který zabrání zjednodušení typu.
```cpp
//udajne smim toto
A a(5.7);
//a i toto
A a = 5.6;
```
Pokud ale:
```cpp
class A {
public:
int a
explicit A(int x) {this->a = x;} //explicit
};
void f(A obj) {}
f(10); //tady proběhne konverze
```
Tak
```cpp
//smim toto
A a(5.7); //zmeni na 5
//a nesmim toto
A a = 5.7;
```
### 19) Jaký je rozdíl mezi statickou a dynamickou vazbou? ### 19) Jaký je rozdíl mezi statickou a dynamickou vazbou?
Vazba je zpsůsob přiřazení funkci ke svému bloku a zde mluvíme zpravidla o **třídach**.
**Statická vazby:**
Když mám normální obyčejnou funkci ve třídě např:
```cpp
class Zvire
{
public:
void zvuk() {cout << "Zvuk zvírete\n";}
};
class Pes : public Zvire
{
public:
void zvuk() { out << "Haf!\n";}
};
int main()
{
Zvire z = Pes(); // Objekt Pes je "převlečen" na Zvire
z.zvuk(); // Zavolá Zvire::zvuk() - "Zvuk zvírete"
return 0;
}
```
Tak rozhodnutí o přiřazení fuknce ke třídě (a jejím objektům) proběhne při kompilaci. Při běhu programu je to rychlé a efektivní, ale je to pevně dané a neflexibilní. **Volaná funkce se rozhodne dle typu objektu a ne podle opravdového typu instance.**
**Dynamická vazby:**
Pokud chci vyřešit tento problém, můžu donutit kompilátor, aby zařídil, že se program aktivně za běhu pamatuje, jakého typu jsou objekty a na jaké funkce odkazují. To je ale pomalejší a paměťově náročnější. Zařizuji to pomocí `virutal` před funkcí u bázové třídy:
```cpp
class Zvire
{
public:
virtual void zvuk() { cout << "Zvuk zvírete\n"; }
virtual ~Zvire() {}
};
class Pes : public Zvire
{
public:
void zvuk() override { cout << "Haf!\n"; }
};
int main()
{
Zvire* z = new Pes(); // Ukazatel na Zvire, ale skutečný objekt je Pes
z->zvuk(); // Zavolá Pes::zvuk() - "Haf!"
delete z;
return 0;
}
```
Technicky je to zařízené pomocí tzv. **vtable** neboli tabulky virtuálních funkcí.
### 20) Jaký je význam klíčového slova auto? Lze ho použít vždy? ### 20) Jaký je význam klíčového slova auto? Lze ho použít vždy?
`auto` se používá jako náhrada datové typu. Kompilátor sám pozná a automaticy použije datový typ, který uzná za vhodný. To nám může ulehčit práci v různých případech, například u iterátorů.
`auto` ale nelze použít vždy, problém je třeba používání **u definování argumentů funkce** nebo
### 21) Co přesouvací (move) kontruktor? ### 21) Co přesouvací (move) kontruktor?
Přesouvaní konstruktor slouží k převzetí zdrojů jiného objektu. V podstatě přijme hodnoty původního objektu (mělce včetně ukazatelů) a pak vymaže původní objekt (nebo ho vyprázdní).
Např:
```cpp
class Trida {
public:
int* data;
A(int x) {data = new int(x);} //konstruktor
// move konstruktor
A(A&& other) { //rvalue reference -> bere pravou stranu x = y -> tedy y
data = other.data; // převezme ukazatel
other.data = nullptr; // zabrání double delete
}
~A() {
delete data;
}
};
```
Pak jde například:
```cpp
Trida a1 = Trida(20); //prirazuji rvalue hodnotu do a1 pres move consturtor
Trida a2(30); //delam pomocny objekt
Trida a3 = Std::move(a2); //prirazuji pomocny a2 pres move constructor
//Std::move() zmeni svuj obsah na rvalue, takze se zavola move consturctor a ne kopirovaci konstructor
```
V podstatě jde o to, že konstruktory se volají dle toho, jestli je přiřazována **rvalue** neb **lvalue**. Lvalue je standardní hodnota jako třeba jiný objekt. Rvalue jsou dočasné objekty, které brzo přestanou existovat. Funkce Std::move() změní svoji hodnotu na rvalue, pak by se něměla ideálně takové změněná hodnotu už používat.
Ale tady jsi raději najděte o čem mluvím, sám tomu moc nerozumím.
### 22) Co je pravidlo tří (rule of three)? ### 22) Co je pravidlo tří (rule of three)?
[Rule of three](https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)#Rule_of_five) (nebo alternativně *rule of five*) je pravidlo, které se zabývá tím, jak správně vytvořit třídu a hlavně tedy, co všechno má obsahovat.
**Rule of three: třída má obsahovat**
- destruktor
- kopírovací konstruktor
- kopírovací operátor `Trida& operator=(const Vector& other)`
Kopírovací operátor se stará o přiřezaní do objektu, pokud **již existuje**. Kopírovací konstruktor dělá nový objekt již z existujícího objektu, kopíruje do jiného objektu. Destruktor se stará o správné uvolnění paměti.
**Rule of five:** rozšiřuje funkční objekt ještě o:
- move konstruktor
- move operátor `Trida& operator=(Vector&& other)`
Rozšiřuje pravidlo o části spojené s **rvalue**.
**Celé toto se dělá hlavně pro nějakou správnou práci s dynamickou pamětí v objektech.**
### 23) Jaký je tvar definice lambda funkce v C++? Uveďte příklad a popište, co funkce dělá. ### 23) Jaký je tvar definice lambda funkce v C++? Uveďte příklad a popište, co funkce dělá.
Lambda funkce jsou způsob jak zkrátit kód a udělat ho efektivnější a čitelnější. Jejich syntax je takový:
```cpp
[capture](parametry) -> navratovy_typ {telo funkce};
//ale zkráceně i:
[nic](parametry){telo};
//napr
auto lambda = [=](int a, int b)->int{return a + b;}
//zkráceně
auto lambda2 = [](int a, int b) {return a + b;}
//pak
std::cout << lambda(10, 20);
```
Obvykle se lambda funkce šikovně ukládá do proměnné. Používá se `auto`, protože to automaticky určí složitý typ funkce lambda napr: `std::function<int(int)>`. Lambda má několik částí
- **capture** -> `[]` určuje jak jsou pro ní viditelné proměnné z okolního scope, např. `[=]` znamená, že vidí všechny členy ve scopu (třeba fce), kde se nachází. Když nic nepotřebuji, tak vynechám.
- **parametry** -> `()` normální argumenty/parametry jako u normálná fuknce. Pro `(int a, char b)` přijímá interger a char.
- **-> typ** -> tím se určuje návratový typ lambda fce, ale kompilátor na to umí přijít sám, tak se to většinou vynechá.
- **tělo** -> `{};` Zde je kód, co lambda provede.
**Toto téma jsem trochu zpracoval v dokumentech.**
# STL kontejnery # STL kontejnery
### 1) Co je to kontejner? ### 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. 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.
@@ -618,5 +849,6 @@ Jinak je třeba definovat `>` `<` pomocí přetěžování operátorů a nebo do
- Co je to REST rozhraní? - Co je to REST rozhraní?
# Otázky proč # Otázky proč
- proč píšu kopírovací konstruktor a nepřetěžuju operátor =? - proč píšu kopírovací konstruktor a nepřetěžuju operátor =? -> protože konstruktor konstruuje a operátor přiřazuje existujícímu objektu.
- - jak funguje mělká/hluboká kopie kontejnerů?
- jak je to s výjimkama? nekdy chytam jako ciste typ a nekdy jako objekt, to mam asi spatne a musim to proverit