- *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 using namespace std; 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ě...