Obsah textu
Objekty v jazyce C++ pro začátečníky - autor Pavel Drbal
Základní prvky a obraty
V této kapitole postupně probereme základní vlastnosti objektů, s jednoduchými ilustračními příklady a podrobným vysvětlením.
Atributy

Již jsme říkali, že objekt je skupina proměnných (atributů) a funkcí (metod), která je programem považována za jednotku. Třída je definice proměnných a metod skupiny objektů.

A je tedy třída, tj. nový námi vytvořený typ, pomocí kterého můžeme vytvářet nové složité proměnné zvané objekty.

“x”, “y” jsou objekty třídy A
Atributy jsou proměnné uvnitř třídy.

Proměnné “i” a “f” jsou atributy třídy. Pokud jsou atributy veřejné, používají se pomocí specifikace jménem objektu (tečkovou notací). Jménem objektu, ne jménem třídy!

Říká se, že “A je třída”, rozumí se objektů; říká se, že “x je objekt třídy A” nebo že “x je instance třídy A”.
Uvědomte si, že deklarátor “class” definuje typ (podobně jako “typedef”), že nevymezuje žádnou paměť. Paměť vymezí až deklarace objektu. Jinými slovy, kolik objektů jedné třídy se deklaruje, tolikrát zabírají místo proměnné deklarované v této třídě.
Pro začátek si můžeme představovat, že objekt je skupina proměnných, podobně jako “struct” v jazyce C nebo “record” v Pascalu a jiných programovacích jazycích. Objekt je skupina jako celek, jméno objektu je jménem této skupiny proměnných.
Všechny vlastnosti objektů se určují při definici tříd, změnit objekt (jeho proměnné) lze tak, že se změní třída, ze které vznikl (jejíž instancí je). Tím se ovšem změní všechny objekty této třídy.
Proměnným objektu se říká atributy (někdy také sloty nebo členská data).
Metody

To, že každý objekt má své vlastní metody, které obhospodařují jeho data, to je specialitou objektového přístupu. Mějme tuto deklaraci třídy:

Je zde deklarována funkce “fnkc” s dvěma celočíselnými parametry a celočíselnou hodnotou, dále je deklarována procedura (funkce s void hodnotou), která se jmenuje “prcdr” a je bez parametrů.

Metody třídy jsou definovány níže za třídou – také se tomu říká implementace metod.
Definujeme-li “x” jako objekt třídy A, takto:

pak použití metod je například následující:

Do proměnné “k” je dosazena hodnota funkce “fnkc” objektu “x”. Je provedena procedura “prcdr” objektu “x”.
- Deklarace třídy začíná deklarátorem “class” a končí příslušnou pravou závorkou. Obsahuje deklarace proměnných a zkrácené deklarace metod (tj. bez těla metody).
- Definice metod třídy (implementace třídy) je úplná definice metody, tj. i s tělem. Začíná jménem třídy, dvě dvojtečky, jméno metody, pak následuje výčet parametrů a tělo metody.
- Deklarace objektu je jméno třídy následované jménem objektu - neodlišuje se od jiných deklarací.
Objekt obvykle obsahuje kromě proměnných i procedury a funkce. Společný název pro procedury a funkce je metody objektu nebo členské funkce. Samozřejmě, metody se musí definovat u třídy objektů - každý objekt této třídy (každá instance této třídy) pak vlastní tyto metody.
Formulaci “objekt vlastní metodu” musíme rozumět takto:
Volaná metoda musí být specifikována jménem objektu a používá jeho proměnné.
Použijeme-li definici třídy A z minipříkladu 2, pak pro

