Rozdíly

Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.

Odkaz na výstup diff

public:pb161:fall14_cviko09 [2018/02/24 19:10] (aktuální)
Řádek 1: Řádek 1:
 +====== Cvičení 09 ======
  
 +===== Úvod do cvičení =====
 +Na tomto cvičení budete pracovat s operátory, vyzkoušíte si implementaci operátorů jako metod i jako samostatných funkcí. Naučíte se vytvořit kopii objektu, jehož typ není v dobře překladu známý. Na tomto cvičení využijete upravené třídy ze druhé domácí úlohy, které si můžete stáhnout {{:​public:​pb161:​fall14_cviko09.zip|zde}}.
 +
 +Kromě jednoduchých tříd //Circle// a //​Rectangle//​ přibude ještě jeden potomek třídy //​Geometry2D//​ a to třída //​ObjectSet//​. Ta představuje množinu jednoduchých objektů, které jsou uložené v privátním atributu //objects// typu //​std::​vector//​. Pomocí operátorů bude možné provádět základní množinové operace -- průnik, sjednocení a rozdíl. Prozatím pro toto cvičení využijeme pro ukládání prvků množiny třídu //​std::​vector//,​ která sice není ideální, ale práce s ní je jednodušší.
 +
 +==== Krátké povídání o operátorech v C++ ====
 +
 +=== Metoda či funkce ===
 +
 +Obecně lze říct, že operátory lze implementovat buď jako samostatné funkce, nebo jako členské metody (ze zjevných důvodů ovšem nikdy současně). Kdy tedy implementovat operátor jako členskou metodu a kdy jako samostatnou funkci?
 +
 +Pro zjednodušení se lze řídit těmito doporučeními:​
 +  * Několik specifických operátorů (''​operator[]'',​ ''​operator='',​ ''​operator()''​ a ''​operator->''​) lze implementovat jenom jako členské metody.
 +  * Pokud je to unární operátor, nechť je implementován jako členská metoda.
 +  * Pokud je to binární operátor, který nemění své operandy, nechť je implementován jako samostatná funkce.
 +  * Ovšem pokud se binární operátor nechová k oboum svým operandům totožně, například tím, že mění stav levého operandu, nechť je implementován jako metoda.
 +
 +Většinou je operátor malá funkce, kterou bychom nejraději napsali současně s definicí do hlavičkového souboru. Protože by ale docházelo k problémům při překladu (linker by si neporadil s vícenásobnou definicí funkce -- operátoru),​ je třeba definici operátoru uvést ​ klíčovým slovem ''​inline'':​
 +
 +<code cpp SomeObject.h>​
 +...
 +inline bool operator==(const SomeObject &lhs, const SomeObject &rhs) {
 +    // testování shody
 +}
 +</​code>​
 +
 +=== Operátory porovnání ===
 +Při implementaci operátorů porovnání je vhodné si uvědomit, že existuje celkem 6 relačních operátorů,​ které lze rozdělit na dvě skupiny:
 +  * relace ekvivalence:​ ''​operator==''​ a ''​operator!=''​
 +  * relace uspořádání:​ ''​operator<'',​ ''​operator<​='',​ ''​operator>''​ a ''​operator>​=''​
 +
 +Lze celkem s jistotou prohlásit, že pokud umožníme zápis ''​a < b'',​ bude někdy nějaký programátor chtít zapsat ''​b > a''​. Proto pokud implementujete alespoň jeden operátor ze skupiny, je velmi vhodné implementovat všechny. Abychom ale zamezili duplikacím kódu, je vhodné implementovat relační operátory nějak takto:
 +<code cpp SomeObject.h>​
 +inline bool operator==(const SomeObject &lhs, const SomeObject &rhs) { /* porovnávání */ }
 +inline bool operator!=(const SomeObject &lhs, const SomeObject &rhs) { return !(lhs == rhs); }
 +inline bool operator<​ (const SomeObject &lhs, const SomeObject &rhs) { /* porovnání */ }
 +inline bool operator<​=(const SomeObject &lhs, const SomeObject &rhs) { return !(lhs > rhs); }
 +inline bool operator>​ (const SomeObject &lhs, const SomeObject &rhs) { return rhs < lhs; }
 +inline bool operator>​=(const SomeObject &lhs, const SomeObject &rhs) { return !(lhs < rhs); }
 +</​code>​
 +
 +=== Příjemné používání přetížených operátorů ===
 +
 +Při přetěžování je vhodné se navíc řídit následujícími radami, aby bylo používání přetížených operátorů snadné, bezproblémové a intuitivní.
 +  * Pokud přetěžujete operátory, neměňte jejich sémantiku. ''​+''​ by mělo věci sčítat, ''​-''​ zase odečítat.
 +  * Pokud umožníte ''​a++'',​ umožněte taktéž ''​++a''​.
 +  * Pokud sémantika binárního operátoru umožňuje komutativitu (=nezávislost pořadí operandů), měli byste ji taktéž zohlednit.
 +  * Pokud implementujete operátory sčítání,​ násobení a další, implementujte taktéž i jejich zkrácenou variantu:
 +<code cpp NumericOperators.h>​
 +class A {
 +    int number;
 +public:
 +    A &​operator+=(const A &other) {
 +        number += other.number;​
 +        return *this;
 +    }
 +};
 +inline A operator+(A lhs, const A &rhs) {
 +    return lhs += rhs;
 +}
 +</​code>​
 +<​note>​
 +Povšimněte si rozdílných typů parametrů funkce ''​operator+''​. První se bere hodnotou, protože si tak rovnou vytvoříme kopii a následně můžeme využít již implementovaného ''​operator+=''​.
 +</​note>​
 +
 +<note tip>Pro více informací si můžete přečíst například [[http://​stackoverflow.com/​questions/​4421706/​operator-overloading/​4421729|tento]] článek.</​note>​
 +===== První úkol =====
 +Operace sjednocení umožní sjednotit dvě množiny, případně přidat prvek do množiny. Tato operace je komutativní,​ to znamená, že nezáleží na pořadí operandů.
 +==== Zadání úkolu ====
 +
 +Implementujte ''​operator+''​ a ''​operator+=''​.
 +
 +  * ''​operator+''​ nesmí měnit stavy svých operandů
 +  * ''​operator+=''​ mění pouze svůj levý operand
 +  * Operátory napište tak, abyste
 +    * neduplikovali kód
 +    * používali správné typy parametrů funkcí/​metod
 +    * měli správný návratový typ funkcí/​metod
 +    * správně určili, který operátor má být funkcí a který metodou
 +    * podporovali komutativitu v případě, že jeden operand je množina a druhý je prvek množiny
 +  * Dejte si pozor, abyste nezpůsobovali memory leaky.
 +
 +<note tip>​std::​find_if,​ ObjectSet::​Compare</​note>​
 +
 +===== Druhý úkol =====
 +Implementujte kopírovací konstruktor,​ přiřazovací operátor a metodu ''​clone''​.
 +==== Zadání úkolu ====
 +
 +Cílem je implementovat kopírovací konstruktor,​ přiřazovací operátor a metodu ''​swap''​ dle návodu, který byl prezentován na přednášce.
 +
 +Kopírovací konstruktor implementujte tak, aby se vytvořila "​hluboká"​ kopie -- musíte vytvořit kopie všech prvků z původní množiny.
 +Pro správné zkopírování všech objektů implementujte do všech potomků ''​Geometry2D''​ virtuální metodu ''​clone'',​ jejíž hlavičku najdete v souboru //​Geometry2D.h//​.
 +
 +<note tip>
 +Použijte copy & swap idiom:
 +  - Implementace kopírovacího konstruktoru
 +  - Implementace metody swap
 +    * specializace funkce ''​std::​swap''​ je již poskytnuta
 +  - Implementace přiřazovacího operátoru, který bere parametr __**hodnotou**__ a volá metodu ''​swap''​
 +</​note>​
 +===== Třetí úkol =====
 +Operace rozdílu umožní odečíst od sebe dvě množiny, případně odebrat prvek z množiny.
 +==== Zadání úkolu ====
 +
 +Implementujte ''​operator-''​ a ''​operator-=''​.
 +
 +  * ''​operator-''​ nesmí měnit stavy svých operandů
 +  * ''​operator-=''​ mění pouze svůj levý operand
 +  * Operátory napište tak, abyste
 +    * neduplikovali kód
 +    * používali správné typy parametrů funkcí/​metod
 +    * měli správný návratový typ funkcí/​metod
 +    * správně určili, který operátor má být funkcí a který metodou
 +  * Dejte si pozor, abyste nezpůsobovali memory leaky.
 +
 +<note tip>​std::​find_if,​ ObjectSet::​Compare</​note>​
 +
 +
 +===== Čtvrtý úkol =====
 +Operace průniku umožní vybrat ty prvky z množin, které patří do obou množin.
 +==== Zadání úkolu ====
 +
 +Implementujte ''​operator&''​ a ''​operator&​=''​.
 +
 +  * ''​operator&''​ nesmí měnit stavy svých operandů
 +  * ''​operator&​=''​ mění pouze svůj levý operand
 +  * Operátory napište tak, abyste
 +    * neduplikovali kód
 +    * používali správné typy parametrů funkcí/​metod
 +    * měli správný návratový typ funkcí/​metod
 +    * správně určili, který operátor má být funkcí a který metodou
 +  * Dejte si pozor, abyste nezpůsobovali memory leaky.
 +
 +<note tip>​std::​find_if,​ ObjectSet::​Compare</​note>​
 +
 +===== Vzorové řešení =====
 +
 +{{:​public:​pb161:​fall14_cviko09_reseni.zip|Řešení}}
QR Code
QR Code public:pb161:fall14_cviko09 (generated for current page)