dodelane okruhy krom Qt, ale chtelo by to jeste trochu lasky
This commit is contained in:
@@ -106,6 +106,8 @@ public:
|
||||
//vracím objekt s novým ukazatelem u a
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
### 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í**:
|
||||
@@ -465,16 +467,227 @@ 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?
|
||||
Obvykle to je `template <typename T>`, ale `template <Class C>` je ekvivalentní.
|
||||
Můžu taky parametrizovat třeba konstantní hodnotou, např. `tepmlate <int N>` nebo více parametrů `template <typename T, typename U>`
|
||||
|
||||
### 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.
|
||||
@@ -619,4 +832,4 @@ Jinak je třeba definovat `>` `<` pomocí přetěžování operátorů a nebo do
|
||||
|
||||
# Otázky proč
|
||||
- proč píšu kopírovací konstruktor a nepřetěžuju operátor =?
|
||||
-
|
||||
- jak funguje mělká/hluboká kopie kontejnerů?
|
||||
Reference in New Issue
Block a user