183 lines
5.5 KiB
Markdown
183 lines
5.5 KiB
Markdown
- *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ě... |