8. diel - Konštantný metódy v C ++
V minulej lekcii, Aréna s bojovníkmi v C ++ , sme dokončili našu objektovú arénu. V dnešnom tutoriále zistíme, čo sú to konštantné metódy a prečo sa nimi zaoberať.
Konštantný metódy
Ako už názov napovedá, konštantný metóda je taká metóda, ktorá
nemení dáta inštancie. Sú to všetky Getter - iba získavajú dáta, nič
nemení. Z toho dôvodu by správne mali byť všetky Getter označené ako
konštantná. Metóda Bojovnik.nazivu()
je tiež svojím spôsobom
getter, pretože iba zisťuje či je dostatočný počet životov. Všetky
metódy, ktoré nemenia dáta, by sme mali označiť ako konštantná - to
urobíme jednoducho pridaním kľúčového slova const
za názov
metódy (do .hi .cpp súboru). Napríklad pre triedu Bojovnik
:
Bojovnik.h
#ifndef __BOJOVNIK_H_ #define __BOJOVNIK_H_ #include <string> #include "Kostka.h" using namespace std; class Bojovnik { private: float zivot; float max_zivot; float utok; float obrana; Kostka &kostka; public: Bojovnik(float zivot, float utok, float obrana, Kostka &kostka); bool nazivu() const; float utoc(Bojovnik &druhy) const; float getZivot() const; float getMaxZivot() const; float getUtok() const; float getObrana() const; }; #endif
Bojovnik.cpp
#include "Bojovnik.h" Bojovnik::Bojovnik(float zivot, float utok, float obrana, Kostka &kostka) : kostka(kostka), zivot(zivot), max_zivot(zivot), utok(utok), obrana(obrana) {} bool Bojovnik::nazivu() const { return this->zivot > 0; } float Bojovnik::utoc(Bojovnik & druhy) const { float obrana_druhy = druhy.obrana + druhy.kostka.hod(); float utok_prvni = this->utok + this->kostka.hod(); float zraneni = utok_prvni - obrana_druhy; if (zraneni < 0) zraneni = 0; druhy.zivot -= zraneni; return zraneni; } float Bojovnik::getZivot() const { return this->zivot; } float Bojovnik::getMaxZivot() const { return this->max_zivot; } float Bojovnik::getUtok() const { return this->utok; } float Bojovnik::getObrana() const { return this->obrana; }
Všimnite si, že aj metóda utoc()
je konštantná - nemení
dáta inštancie, ale mení dáta parametra.
Pravidlá
Prečo sa tým zaoberáme? Kľúčové slovo const
nám
postráži, že je metóda správne implementovaná. Ak by sme pre triedu
Kocka nadefinovali metódu setPocetSten()
a nastavili ju
ako konštantná, kompilátor by nám zahlásil nasledujúce hlášku (pre
Visual Studio):
error C2228: left of '.pocet_sten' must have class/struct/union note: type is 'const Kostka *const ' note: did you intend to use '->' instead?
Kompilátor si sám postráži, že funkcia nemôže nič zmeniť a ostatné programátorov tým informujeme, že dáta sú v bezpečí (nemôžu sa zmeniť).
Aké ďalšie pravidlá platia? Z konštantný metódy môžeme volať iba
konštantný metódy. To znamená, že vo chvíli, keď nastavíme getter ako
konštantná, nemôžeme z neho zavolať setter (inak by kľúčové slovo
const
nedávalo zmysel - modifikovala by sa dáta).
Existuje ešte tretí a najdôležitejšie pravidlo: na konštantnej objekty možno volať iba konštantný metódy. Napríklad pre nášho bojovníka. Predpokladáme, že nasledujúci kód by mal fungovať:
const Bojovnik bojovnik(100,8,5,kostka); float utok = bojovnik.getUtok(); float obrana = bojovnik.getObrana(); float uroven_agresivity = utok - obrana;
Prečo by sme to očakávali? Hoci je bojovník konštantná, chceme získať útok a obranu iba pre čítanie - to by nemal byť problém, pretože metódy nemení dáta a konštanta je dodržaná. To ale viete vy, ale zatiaľ to nevie kompiler. Aby tento kód fungovať, musíte nastaviť Getter ako konštantná - kompiler má potom istotu, že metóda nič nezmení a môže byť teda volaná nad konštantným objektom.
Ukazovatele
Pre ukazovatele a referencie sa situácia ešte trochu skomplikuje. Pridaním
kľúčového slova const
za názov metódy sa stane, že sú (pre
predstavu) všetky atribúty označené ako konštantná. Pre ukážku si
predstavme nasledujúce triedu:
class Uzivatel { int vek; char* jmeno; void vypisJmeno() const; };
Vnútri metódy vypisJmeno()
bude vďaka const
ukazovateľ this
typu Uzivatel const * const
(na
rozdiel od klasického Uzivatel * const
). Len pre upresnenie,
ukazovatele vždy čítame odzadu, teda Uzivatel const * const
je
"konštantný ukazovateľ na konštantného užívateľa", zatiaľ čo
Uzivatel * const
je "konštantný ukazovateľ na používateľa".
Tiež máme dve možnosti zápisu, teda nasledujúce dve ukážky sú
ekvivalentné: Uzivatel const *
a
const Uzivatel *
.
Konštantná metódu si možno teda predstaviť tak, že všetky atribúty budú konštantný:
class Uzivatel { const int vek; char * const jmeno; };
Všimnite si typu atribútu jmeno
. Jedná sa o konštantný
ukazovateľ (nemôžeme zmeniť adresu, kam ukazuje), ale nie je to ukazovateľ
na konštantnú hodnotu - meno môžeme stále zmeniť. Konštantná metódy
nám nezaručí, že sa nezmení dáta inštancie - zaručí nám len to, že sa
nezmení atribúty.
Na problémy dôjde aj pri práci s referenciami. Predstavme si, že chceme
vrátiť vek používateľa referencií. Nie je to obvyklé, ale z nejakého
dôvodu to tak chceme. Referenciu na int
použiť nemôžeme,
pretože typ atribútu je const int
a typy sa musí zhodovať. Z
toho vyplýva, že musíme použiť konštantný referenciu:
class Uzivatel { int vek; char* jmeno; void vypisJmeno() const; const int& getVek() const; };
Teraz by naše časť kódu fungovala, a keď sa nad tým zamyslíme, potom až teraz funguje správne - rešpektuje konštantné hodnoty tam, kde to dáva zmysel.
To by bolo pre dnešné kratšie lekciu všetko. V zdrojovom boli pridané konštanty ku getterům a k pár ďalším metódam (u ktorých to dávalo zmysel). Nabudúce budeme s kódom pokračovať a preto by som odporučil stiahnuť si zdrojové kódy dole pod článkom. Budete mať istotu, že budeme pracovať s rovnakým zdrojovým kódom. Nabudúce, v lekcii Riešené úlohy k 6. až 8. lekciu OOP v C ++ , nás čaká statika.
V nasledujúcom cvičení, Riešené úlohy k 6. až 8. lekciu OOP v C ++, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 75x (9.78 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C++