Válí se ti projekty v šuplíku? Dostaň je mezi lidi a získej cool tričko a body na profi IT kurzy v soutěži ITnetwork summer 2017!
Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)

10. díl - Přetypování a operátory

C a C++ C++ Pokročilé konstrukce v C++ Přetypování a operátory

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Z matematiky víme, že násobení a dělení má přednost před sčítáním a odčítáním. To je zcela běžné a očekávali bychom to i od programovacího jazyka. Ačkoliv se tento předpoklad zdá zcela běžný, nemusí nutně platit. Vše závisí na definici jazyka a na tom, jak je jazyk navrhnut. V C++ navíc máme vedle základních aritmetických operací další operace - logické, binární atd. Schválně jestli uhádnete, zda má přednost sčítání nebo modulo? A jak je na tom modulo s násobením? A budou se operace vyhodnocovat zprava nebo zleva?

Priority operátorů

Jazyk definuje tzv priority operátorů. Operátor s vyšší prioritou se vyhodnotí před operací s prioritou nižší. Nikoho asi nepřekvapí, že operace násobení má vyšší prioritu než operace sčítání. V následující tabulce jsou shrnuty všechny operace a jejich priorita (nižší číslo udává vyšší prioritu). Některé operátory ještě nemusíte znát, to nevadí, pbudou probrány až v lekci OOP.

Přednost Operátor Popis Směr vyhodnocení
1 :: rozlišení kontextu zleva
2 ++ -- postfixové operátory inkrementace a dekrementace
() operátor volání funkce
[] operátor přístupu k prvku pole
. výběr členu přes referenci
-> výběr členu přes ukazatel
3 ++ -- prefixové operátory inkrementace a dekrementace zprava
+ unární plus a mínus
! ~ logická a bitová negace
(type) operátor přetypování
operátor dereference
& získání adresy prvku
sizeof velikost prvku
new, new[] dynamická alokace paměti
delete, delete[] dynamicka dealokace paměti
4 . -> ukazatel na člen zleva
5 / % operátory násobení, dělení a zbytek po dělení
6 + operátory součtu a rozdílu
7 << >> bitový posun doleva a doprava
8 < <= Relační operátory < a ≤
> >= Relační operátory > a ≥
9 == != Relační operátory = a ≠
10 & bitové AND
11 ^ bitové XOR (výlučný součet)
12 | bitové OR
13 && logické AND
14 || logické OR
15 ?: ternární operátor[1] zprava
= přímé přiřazení
+= −= přiřazení přičtením a odečtením
*= /= %= Přiřazení násobením, podílem a zbytkem
<<= >>= přiřazení bitovým posunem doleva a doprava
&= ^= |= přiřazení bitovou operací AND, XOR a OR
16 throw operátor throw (pro výjimky)
17 , operátor čárka zleva

Z tabulky by mělo být zřejmé, jak se operace vyhodnocují. Samozřejmě nikdo nebude chtít (snad jen na nějakých pohovorech), abyste si celou tabulku pamatovali. Je ale důležité vědět, že taková tabulka existuje (tzv. priorita operátorů) a že určuje způsob, jakým se v C++ vyhodnocuje. Jiné jazyky mohou mít tabulku jinou nebo mít nějakou modifikaci. Je dobré si před přechodem na jiný jazyk zjistit, jak se operátory vyhodnocují.

Chybí zde jeden důležitý operátor - závorky. Uzávorkování má nejvyšší prioritu a je vždy vyhodnoceno před zbylými operacemi. Doporučuji nespoléhat na prioritu operátorů a raději dávat do vyhodnocení závorky. Nejenže budete mít kontrolu nad vyhodnocováním operátorů, program se bude i mnohem lépe číst - hlavně pro lidi, kteří přijdou po vás.

Přetypování

C++ zavádí pro přetypování velkou spoustu pravidel (ještě více než u operátor). Pokud by vás zajímalo více, můžete si informace dohledat v dokumentaci (v angličtině). Zde vypíchnu jen několik důležitých konstrukcí, které C používá.

V základu existují dva typy přetypování - explicitní a implicitní. Implicitní přetypování je takové, které probíhá automaticky. Jedná se o konverze z typu o menším rozsahu hodnot do typu o větším rozsahu hodnot. Graficky si můžeme implicitní konverze zobrazit jako jednosměrný řetěz, který udává, které konverze jsou možné.

char
unsigned char
short
unsigned short
int <=> enum
unsigned int
long
unsigned long
long long
unsigned long long
float
double
long double

Typ, který je nahoře, se implicitně přetypuje na libovolný typ pod ním, je-li to potřeba.

Obráceným směrem probíhá tzv explicitní konverze. Kompilátoru musíme dodat informaci, že typ chceme skutečně přetypovat na typ menší. Máme-li ve větším typu příliš velké číslo, menší typ ho nemusí celé uložit. Ztratíme tím část informace - například při přetypování čísla z float do int se ztratí část čísla za desetinnou čárkou. Kompilátor chce mít jistotu, že jsme skutečně operaci požadovali a nejedná se o chybu. Přetypování napíšeme tak, že před výraz, který chceme přetypovat, napíšeme do závorky požadovaný typ. Pro příklad si napíšeme program pro výpočet průměru.

