|
|
|
|
@@ -1,9 +1,12 @@
|
|
|
|
|
|
|
|
|
|
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í
|
|
|
|
|
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.
|
|
|
|
|
```cpp
|
|
|
|
|
### 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.
|
|
|
|
|
```cpp
|
|
|
|
|
class Trida
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
@@ -16,47 +19,273 @@ Poznámka: Příklady jsou zjednodušené a ne vždy jsou 100% syntakticky práv
|
|
|
|
|
Trida objekt;
|
|
|
|
|
objekt.cislo = 10;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
2) 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í
|
|
|
|
|
```
|
|
|
|
|
### 2) Jak je určena viditelnost členských proměnných a metod?
|
|
|
|
|
- **public** -> přístup možný odkudkoli z programu (ze scope)
|
|
|
|
|
- **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í
|
|
|
|
|
```cpp
|
|
|
|
|
class Trida
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
int a;
|
|
|
|
|
private:
|
|
|
|
|
int b;
|
|
|
|
|
protected:
|
|
|
|
|
int b;
|
|
|
|
|
private:
|
|
|
|
|
int c;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Podtrida : public Trida {};
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
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();`
|
|
|
|
|
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
|
|
|
|
|
- **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?
|
|
|
|
|
- Co je to bázová třída a čím se vyznačuje?
|
|
|
|
|
- Uveďte příklad deklarace plně virtuální metody?
|
|
|
|
|
- Co je to implicitní konstuktor?
|
|
|
|
|
- Co je to kopírovací konstruktor?
|
|
|
|
|
- Jaké jsou možnosti dědění? Uveďte příklady.
|
|
|
|
|
- Co je to virtuální dědění a k čemu je dobré?
|
|
|
|
|
- Které vlastnosti rodiče potomek nedědí?
|
|
|
|
|
- Co je to přetížení? Uveďte příklad (několik řádek kódu, ze kterých bude zřejmé, o co jde).
|
|
|
|
|
- Jaký je rozdíl mezi přepsáním (override) a přetížením (overload)?
|
|
|
|
|
- Co je vazba typu kompozice? Uveďte příklad (několik řádek kódu, ze kterých bude zřejmé, o co jde).
|
|
|
|
|
- Co je vazba typu asociace? Uveďte přiklad (několik řádek kódu, ze kterých bude zřejmé, o co jde).
|
|
|
|
|
- Co reprezentuje klíčové slovo this?
|
|
|
|
|
- Jaký je rozdíl mezi referencí a ukazatelem?
|
|
|
|
|
- Jaký je rozdíl mezi mělkou a hlubokou kopií?
|
|
|
|
|
### 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();`
|
|
|
|
|
### 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
|
|
|
|
|
- **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
|
|
|
|
|
### 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ů.
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
### 6) Co je to bázová třída a čím se vyznačuje?
|
|
|
|
|
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 (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í.
|
|
|
|
|
**Prostě je to třída z které někdo dědí, to je všechno.**
|
|
|
|
|
### 7) 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";}
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
### 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á.
|
|
|
|
|
|
|
|
|
|
**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
|
|
|
|
|
### 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:**
|
|
|
|
|
|
|
|
|
|
```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
|
|
|
|
|
//nastavím svému nově vytvořenému objektu hodnoty tak, jak se mi to hodí
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
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ů.
|
|
|
|
|
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
|
|
|
|
|
### 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.)
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
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 {};
|
|
|
|
|
```
|
|
|
|
|
### 12) Které vlastnosti rodiče potomek nedědí?
|
|
|
|
|
- **konstruktory a destruktory**
|
|
|
|
|
- **privátní členy**
|
|
|
|
|
- **`operator=`**
|
|
|
|
|
- statické členy (jdou zavolat, ale neexistuje kopie, kinda nieche)
|
|
|
|
|
### 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ěž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)
|
|
|
|
|
|
|
|
|
|
### 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.
|
|
|
|
|
|
|
|
|
|
**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í
|
|
|
|
|
### 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:
|
|
|
|
|
```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...
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
### 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.
|
|
|
|
|
```cpp
|
|
|
|
|
class Ucitel
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
void uc() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Student
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
Ucitel* ucitel; // asociace
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
//nejaky konstruktor priradi ucitle..
|
|
|
|
|
|
|
|
|
|
void studuj() {ucitel->uc();}
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
### 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` taky ulehčuje předání všech členů třídy/objektu lambda funkci
|
|
|
|
|
### 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.
|
|
|
|
|
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 - vytvoření
|
|
|
|
|
p = &b; //ukazatel ukazuje na b - změna adresy
|
|
|
|
|
|
|
|
|
|
int& r = a; //reference ukazuje na a - vytvoření
|
|
|
|
|
r = b; //reference nabírá hodnoty b, teď a = b - změna hodnoty ne adresy
|
|
|
|
|
//r = &b //NELEGÁLNÍ
|
|
|
|
|
// a = b; je ekvivalentní
|
|
|
|
|
```
|
|
|
|
|
viz dokument, co jsem na to udělal ve stejném repu
|
|
|
|
|
### 19) 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
|
|
|
|
|
@@ -87,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())`
|
|
|
|
|
|
|
|
|
|
**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.
|
|
|
|
|
Přetěžování operátorů je implementace fungování znaků operátorů jako `+`, `-`, `>`, etc. pro objekty tříd, co napíšu.
|
|
|
|
|
@@ -120,7 +351,7 @@ 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};
|
|
|
|
|
return Vec(a.x + b.x);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
@@ -128,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ů)**
|
|
|
|
|
### 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:
|
|
|
|
|
- `.`
|
|
|
|
|
- `::`
|
|
|
|
|
- `?:`
|
|
|
|
|
- `.` - member dot
|
|
|
|
|
- `::` - scope resolution
|
|
|
|
|
- `?:` - ternary operator
|
|
|
|
|
- `.*` -
|
|
|
|
|
- `sizeof`
|
|
|
|
|
- `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í.**
|
|
|
|
|
|
|
|
|
|
@@ -164,7 +398,8 @@ 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;`
|
|
|
|
|
**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.
|
|
|
|
|
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).
|
|
|
|
|
|
|
|
|
|
@@ -222,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Ě
|
|
|
|
|
[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
|
|
|
|
|
template int secti<int>(int, int);
|
|
|
|
|
```
|
|
|
|
|
@@ -236,32 +471,241 @@ 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) {
|
|
|
|
|
template <typename T> //hpp?
|
|
|
|
|
|
|
|
|
|
T secti(T a, T b) { //cpp
|
|
|
|
|
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 definuju šablonu v hpp, a v cpp řeknu, jaké přesné šablony pro to využiju.
|
|
|
|
|
|
|
|
|
|
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?
|
|
|
|
|
### 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?
|
|
|
|
|
|
|
|
|
|
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é?
|
|
|
|
|
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.
|
|
|
|
|
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?
|
|
|
|
|
### 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?
|
|
|
|
|
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?
|
|
|
|
|
`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?
|
|
|
|
|
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)?
|
|
|
|
|
[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á.
|
|
|
|
|
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
|
|
|
|
|
### 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.
|
|
|
|
|
@@ -402,4 +846,9 @@ Jinak je třeba definovat `>` `<` pomocí přetěžování operátorů a nebo do
|
|
|
|
|
- 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í?
|
|
|
|
|
- Co je to REST rozhraní?
|
|
|
|
|
|
|
|
|
|
# Otázky proč
|
|
|
|
|
- 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
|