5. Výrazy
  1. Výrazy provádějí v programu práci. Mimo jiné, výrazy jsou používány k výpočtu a přiřazování hodnot proměnným a pomáhají řídit provádění programu. Výrazy mají dvě úlohy: provedení výpočtů určených prvky výrazu a vracejí nějakou hodnotu, která je výsledkem výpočtu. Můžeme použít tuto definici: Výraz je řada proměnných, operátorů a volání funkcí, která vypočítá jednu hodnotu.

  2. Jak již bylo uvedeno v předchozí kapitole, operátory vrací hodnotu. Operátory používáme ve výrazech. Např. následující příkaz je výraz (předpokládejme, že pocet je typu int):
    pocet++;
    Tento výraz má hodnotu pocet před provedením operace.
    Datový typ vrácené hodnoty závisí na prvcích použitých ve výrazu. Předchozí výraz vrací typ int, protože ++ vrací hodnotu stejného datového typu jako je jeho operand a pocet je typu int. Jiné výrazy mohou vracet reálná čísla, řetězce apod.
    V jednom z našich předchozích programů byl použit výraz:
    (c = getchar()) != '\n'
    Tento výraz je zajímavý, neboť se skládá ze tří výrazů. Prvním výrazem je volání funkce getchar. Volání funkce vrací hodnotu přečteného znaku a tato hodnota je dalším výrazem přiřazena do proměnné c. Hodnotou tohoto výrazu je přiřazovaná hodnota (tj. přečtený znak) a tato hodnota je porovnána v posledním výrazu se znakem odřádkování. Není-li hodnota přečteného znaku znak odřádkování, pak tento výraz je pravdivý. Jak vidíme můžeme vytvářet složené výrazy z různých menších výrazů a to tak, aby datové typy části výrazu byly ve shodě. V předchozím příkladě také vidíme postup při vyhodnocování výrazu.
    Předpokládejme následující složený výraz
    x * y * z
    V tomto případě pořadí, ve kterém je výraz vyhodnocován, není podstatné neboť výsledek násobení nezáleží na pořadí násobených hodnot. Toto, ale neplatí ve všech výrazech. Např. následující výraz dává různý výsledek v závislosti na tom, zda je dříve provedena operace sčítání nebo operace dělení.
    x + y / 100
    Prioritu operací můžeme změnit použitím závorek. Např. můžeme zapsat (x + y) / 100. Jestliže závorky nepoužijeme, pak pořadí provádění operací je určeno prioritou jednotlivých operátorů. Operátory s vyšší prioritou jsou prováděny dříve. Dělení má vyšší prioritu než sčítání a náš složený výraz je ekvivalentní s výrazem
    x + (y / 100)
    V následující tabulce je uvedena priorita jednotlivých operátorů a to od nejvyšší k nejnižší prioritě. Operátory na stejném řádku mají stejnou prioritu.
    Operátory Pořadí vyhodnocování
    () [] -> >> . zleva doprava
    ! ~ + - ++ -- & *(změna typu) - unární operace  zprava doleva
    sizeof new delete typeid zprava doleva
    .* ->* zleva doprava
    * / %  zleva doprava
    + - zleva doprava
    << >> zleva doprava
    < <= > >= zleva doprava
    == != zleva doprava
    & zleva doprava
    ^ zleva doprava
    | zleva doprava
    && zleva doprava
    || zleva doprava
    ?: zprava doleva
    = *= /= %= += -= |= &= ^= <<= >>= zprava doleva
    , zleva doprava
    Když v jednom výrazu jsou operátory se stejnou prioritou, pak nějaké pravidlo musí rozhodnout, který z nich bude použit první. Všechny binární operátory mimo operátoru přiřazení jsou prováděny odleva doprava. Operátory přiřazení jsou prováděny zprava doleva.
  3. V předchozí kapitole jsme se zabývali vytvářením konzolové aplikace převádějící sekundy na minuty a sekundy. Nyní totéž vyřešíme jako aplikaci GUI (a zopakujeme si, co jsme používali v první kapitole). Na formulář umístíme editační komponentu (vyprázdníme její obsah), nad ní umístíme komponentu Label s textem ?Zadej počet sekund:, vedle editační komponenty přidáme tlačítko ?,Vypočti a pod editační komponentu vložíme další ? Label, ve které budeme zobrazovat výsledek (tuto komponentu vyprázdníme). Základní rozdíl mezi touto a konzolovou aplikací je ten, že zde zadáváme informace v editační komponentě (zadaná hodnota je brána jako řetězec znaků). Obdobně to lze říci i o výstupu (např. při zápisu do komponenty Label). Musíme se tedy zabývat převodem řetězec - číslo a také opačným převodem. Pro převod řetězce znaků na celé číslo používáme metodu ToInt a pro opačný převod konstruktor AnsiString (vlastnosti Text a Caption jsou typu AnsiString). Obsluhu stisku našeho tlačítka bude tvořit příkaz (operátory + zde spojují textové řetězce v jeden řetězec, tj. je vytvořen jeden řetězec tvaru: Výsledek: XX:XX):

  4.  Label2->Caption = "Výsledek: " + AnsiString(Edit1->Text.ToInt() / 60)
                                      + ":" + AnsiString(Edit1->Text.ToInt() % 60);
    V našem programu není ošetřeno případné zadání nečíselné hodnoty (je pouze generována standardní výjimka popisující chybu). Program vyzkoušejte, pokuste se také zadat nečíselnou hodnotu a seznamte se se standardním způsobem signalizace chyb.
  5. Pokud nepočítáme konsolové aplikace, pak  jsme v našich programech zatím nepotřebovali žádné proměnné (např. pro uložení mezivýsledků). V předchozím příkladě dvakrát převádíme text zapsaný v editačním ovladači na číslo. Toto nyní změníme, převod provedeme pouze jednou a převedenou hodnotu uložíme do proměnné. Do proměnných můžeme také umístit výsledky. Deklarujeme proměnné Sekundy a Minuty, které budou typu int. Obsluha stisku tlačítka bude nyní tvořena příkazy:

  6. int Sekundy, Minuty;
    Sekundy = Edit1->Text.ToInt();
    Minuty = Sekundy / 60;
    Sekundy %= 60;
    Label2->Caption = "Výsledek: " + AnsiString(Minuty)+ ":" + AnsiString(Sekundy);
    Vidíme, že příkazy provádějící výpočty jsou stejné jako v konzolové aplikaci, příkazy vstupů a výstupů se liší. Vyzkoušejte provést tyto změny.
  7. Upravte předchozí program tak, aby se počet sekund rozložil na počet hodin, minut a sekund (obdoba další konsolové aplikace).
  8. Vytvořte program, který bude provádět výpočet obvodu a obsahu kruhu o zadaném poloměru (každý výsledek uložte do jiné komponenty Label). Pro uložení reálných čísel používáme datový typ double. Pro převod řetězce na typ double používáme metodu ToDouble a pro opačný převod opět konstruktor AnsiString.
  9. Když se podíváme na některou obsluhu události (např. obsluhu události stisku tlačítka), pak zjistíme, že jméno obsluhy je tvořeno jménem formuláře, dvěmi dvojtečkami a jménem tvořeným z názvu komponenty a názvu události (např. Form1::Button1Click). Zatím jsme používali převážně obsluhy stisknutí tlačítka. Události je ale mnohem více. Jestliže chceme vytvořit obsluhu pro nějakou událost (stisknutí tlačítka je implicitní událostí tlačítka a obsluhu implicitní události vytvoříme dvojitým kliknutím na komponentě) provedeme to dvojitým kliknutím na události v Inspektoru objektů. Začneme vytvářet novou aplikaci, kde do středu formuláře vložíme tlačítko a vytvoříme obsluhu události OnResize formuláře (změna velikosti formuláře) tak, aby při změně rozměrů formuláře myší, bylo tlačítko vždy uprostřed. Rozměry vnitřní oblasti formuláře určují vlastnosti ClientWidth a ClientHeight. Vytvořte tuto aplikaci sami.
5. Výrazy