oprava nekterych chyb v otazkach
This commit is contained in:
@@ -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.)
|
||||
|
||||
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í
|
||||
### 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.
|
||||
```cpp
|
||||
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;
|
||||
}
|
||||
```
|
||||
### 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
|
||||
}
|
||||
```
|
||||
### 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();`
|
||||
### 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
|
||||
- **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ů.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
### 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.**
|
||||
### 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/)
|
||||
|
||||
**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";}
|
||||
};
|
||||
```
|
||||
### 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á.
|
||||
|
||||
**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?
|
||||
### 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
|
||||
@@ -103,12 +116,12 @@ public:
|
||||
|
||||
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
|
||||
//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.
|
||||
### Jaké jsou možnosti dědění? Uveďte příklady.
|
||||
### 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**
|
||||
@@ -139,7 +152,7 @@ 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é?
|
||||
### 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.)
|
||||
|
||||

|
||||
@@ -168,12 +181,12 @@ public:
|
||||
//zdědí obě vlastnosti bez duplikace
|
||||
class Bat: public Mammal, public WingedAnimal {};
|
||||
```
|
||||
### Které vlastnosti rodiče potomek nedědí?
|
||||
### 12) Které vlastnosti rodiče potomek nedědí?
|
||||
- **konstruktory a destruktory**
|
||||
- **privátní členy**
|
||||
- **funkce přetěžování operátorů**
|
||||
- **`operator=`**
|
||||
- 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ěžovat jdou:
|
||||
- funkce
|
||||
@@ -195,13 +208,13 @@ bool is_not_zero(bool 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)
|
||||
|
||||
### 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.
|
||||
|
||||
**Přetížení**:
|
||||
@@ -209,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í**:
|
||||
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:
|
||||
```cpp
|
||||
class FEL {};
|
||||
@@ -226,7 +239,7 @@ public
|
||||
//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.
|
||||
```cpp
|
||||
class Ucitel
|
||||
@@ -246,10 +259,10 @@ public:
|
||||
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` 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.
|
||||
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á.
|
||||
|
||||
@@ -257,15 +270,16 @@ V podstatě je podobná konstantnímu ukazateli. Není možné změnit, na co re
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
|
||||
int* p = &a; #ukazatel ukazuje na a
|
||||
p = &b; # ukazatel ukazuje na b
|
||||
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
|
||||
r = b; #reference nabírá hodnoty b, teď a = b
|
||||
# a = b; je ekvivalentní
|
||||
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
|
||||
### 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.
|
||||
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í.
|
||||
|
||||
@@ -302,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.
|
||||
@@ -335,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);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -343,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í.**
|
||||
|
||||
@@ -379,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).
|
||||
|
||||
@@ -437,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);
|
||||
```
|
||||
@@ -451,24 +471,22 @@ 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?
|
||||
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>`
|
||||
### 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?
|
||||
|
||||
@@ -831,5 +849,6 @@ Jinak je třeba definovat `>` `<` pomocí přetěžování operátorů a nebo do
|
||||
- Co je to REST rozhraní?
|
||||
|
||||
# Otázky proč
|
||||
- proč píšu kopírovací konstruktor a nepřetěžuju operátor =?
|
||||
- jak funguje mělká/hluboká kopie kontejnerů?
|
||||
- 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
|
||||
Reference in New Issue
Block a user