#include <iostream>
using namespace std;

int main( int argc, char** argv )
{
        unsigned int suma = 0;
        unsigned int pocet = 0;

        cout << "Zadejte cisla (zaporne cislo pro ukonceni): ";
        while( true )
        {
                int precteno;
                cin >> precteno;
                if( (bool)cin==false || precteno < 0 )
                        break;
                suma += precteno;
                pocet++;
        }

        double prumer = (double)suma / (double)pocet;
        cout << "Prumer je: " << prumer << endl;

        cin.get();
        return 0;
}

Nejdříve přečteme všechny čísla. Protože průměr není celé číslo, musíme před samotným dělením čísla převést na typ double - v C++ vrací dělení dvou celých čísel vždy číslo celé. V tomto případě by stačilo přetypovat pouze jedno číslo (podle pravidel C++), ale je vždy lepší explicitně říci, že se mají převést čísla obě - program se lépe čte. Také je v programu použito implicitní přetypování, při přičítání přečteného čísla (které je int) k sumě (která je unsigned int).

Kam dále

Gratuluji, právě jste dokončili pokročilé konstrukce jazyka C++. Nyní jste již připravení na to, abyste se začali zabývat objektově orientovaným programováním. Před samotným OOP ale doporučuji přečíst tři články: Kompilace v jazyce C a C++, dále Kompilace v jazyce C a C++ podruhé a nakonec článek Knihovny v jazyce C a C++. Řeknou vám, jak to všechno vlastně pod kapotou funguje. Nyní již hurá na OOP.


 

 

Článek pro vás napsal patrik.valkovic
Avatar
Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu.
Miniatura
Předchozí článek
Výčtové typy
Miniatura
Všechny články v sekci
Pokročilé konstrukce C++
Miniatura
Následující článek
Ukazatele v C++
Aktivity (4)

 

 

Komentáře

Avatar
Cement
Člen
Avatar
Cement:8. dubna 21:20

Co konkrétně dělá v podmínce "(bool)cin"? Když je zadán prázdný řetězec, tak cin má hodnotu false a vyskočí z cyklu while?

Musí být "int precteno" v cyklu while nebo stačí proměnnou definovat před cyklem?

Předpokládám, že má být správně "suma += precteno;".

Odpovědět 8. dubna 21:20
Když selžou všechny pokusy, použijte návod.
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Cement
patrik.valkovic:8. dubna 21:47

Ano, má být "suma += precteno;", opraveno.
"(bool)cin" zjistí, že čtení proběhlo úspěšně. Například když na vstup příjde "l", tak cin pozná, že to není číslo a při následném přetypování vrátí false.
promměná "precteno" může být umístěna i před cyklem. Takhle to vypadá, že se proměnná inicializuje při každé průchodu cyklu, ale kompilátor kód optimalizuje a vystrčí ji stejně ven.

Odpovědět 8. dubna 21:47
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Cement
Člen
Avatar
Cement:9. dubna 11:41

V podmínce je to "(bool)cin" zbytečné, protože nebude mít nikdy hodnotu menší než nula. Možná by tam mělo být "(bool)cin = 0".

Odpovědět 9. dubna 11:41
Když selžou všechny pokusy, použijte návod.
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Cement
patrik.valkovic:9. dubna 12:28

Co je to za hloupost? Tady nejde o hodnotu, ale o logické true nebo false. Pokud se cinu nepodaří přečíst znak, poté při přetypování na bool vrací false a cyklus se ukončí. Stejně tak, pokud se zadá záporné číslo, tak se cyklus ukončí. Schválně zkus program zkompilovat a dát tam čísel ap oté třeba "k".

Odpovědět 9. dubna 12:28
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Taskkill
Šéfredaktor
Avatar
Odpovídá na patrik.valkovic
Taskkill:9. dubna 12:39

Nema cin pretypovani na bool explicitni?

 
Odpovědět 9. dubna 12:39
Avatar
Cement
Člen
Avatar
Cement:9. dubna 13:17

No právě, když si program zkopíruji do CodeBlocks, tak ať napíšu cokoli, tak se hned ukončí. Když opravím "(bool)cin = =0" (nula nebo false) tak to dělá asi to, co to má dělat.

Před opravou to hází chybu:
Zadejte cisla (zaporne cislo pro ukonceni): 33
Prumer je: -nan

Oprava: if( (bool)cin == 0 || precteno < 0 )

Po opravě to pracuje asi správně:
Zadejte cisla (zaporne cislo pro ukonceni): 55
55
55
g
Prumer je: 55

Odpovědět 9. dubna 13:17
Když selžou všechny pokusy, použijte návod.
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovědět 9. dubna 14:32
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Cement
patrik.valkovic:9. dubna 14:34

Jo máš pravdu, pokud přečte číslo, tak se vyhodnotí na true a tím se program ukončí. Má tam být "!(bool)cin", popřípadě jiná variace. V článku je to opraveno.

Odpovědět 9. dubna 14:34
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 8 zpráv z 8.