vypracovani temat z 3. prednasky
This commit is contained in:
183
Přetěžování operátorů.md
Normal file
183
Přetěžování operátorů.md
Normal file
@@ -0,0 +1,183 @@
|
||||
- *operator overloading*
|
||||
- prakticky definování operací s operátory (např. +, -, /, etc.) pro objekty
|
||||
- [oficiální dokumentace](https://isocpp.org/wiki/faq/operator-overloading/1000)
|
||||
- [geeks for geeks](https://www.geeksforgeeks.org/cpp/operator-overloading-cpp/)
|
||||
- [krátké YT video](https://www.youtube.com/watch?v=9tHu4mWtrnM&pp=ygUYY3BwIG9wZXJhdG9yIG92ZXJsb2FkaW5n) které jsem trochu vykradl
|
||||
|
||||
Když si vytvoříme třídu, chceme někdy mít jednoduchou práci při pracování s více jejími objekty. Pokud mám třeba třídu `ComplexNumber`" a chci sečíst 2 její objekty, musel bych normálně vytvořit vlastní funkci, která mi to umožní. Přetěžování operátorů mi ale zjednoduší práci. **Místo sepsání funkce pro součet si nadefinuji, že pokud sečtu 2 objekty pomocí operátoru `+`, tak se sečtou.**
|
||||
|
||||
Příklad:
|
||||
```cpp
|
||||
class Number
|
||||
{
|
||||
public:
|
||||
int n;
|
||||
|
||||
Number(int set_n) {n = set_n;}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
Number a(5);
|
||||
Number b(10);
|
||||
|
||||
Number c = a + b; //TOTO BY SE NÁM HODILO, ALE VYHODÍ TO ERROR
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
V kódu se snažím sečíst dva různé objekty, ale nejde to, protože součet dvou objektů typu `Number` není definován (stejně jako není definován součet 2 objektů typu chyba, nebo čehokoli jiného).
|
||||
**Dostanu error ve stylu:** `Invalid operands to binary expression ('Number' a...)`
|
||||
|
||||
**Já to ale můžu spravit tím, že si operaci pro součet sám definuju...**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
|
||||
class Number
|
||||
{
|
||||
public:
|
||||
int n;
|
||||
|
||||
Number(int set_n) {n = set_n;}
|
||||
|
||||
Number operator+(const Number &numA) //reference na objekt napravo od +
|
||||
{
|
||||
return Number(this->n + numA.n)
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
Number a(5);
|
||||
Number b(10);
|
||||
|
||||
Number c = a + b; //TED FUNGUJE
|
||||
|
||||
std::cout << c.n << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Takže co se děje...
|
||||
Tady je příklad binárního operátoru `+`. V podstatě to je ekvivalent zavolání funkce z objektu `a`, která by se mohla jmenovat `vrat_muj_soucet_s_necim_jak_objekt` (hrozné jméně, já vím). **V podstatě `+` je nyní funkce objektu nalevo a to co je napravo od `+` je argument této funkce.**
|
||||
|
||||
Je dobrý ale vědět, že operátory se nemusí přetěžovat jenom přes funkci objektu/třídy. Přetěžovat se dá i pomocí **nečlenské funkce** (normální funkce, která není součástí žádné třídy).
|
||||
|
||||
Příklad:
|
||||
```cpp
|
||||
Number operator+(const Vec& a, const Vec& b)
|
||||
{
|
||||
return Vec{a.x + b.x};
|
||||
}
|
||||
```
|
||||
Toto funguje, i když to není v třídě `Number`. Pomocí nečlenské funkce lze mít součty 2 různých objektů, kde nalevo není objekt třídy, např: `5 + a`.
|
||||
|
||||
# Typy operátorů a jejich přetěžování
|
||||
Existuje více typů operátorů valná většina z nich se dá přetěžovat. Přetěžovat ale nelze operátory:
|
||||
- `.`
|
||||
- `::`
|
||||
- `?:`
|
||||
- `sizeof`
|
||||
- `typeid`
|
||||
## Binární operátory
|
||||
- operáty s více stranami
|
||||
- `např +, -, /, %` etc.
|
||||
|
||||
Ve třídě:
|
||||
```cpp
|
||||
class Vec
|
||||
{
|
||||
public:
|
||||
int x;
|
||||
|
||||
Vec operator+(const Vec& other)
|
||||
const {
|
||||
return Vec{x + other.x};
|
||||
}
|
||||
};
|
||||
```
|
||||
`a + b` je prakticky `a.operator+(b)`
|
||||
|
||||
Mimo funkci:
|
||||
``` cpp
|
||||
Vec operator+(const Vec& a, const Vec& b)
|
||||
{
|
||||
return Vec{a.x + b.x};
|
||||
}
|
||||
```
|
||||
`a + b` je prakticky `operator+(a, b)`
|
||||
|
||||
## Unární operátory (prefixové)
|
||||
- mají pouze jeden člen
|
||||
- operátory prefixové se píšou před členem
|
||||
- př: `-a, ++a`
|
||||
|
||||
Ve třídě:
|
||||
```cpp
|
||||
class Vec
|
||||
{
|
||||
public:
|
||||
int x;
|
||||
|
||||
Vec operator-()
|
||||
const {
|
||||
return Vec{-x};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
`-a` je prakticky funkce `a.operator-()`
|
||||
`const` v tomto případě znamená, že se nezmění objekt `this`. Ono to v tomto případě ani nedává smysl, jelikož chceme vrátit `-a`, ale nechceme změnit `a` na `-a`... Tho, ten syntax je matoucí.
|
||||
**Přesněji** `const` před `{}` znamená, že metoda **nesmí měnit objekt** na kterém byla zavolaná.
|
||||
Nesmím pak měnit proměnné objektu a volat jeho funkce, co nejsou stejně `const`. **Umožní mi to ale volat funkci i na const objektu**.
|
||||
|
||||
## Unární operátory (postfixové)
|
||||
- pouze jeden člen
|
||||
- píší se za členem
|
||||
- mají dummy parametr -> to je trik jak odlišit `++a` od `a++`
|
||||
- např: `a++`
|
||||
|
||||
```cpp
|
||||
Vec operator++(int)
|
||||
{
|
||||
Vec old = *this;
|
||||
x++; //kde x je promenna Vec
|
||||
return old;
|
||||
}
|
||||
```
|
||||
`a++` je prakticky `a.operator++(0)`
|
||||
`this` je ukazatel a já nechci kopírovat ukazatel, ale to na co ukazuje, proto:
|
||||
`Vec old = *this;`
|
||||
|
||||
**Proč se to sakra píše jako:** `operator++(int)` **s int?** (`a.operator++(0)` -> dělá kompilátor). Protože by jinak nešlo rozlišit `++a` a `a++`. Proto je konvence, že `a++` je `operator++(int)` a `++a` je `operator++()`.
|
||||
|
||||
## Ostatní
|
||||
Operátor přístupu:
|
||||
```cpp
|
||||
int& operator[](size_t i)
|
||||
{
|
||||
return data[i];
|
||||
}
|
||||
```
|
||||
`a[i]` -> `a.operator[](i)`
|
||||
`int&` protože jsem šetrný a vracím referenci na prvek -> něco co ukazuje na jeho hodnotu a ne jeho
|
||||
|
||||
**Funktor**:
|
||||
```cpp
|
||||
class Functor
|
||||
{
|
||||
public:
|
||||
int operator()(int x) {
|
||||
return x * 2;
|
||||
}
|
||||
};
|
||||
```
|
||||
`a(i)` -> `f.operator()(i)`
|
||||
|
||||
Funktory jsou důležité! Funktory jsou objekty, které se chovají jako funkce a hádám (teď to nedokážu říct), že o nich uslyšíme ještě dost.
|
||||
Jejich hlavní smysl je **být něco mezi objektem a funkcí**. Funkce nemá žádnou paměť, což znamená, že vždy dává stejný výsledek při stejném vstupu (i mean ne nutně, jako když použiju náhodná čísla, tak ne... buuuhuuu, ale chápeme se...).
|
||||
Funktor mi umožňuje udělat objekt, který "předstírá, že je funkce". Pamatuje si svoje operace a může ukládat do vnitřních proměnných při každém zavolání/upravě, etc...
|
||||
|
||||
Dále jde přetěžovat třeby `->`. Operátorů je opravdu hodně...
|
||||
Reference in New Issue
Block a user