platí, že volání metody “x.uloz(1)” uloží číslo 1 do proměnné “alfa” v objektu “x”, hodnota proměnné “alfa” v objektu “y” se tímto příkazem nijak nezmění. Ovšem příkaz “y.uloz(8)” naplní proměnnou “alfa” v objektu “y”, nijak však nezmění objekt “x”.
Pamatujte
Každý objekt vymezuje paměť pro své proměnné, ale ne pro své metody.
Každý objekt má svou vlastní sadu proměnných, ale pro všechny objekty téže třídy je jen jedna sada metod.
Musíme tomu rozumět takto:
Pro návrh programu si představujeme, že každý objekt vlastní svá data a své metody. Jestliže použijeme metodu, tak pracuje jen s atributy svého objektu.
Pro rozpočet paměti programu si uvědomíme, že fakticky je každá metoda uložena v paměti jen jednou. Jakmile napíšeme definici třídy, tak metody zabírají místo v paměti, i když k této třídě neexistuje žádný objekt. I když je deklarováno libovolné množství objektů, paměťový prostor zabíraný metodami je stále stejný.
S atributy to je jinak. V definici třídy atributy nezabírají žádné místo, jsou to jen deklarace v kompilátoru, žádné proměnné ještě neexistují. Atributy zabírají místo v paměti až v deklaracích objektů. Když znásobím počet objektů, znásobí se velikost zabíraného místa paměti.
Jinými slovy: Každá třída má jen jednu sadu metod pro všechny své objekty. Přesto musíme metody specifikovat jménem objektu - to proto, aby metoda věděla, z kterého konkrétního objektu má brát proměnné.
Chceme-li pracovat s objekty, musíme mít
- deklaraci třídy,
- definice metod třídy,
- deklaraci objektů – jednoho nebo více.
Zapouzdření
Některé proměnné a funkce mohou být použity pouze metodami téhož objektu, nejsou přístupné z jiných částí programu.

Mějme tuto definice třídy:

Proměnná “i” je soukromá, tj. je použitelná pouze uvnitř metod této třídy, není použitelná z vnějšku.
Definujme metody takto:

a deklarujme objekt “x”:

Pak následující použití je správné:

avšak rozhodně nelze použít

Zapouzdření (encapsulation) je podstatná vlastnost objektového programování. Svazuje funkce s daty. Pod zapouzdřením rozumíme to, že o proměnných a metodách lze určit, jsou-li veřejně přístupné vně objektu (to jsou ty za “public”), nebo jestli jsou soukromé, tj. lze je použít pouze v metodách téhož objektu (soukromé jsou ty, které jsou uvedené za “private”).
Obvyklé použití je to, že proměnné jsou prohlášené za soukromé a jsou vytvořeny metody, které umožňují tyto proměnné používat (viz do krajnosti zjednodušené v minipříkladě 2).
Důvody jsou následující: metody kontrolují správnost naplňování proměnných. Kdybychom připustili přímé dosazování hodnot do proměnných, bez kontroly, pak omylem nebo chybou špatně naplněné proměnné způsobí těžce identifikovatelnou chybu.
Důležitost zapouzdření je v tom, že umožňuje skrýt atributy a metody objektu před zbytkem programu. Správné zapouzdření vlastně předpisuje, že jediný možný způsob komunikace s objektem je prostřednictvím veřejných metod.
Rozhraní objektu je souhrn všech jeho veřejných metod.
Konstruktor a destruktor
Při vzniku objektu se provede speciální metoda zvaná konstruktor. Při zániku objektu se provede speciální metoda zvaná destruktor.

Konstruktor hlavně slouží k nastavení počátečních hodnot atributů.
Destruktor slouží k uvolnění polí a jiných prvků umístěných v haldě.
Mějme třídu definovanou takto:

(Připomeňme si, že funkce “malloc” vymezí prostor paměti o velikosti, která je zadaná argumentem (její hodnotou je ukazatel na tuto paměť), a že funkce “free” uvolní tu vymezenou paměť, na kterou ukazuje její argument.)
Deklarujme objekt takto:

Objekt “x” při deklaraci alokuje 100 znaků, při rušení objektu se pomocí destruktoru uvolní alokovaná paměť.
Konstruktor je metoda, která má stejné jméno jako třída, destruktor má navíc znak “~” (tilda). Konstruktor slouží k dosazení počátečních hodnot do proměnných objektu. Konstruktor se provádí v okamžiku vzniku objektu, v zásadě ve dvou případech. Ukážeme si to na příkladu:

