Binární operátor, jako je například operátor sčítání +, musí být definován buď jako nestatická členská funkce třídy s jedním parametrem, nebo jako členská funkce bez třídy se dvěma parametry.

Zprávy kompilátoru, které jste dostali

Main.cpp:17:5: chyba: C++ vyžaduje specifikátor typu pro všechny deklarace operator+(Cat a, Cat b) ( ^ main.cpp:18:16: chyba: nelze inicializovat návratový objekt typu "int" s hodnotou rvalue typu "Cat *" vrátit novou Cat(a.value + b.value); ^~~~~~~~~~~~~~~~~~~~~~~~

řekněme, že vámi definovaný operátor nemá návratový typ.

Návratový typ nemusí mít pouze konverzní funkce. V případě operátoru sčítání musíte zadat typ návratové hodnoty.

Při přidávání dvou objektů třídy nemá smysl vracet ukazatel na objekt. V tomto případě nebudete moci řetězit operátory sčítání bez dalších operátorů a co víc, může dojít k úniku paměti.

Operátor musí vrátit samotný objekt, buď s kvalifikátorem const, nebo bez něj.

Jak bylo uvedeno výše, operátor může být deklarován jako nestatická členská funkce třídy s jedním parametrem.

V tomto případě může operátor + vypadat takto

Třída Cat ( private: int hodnota = 1; public: Cat(int _value) ( ​​​​hodnota = _value; ) Operátor Cat +(const Cat &a) const ( return Cat(this->value + a.value); ) ) ;

Třída Cat ( private: int hodnota = 1; public: Cat(int _value) ( ​​​​hodnota = _value; ) const Operátor Cat +(const Cat &a) const ( return Cat(this->value + a.value); ) );

Mohli byste přetížit operátora také pro reference rvalue, jako v

Operátor Cat +(const Cat &&a) const ( return Cat(this->value + a.value); )

Operátor Cat +(Cat &&a) const ( return Cat(this->value + a.value); )

ale za tohle jednoduchá třída, která nezachycuje velké zdroje, na tom nezáleží.

Všimněte si přítomnosti kvalifikátoru condt za seznamem parametrů. To znamená, že samotný objekt, který se bude nacházet na levé straně operátoru, se nezmění, stejně jako pravý objekt, protože jemu odpovídající parametr operátoru je také definován s kvalifikátorem const.

Mějte na paměti, že protože konstruktor třídy je deklarován jako konstruktor převodu, můžete v tomto případě přidat objekty Cat s čísly. Například,

#zahrnout class Cat ( private: int value = 1; public: Cat(int _value) ( ​​​​​value = _value; ) const Cat operátor +(const Cat &a) const ( return Cat(this->

Je na vás, zda je to oprávněné, na základě toho, jaký význam má tento operátor přidání. Pokud nechcete povolit takový implicitní převod z čísla na objekt Cat, můžete konstruktor deklarovat jako explicitní. V tomto případě se program nezkompiluje, pokud se pokusí přidat objekt Cat k číslu.

#zahrnout class Cat ( private: int hodnota = 1; public: explicit Cat(int _value) ( ​​​​​hodnota = _value; ) const Cat operátor +(const Cat &a) const ( return Cat(this->value + a.value); )); int main() ( Cat c1(10); c1 + 5,5; return 0; )

Pro tento program vygeneruje kompilátor chybovou zprávu podobnou následující

Prog.cpp:24:5: chyba: žádná shoda pro "operator+" (typy operandů jsou "Cat" a "double") c1 + 5.5; ^

Druhý způsob, jak deklarovat tento operátor, je deklarovat jej jako funkci, která není členem třídy. Vzhledem k tomu, že tato funkce musí mít přístup k hodnotě člena soukromé třídy , bude nutné ji deklarovat jako přátelskou funkci třídy.

Samotnou funkci můžete definovat jak uvnitř definice třídy, tak mimo ni.

Například,

#zahrnout class Cat ( private: int value = 1; public: Cat(int _value) ( ​​​​​value = _value; ) friend const Cat operator +(const Cat &a, const Cat &b) ( return Cat(a.value + b.value );)); int main() ( Cat c1(10); Cat c2(5); Cat c3 = c1 + c2; return 0; )

Mějte na paměti, že je špatný nápad deklarovat proměnné, které začínají podtržítkem. Obecně platí, že taková jména, která začínají podtržítkem, jsou rezervována pro kompilátor.

Je obvyklé, že parametry konstruktoru mají jména, která odpovídají jménům členů třídy. V tomto případě okamžitě vidíte, který parametr inicializuje kterého člena třídy. Takže byste mohli definovat konstruktor takto

Cat(int value) : value(value) ( ​​)

Pokud hodnota člena třídy nemůže nabývat záporných hodnot, je lepší ji a odpovídající parametr konstruktoru deklarovat jako typ unsigned int .

Dobrý den!

Touha napsat tento článek se objevila po přečtení příspěvku, protože mnoho důležitých témat v něm nebylo zveřejněno.

Nejdůležitější je zapamatovat si, že přetížení operátora je jen pohodlnější způsob volání funkcí, takže se nenechte unést přetížením operátora. Mělo by se používat pouze tehdy, když usnadňuje psaní kódu. Ale ne tolik, aby to ztěžovalo čtení. Koneckonců, jak víte, kód se čte mnohem častěji, než je zapsán. A nezapomeňte, že nikdy nebudete moci přetěžovat operátory v tandemu s vestavěnými typy, přetížit lze pouze vlastní typy/třídy.

Syntaxe přetížení

Syntaxe přetěžování operátorů je velmi podobná definici pojmenované funkce [e-mail chráněný], kde @ je identifikátor operátoru (např. +, -,<<, >>). Zvážit nejjednodušší příklad:
class Integer ( private: int value; public: Integer(int i): value(i) () const Integer operator+(const Integer& rv) const ( return (value + rv.value); ) );
V tomto případě je operátor orámován jako člen třídy, argument určuje hodnotu, která je na pravé straně operátoru. Obecně existují dva hlavní způsoby přetížení operátorů: globální funkce, třída přátelská, nebo inline funkce třídy samotné. Která metoda, pro který operátor je lepší, zvážíme na konci tématu.

Ve většině případů operátory (kromě podmíněných) vracejí objekt nebo odkaz na typ, na který odkazují jeho argumenty (pokud se typy liší, pak se rozhodnete, jak interpretovat výsledek vyhodnocení operátorů).

Přetížení unárních operátorů

Zvažte příklady přetížení unárních operátorů pro třídu Integer definovanou výše. Zároveň je definujeme jako přátelské funkce a vezmeme v úvahu operátory dekrementace a inkrementace:
class Integer ( private: int value; public: Integer(int i): value(i) () //unary + friend const Integer& operator+(const Integer& i); //unary - friend const Integer operator-(const Integer& i) ; //přírůstek předpony friend const Integer& operator++(Integer& i); //přírůstek s příponou přítel const Integer operator++(Integer& i, int); //předpona snížení friend const Integer& operator--(Integer& i); //postfix snížení přítele const Operátor celého čísla--(Integer& i, int); ); // unární plus nedělá nic. const Integer& operator+(const Integer& i) ( return i.value; ) const Integer operator-(const Integer& i) ( return Integer(-i.value); ) //verze prefixu vrátí hodnotu po přírůstku const Integer& operator++(Integer& i) ( i.value++; return i; ) //verze postfixu vrátí hodnotu před přírůstkem const Integer operator++(Integer& i, int) ( Integer oldValue(i.value); i.value++; return oldValue; ) //verze prefixu vrátí hodnota po dekrementaci const Celé číslo& operátor--(Celé číslo& i) ( i.hodnota--; return i; ) //verze postfixu vrátí hodnotu před snížením const Integer operátor--(Celé číslo& i, int) ( Integer oldValue(i.value ); i .value--; return oldValue; )
Nyní víte, jak kompilátor rozlišuje mezi prefixovou a postfixovou verzí dekrementace a inkrementace. V případě, že vidí výraz ++i, je zavolána funkce operator++(a). Pokud vidí i++, zavolá se operátor ++(a, int). To znamená, že se volá funkce přetíženého operátora++ a k tomu se ve verzi postfixu používá parametr dummy int.

Binární operátory

Zvažte syntaxi pro přetížení binárních operátorů. Pojďme přetížit jeden operátor, který vrací l-hodnotu, one podmíněný operátor a jeden příkaz, který vytváří novou hodnotu (definujeme je globálně):
class Integer ( private: int value; public: Integer(int i): value(i) () friend const Integer operator+(const Integer& left, const Integer& right); friend Integer& operator+=(Integer& left, const Integer& right); friend bool operator==(const Integer& left, const Integer& right); ); const Integer operator+(const Integer& left, const Integer& right) ( return Integer(left.value + right.value); ) Integer& operator+=(Integer& left, const Integer& right) ( left.value += right.value; return left; ) bool operator==(const Integer& left, const Integer& right) ( return left.value == right.value; )
Ve všech těchto příkladech jsou operátoři přetíženi pro stejný typ, není to však vyžadováno. Je možné například přetížit přidání našeho typu Integer a Float definovaného v jeho podobě.

Argumenty a návratové hodnoty

Jak vidíte, příklady používají různé cesty předávání argumentů funkcím a vracení hodnot operátorů.
  • Pokud není argument operátorem modifikován, v případě např. unárního plus, musí být předán jako odkaz na konstantu. Obecně to platí pro téměř všechny aritmetické operátory (sčítání, odčítání, násobení...)
  • Typ vrácené hodnoty závisí na povaze operátora. Pokud musí operátor vrátit novou hodnotu, musí být vytvořen nový objekt (jako v případě binárního plus). Pokud chcete zabránit změně objektu jako l-hodnoty, musíte jej vrátit jako const.
  • Operátoři přiřazení musí vrátit odkaz na změněný prvek. Také, pokud chcete použít operátor přiřazení v konstrukcích jako (x=y).f(), kde je funkce f() volána pro proměnnou x, poté, co k ní přiřadíte y, nevracejte odkaz na konstantu, stačí vrátit referenci.
  • Logické operátory by měly v nejhorším případě vrátit int a v lepším případě bool.

Optimalizace návratové hodnoty

Při vytváření nových objektů a jejich vracení z funkce byste měli použít zápis jako ve výše popsaném příkladu binárního operátoru plus.
return Integer(left.value + right.value);
Abych byl upřímný, nevím, jaká situace je relevantní pro C++11, všechny níže uvedené argumenty jsou platné pro C++98.
Na první pohled to vypadá jako syntaxe pro vytvoření dočasného objektu, což znamená, že mezi výše uvedeným a tímto kódem není žádný rozdíl:
Integer temp(left.value + right.value); návratová teplota;
Ale ve skutečnosti se v tomto případě na prvním řádku zavolá konstruktor, pak se zavolá konstruktor kopírování, který zkopíruje objekt, a poté, když se zásobník rozvine, se zavolá destruktor. Při použití prvního záznamu kompilátor nejprve vytvoří v paměti objekt, do kterého je potřeba jej zkopírovat, čímž uloží volání konstruktoru a destruktoru kopírování.

Speciální operátoři

V C++ existují operátory, které mají specifickou syntaxi a metodu přetížení. Například operátor indexu . Je vždy definován jako člen třídy, a protože je zamýšleno chování indexovaného objektu jako pole, měl by vrátit odkaz.
operátor čárky
Mezi "speciální" operátory patří také operátor čárka. Volá se pro objekty, které mají vedle sebe čárku (ale nevolá se v seznamech argumentů funkcí). Vymyslet smysluplný příklad použití tohoto operátoru není tak snadné. Habrauser v komentářích k předchozímu článku o přetěžování .
Operátor dereference ukazatele
Přetížení těchto operátorů může být ospravedlnitelné pro třídy inteligentních ukazatelů. Tento operátor je nutně definován jako funkce třídy a jsou na něj uvalena určitá omezení: musí vracet buď objekt (nebo odkaz), nebo ukazatel, který vám umožní přístup k objektu.
operátor přiřazení
Operátor přiřazení je nutně definován jako funkce třídy, protože je neoddělitelně spojen s objektem nalevo od "=". Globální definování operátoru přiřazení by umožnilo přepsat standardní chování operátoru "=". Příklad:
class Integer ( private: int value; public: Integer(int i): value(i) () Integer& operator=(const Integer& right) ( // kontrola samopřiřazení if (this == &right) ( return *this; ) value = right.value; return *this; ) );

Jak vidíte, na začátku funkce je provedena kontrola samopřiřazení. Obecně je v tomto případě samopřidělování neškodné, ale ne vždy je situace tak jednoduchá. Pokud je objekt například velký, můžete strávit spoustu času zbytečným kopírováním nebo při práci s ukazateli.

Nepřetěžující operátory
Některé operátory v C++ nejsou vůbec přetížené. Zjevně se tak děje z bezpečnostních důvodů.
  • Operátor výběru členů třídy ".".
  • Ukazatel na operátor dereference člena třídy ".*"
  • V C++ (jako ve Fortranu) není žádný operátor umocňování "**".
  • Je zakázáno definovat své operátory (mohou být problémy s prioritizací).
  • Prioritu operátora nelze změnit
Jak jsme již zjistili, existují dva způsoby operátorů - ve formě funkce třídy a ve formě přátelské globální funkce.
Rob Murray ve své knize C++ Strategies and Tactics identifikoval následující pokyny pro výběr formuláře operátora:

proč tomu tak je? Za prvé, někteří operátoři jsou zpočátku omezeni. Obecně platí, že pokud sémanticky není žádný rozdíl v tom, jak definovat operátor, pak je lepší jej uspořádat jako funkci třídy pro zdůraznění spojení a navíc funkce bude inline (inline). Kromě toho může být někdy nutné reprezentovat levý operand objektem jiné třídy. Asi nejvýraznějším příkladem je redefinice<< и >> pro I/O streamy.

Mnoho programovacích jazyků používá operátory: alespoň přiřazení (= , := nebo podobné) a aritmetické operátory(+, -, * a /). Ve většině staticky typovaných jazyků jsou tyto operátory vázány na typy. Například v Javě je sčítání pomocí operátoru + možné pouze pro celá čísla, čísla s plovoucí desetinnou čárkou a řetězce. Pokud definujeme vlastní třídy pro matematické objekty, jako jsou matice, můžeme implementovat metodu pro jejich sčítání, ale lze ji volat pouze takto: a = b.add(c) .

V C++ takové omezení neexistuje – přetížit můžeme téměř jakýkoli známý operátor. Možnosti jsou nekonečné: můžete si vybrat libovolnou kombinaci typů operandů, jediným omezením je, že musí být přítomen alespoň jeden uživatelsky definovaný typ operandu. To znamená, definovat nový operátor na vestavěných typech nebo přepsat existující je to zakázáno.

Kdy přetížit operátory?

Pamatujte na hlavní věc: přetěžujte operátory tehdy a jen tehdy, když to dává smysl. Tedy pokud je smysl přetížení zřejmý a nenese skrytá překvapení. Přetížení operátoři by se měli chovat stejně jako jejich základní verze. Výjimky jsou samozřejmě přípustné, ale pouze v případech, kdy jsou doprovázeny srozumitelným vysvětlením. dobrý příklad jsou operátoři<< и >> standardní knihovny iostream , které se zjevně chovají jinak než normálně .

Zde jsou dobré a špatné příklady přetěžování operátorů. Výše uvedené přidání matice je ilustrativní případ. Zde je přetížení operátoru přidávání intuitivní a pokud je správně implementováno, je samovysvětlující:

Matice a, b; Matice c = a + b;

Příkladem špatného přetížení operátora přidávání by bylo přidání dvou objektů hráče ve hře. Co tím tvůrce třídy myslel? Jaký bude výsledek? Nevíme, co operace dělá, a proto je nebezpečné používat tento operátor.

Jak přetížit operátory?

Přetížení operátorů je podobné přetížení funkcí speciálními názvy. Ve skutečnosti, když kompilátor vidí výraz, který obsahuje operátor a uživatelsky definovaný typ, nahradí tento výraz voláním příslušné funkce přetíženého operátoru. Většina jejich jmen začíná na klíčové slovo operátor , za nímž následuje symbol odpovídajícího operátoru. Pokud se označení neskládá ze speciálních znaků, například v případě operátoru přetypování nebo správy paměti (new , delete , atd.), musí být slovo operátor a označení operátora odděleno mezerou (operátor nový), jinak může být mezera ignorována (operátor+ ).

Většina operátorů může být přetížena jak metodami tříd, tak i jednoduché funkce, ale existuje několik výjimek. Když je přetíženým operátorem metoda třídy, typ prvního operandu musí být tato třída (vždy *this) a druhý musí být deklarován v seznamu parametrů. Příkazy metody také nejsou statické, s výjimkou příkazů správy paměti.

Při přetížení operátoru v metodě třídy získá přístup k soukromým polím třídy, ale skrytý převod prvního argumentu není dostupný. Binární funkce jsou proto obvykle přetěžovány jako volné funkce. Příklad:

Class Rational ( public: //Konstruktor lze použít pro implicitní převod z int: Rational(int čitatel, int jmenovatel = 1); Racionální operátor+(Rational const& rhs) const;); int main() ( Racionální a, b, c; int i; a = b + c; //ok, není nutná konverze a = b + i; //ok, implicitní konverze druhého argumentu a = i + c; //CHYBA: první argument nelze implicitně převést)

Když jsou unární operátory přetíženy jako volné funkce, je jim k dispozici skrytá konverze argumentů, která se však obvykle nepoužívá. Na druhou stranu je tato vlastnost nezbytná pro binární operátory. Takže hlavní rada by byla:

Implementujte unární operátory a binární operátory jako „ X=” jako metody třídy a další binární operátory jako volné funkce.

Kteří operátoři mohou být přetíženi?

Můžeme přetížit téměř jakýkoli operátor C++, s výhradou následujících výjimek a omezení:

  • Nemůžete definovat nový operátor, například operátor** .
  • Následující operátory nelze přetížit:
    1. ?: (ternární operátor);
    2. :: (přístup k vnořeným názvům);
    3. . (přístup k polím);
    4. .* (přístup k poli pomocí ukazatele);
    5. Operátory sizeof , typeid a cast.
  • Následující operátory lze přetížit pouze jako metody:
    1. = (zadání);
    2. -> (přístup k polím pomocí ukazatele);
    3. () (volání funkce);
    4. (přístup pomocí indexu);
    5. ->* (přístup ukazatele k poli ukazatelem);
    6. operátory konverze a správy paměti.
  • Počet operandů, pořadí provádění a asociativita operátorů je určena standardní verzí.
  • Alespoň jeden operand musí být uživatelsky definovaný typ. Typedef se nepočítá.

V příštím díle se seznámíte s C++ přetíženými operátory, ve skupinách i jednotlivě. Každý úsek je charakterizován sémantikou, tzn. očekávané chování. Kromě toho budou ukázány typické způsoby deklarování a implementace operátorů.

Poslední aktualizace: 20.10.2017

Přetížení operátora umožňuje definovat akce, které operátor provede. Přetížení znamená vytvoření funkce, jejíž název obsahuje slovo operátor a symbol přetíženého operátoru. Operátorová funkce může být definována jako člen třídy nebo mimo třídu.

Přetížit můžete pouze operátory, které jsou již definovány v C++. Nemůžete vytvářet nové operátory.

Pokud je operátorská funkce definována jako samostatná funkce a není členem třídy, pak je počet parametrů takové funkce stejný jako počet operandů operátoru. Například funkce, která představuje unární operátor, bude mít jeden parametr, zatímco funkce, která představuje binární operátor, bude mít dva parametry. Pokud operátor vezme dva operandy, pak je první operand předán prvnímu parametru funkce a druhý operand je předán druhému parametru. V tomto případě musí alespoň jeden z parametrů reprezentovat typ třídy

Zvažte příklad s třídou Counter, která představuje stopky a ukládá počet sekund:

#zahrnout << seconds << " seconds" << std::endl; } int seconds; }; Counter operator + (Counter c1, Counter c2) { return Counter(c1.seconds + c2.seconds); } int main() { Counter c1(20); Counter c2(10); Counter c3 = c1 + c2; c3.display(); // 30 seconds return 0; }

Zde funkce operátora není součástí třídy Counter a je definována mimo ni. Tato funkce přetěžuje operátor sčítání pro typ čítače. Je binární, takže vyžaduje dva parametry. V tomto případě přidáváme dva objekty Counter. Funkce také vrátí objekt Counter, který ukládá celkový počet sekund. To znamená, že operace sčítání je zde redukována na sčítání sekund obou objektů:

Operátor čítače + (počítadlo c1, čítač c2) ( return Counter(c1.seconds + c2.seconds); )

V tomto případě není nutné vracet objekt třídy. Může to být i objekt vestavěného primitivního typu. A můžeme také definovat další přetížené funkce operátora:

Int operátor + (Counter c1, int s) ( return c1.seconds + s; )

Tato verze přidá objekt Counter k číslu a také vrátí číslo. Proto levý operand operace musí být typu Counter a pravý operand typu int. A například tuto verzi operátoru můžeme použít následovně:

Čítač cl(20); int sekund = c1 + 25; // 45 std::out<< seconds << std::endl;

Operátorové funkce lze také definovat jako členy tříd. Pokud je funkce operátora definována jako člen třídy, pak je levý operand přístupný přes tento ukazatel a představuje aktuální objekt a pravý operand je předán jako jediný parametr takové funkci:

#zahrnout class Counter ( public: Counter(int sec) (seconds = sec; ) void display() ( std::cout<< seconds << " seconds" << std::endl; } Counter operator + (Counter c2) { return Counter(this->sekundy + c2.sekundy); ) operátor int + (int s) ( return this->seconds + s; ) int seconds; ); int main() ( Counter c1(20); Counter c2(10); Counter c3 = c1 + c2; c3.display(); // 30 sekund int seconds = c1 + 25; // 45 return 0; )

V tomto případě přistupujeme k levému operandu v operátorských funkcích přes tento ukazatel.

Jaké operátory kde předefinovat? Operátory pro přiřazení, indexování (), volání (()), přístup ke členu třídy pomocí ukazatele (->) by měly být definovány jako funkce členů třídy. Operátory, které mění stav objektu nebo přímo souvisejí s objektem (inkrementace, dekrementace atd.), jsou obvykle také definovány jako členské funkce třídy. Všechny ostatní operátory jsou častěji definovány jako samostatné funkce než jako členové třídy.

Porovnávací operátory

Řada operátorů je přetížena ve dvojicích. Pokud například definujeme operátor ==, musíme definovat také operátor !=. A při definování operátora< надо также определять функцию для оператора >. Přetěžme například tyto operátory:

bool operátor == (počítadlo c1, čítač c2) ( return c1.seconds == c2.seconds; ) bool operátor != (counter c1, counter c2) ( return c1.seconds != c2.seconds; ) bool operátor > ( Čítač c1, Čítač c2) ( návrat c1.seconds > c2.seconds; ) boolův operátor< (Counter c1, Counter c2) { return c1.seconds < c2.seconds; } int main() { Counter c1(20); Counter c2(10); bool b1 = c1 == c2; // false bool b2 = c1 >c2; // true std::cout<< b1 << std::endl; std::cout << b2 << std::endl; return 0; }

Operátoři přiřazení

#zahrnout class Counter ( public: Counter(int sec) (seconds = sec; ) void display() ( std::cout<< seconds << " seconds" << std::endl; } Counter& operator += (Counter c2) { seconds += c2.seconds; return *this; } int seconds; }; int main() { Counter c1(20); Counter c2(10); c1 += c2; c1.display(); // 30 seconds return 0; }

Operace zvýšení a snížení

Předefinování operátorů inkrementace a dekrementace může být obzvláště složité, protože pro tyto operátory potřebujeme definovat předpony i postfixy. Pojďme definovat podobné operátory pro typ Counter:

#zahrnout class Counter ( public: Counter(int sec) (seconds = sec; ) void display() ( std::cout<< seconds << " seconds" << std::endl; } // префиксные операторы Counter& operator++ () { seconds += 5; return *this; } Counter& operator-- () { seconds -= 5; return *this; } // постфиксные операторы Counter operator++ (int) { Counter prev = *this; ++*this; return prev; } Counter operator-- (int) { Counter prev = *this; --*this; return prev; } int seconds; }; int main() { Counter c1(20); Counter c2 = c1++; c2.display(); // 20 seconds c1.display(); // 25 seconds --c1; c1.display(); // 20 seconds return 0; }

Counter& operator++ () ( sekund += 5; return *this; )

V samotné funkci můžete definovat určitou logiku zvýšením hodnoty. V tomto případě se počet sekund zvýší o 5.

Postfixové operátory musí vrátit hodnotu objektu před inkrementací, tedy předchozí stav objektu. Pro odlišení formy postfixu od formuláře prefixu obdrží verze postfixu další parametr typu int, který se nepoužívá. I když v zásadě to můžeme použít.

Operátor počítadla++ (int) (Předchozí počítadlo = *toto; ++*toto; vrátit předchozí; )