deklaruje objekt “x” o 50 znacích (bytech).

“Py” je ukazatel na objekt třídy A, tento objekt je vymezen v oblasti přidělované paměti a navíc má 150 bytů (také v oblasti přidělované paměti). (O ukazatelích na objekt následuje níže samostatná kapitola.)
Hlavní úloha konstruktoru objektu je dosadit počáteční hodnoty do proměnných objektu. Protože konstruktor je metoda jako každá jiná (pouze nemůže mít funkční hodnotu, je tedy automaticky “void”), tak můžeme tyto počáteční hodnoty získat i dosti složitým algoritmem.
Následující tvrzení o konstruktorech jsou vysvětlena později v příslušných kapitolách:
- Třída může mít více konstruktorů (kapitola “Polymorfismus konstruktoru”).
- Konstruktory se nedědí (kapitola “Dědění”).
- Konstruktor nemůže být virtuální (kapitola “Brzké a pozdní spojení”).
- Pro objekty použité v poli je nutný konstruktor bez parametrů (kapitola “Pole objektů”).
I když u některé třídy neuvedeme konstruktor, překladač si jej v případě potřeby (při deklaraci) vytvoří - ovšem takový konstruktor nedělá nic speciálního.
Destruktor se provádí těsně před koncem existence objektu, to znamená, že se provede na konci bloku příkazů, v němž je objekt platný, nebo při příkazu

který je opositním příkazem k “new(…)”.
Destruktor uklízí objekt, tj. uvolňuje paměť a ruší vazby, kterých se objekt účastnil. Nic z toho nedělá automaticky, vše musíme naprogramovat.
Jestliže objekt má vyžádanou paměť (pomocí funkce malloc, new nebo podobně), je velmi důležité nezapomenout tuto paměť zase v destruktoru uvolnit. Když objekt skončí svou existenci a vyžádaná paměť není uvolněna, tak tuto paměť později již nikdo nemůže uvolnit. Je-li takových objektů více nebo jsou v cyklu, pak náročnější programy mohou havarovat z nedostatku přidělitelné paměti. Neuvolnění vyžádané paměti je nedostatek dobré výchovy.
Následující tvrzení o destruktorech jsou vysvětlena později v příslušných kapitolách.
- destruktor může být maximálně jeden (kapitola “Polymorfismus”);
- destruktor se dědí (kapitola “Dědění”);
- destruktor může být virtuální, v některých případech musí být virtuální (kapitola “Brzké a pozdní spojení”).
I když u některé třídy neuvedeme destruktor, překladač si jej v případě potřeby (při ukončení objektu) vytvoří - ovšem takový destruktor nedělá nic speciálního.

Na začátku životního cyklu objektu se nejdříve vymezí paměť pro atributy a pak se vyvolá konstruktor, který dosadí do těchto atributů počáteční hodnoty nebo si vyžádá další paměť z haldy a její umístění dá do ukazatelů.
Na konci života objektu se nejdříve provede destruktor, jehož hlavní úlohou je uvolnit paměť z haldy. Pak se uvolní paměť pro atributy.
Přidělování a rušení paměti pro atributy je stejné jako pro jiné proměnné:
- Statická deklarace vymezuje paměť pro atributy u příkazů – podobně jako u konstant.
- Automatická deklarace vymezuje paměť pro atributy v zásobníku programu.
- Dynamická deklarace (new) vymezuje paměť pro atributy v haldě.
Obvykle se u objektů používá dynamická deklarace, takže paměť pro atributy se vymezí v haldě, pak, nezávisle na tom, konstruktor vymezí v haldě další vyžadovanou paměť.
Jedna z nejzáludnějších chyb je použít příkaz delete na staticky nebo automaticky deklarovanou paměť. To je jeden z důvodů, proč profesionální programátoři používají výhradně dynamické deklarace.
