Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
C/C++
Vytváření instancí - konstruktory, destruktory
18. ledna 2001, 00.00 | V tomto článku si povíme něco o vytváření instancí, konstruktorech, destruktorech, operátorech new, delete a o věcech s těmito pojmy souvisejících.
KonstruktorKaždá instance je vytvořena pomocí speciální metody - konstruktoru. Konstruktor se musí jmenovat stejně jako třída, jejíž instance bude vytvářet, nesmí mít návratovou hodnotu a měl by být veřejný. Každá třída může mít k dispozici více konstruktorů s různými parametry. Jedná se o přetěžování konstruktorů - o přetěžování jsem se zmiňoval v 1. článku "Od C k C++". Nemá-li třída žádný konstruktor (Například třída MojePrvniTrida v mém předchozím článku "Vytváření tříd, instance třídy, zasílání zpráv".) vytvoří překladač tak zvaný implicitní konstruktor bez parametrů. V konstruktoru by se měla provést inicializace dané instance. Nastavit všechny její atributy, vytvořit instance tříd, které obsahuje atd... Uvedu příklad jednoduché třídy Zlomek i s konstruktory.
|
Nejprve vysvětlím některé možné nejasnosti ke zdrojovému textu, i když se přímo netýkají zaměření článku:
- Klíčové slovo const za některými metodami. - Takto označená metoda nemění nijak vnitřní stav instance. V C++ existují "konstantní instance", stejně jako v C konstantní proměnné. V C++ může být konstantní jak proměnná "primitivního" datového typu, tak i instance. "Konstantní instanci" nelze nijak měnit vnitřní stav. Lze pro takovou instanci vyvolat pouze metody deklarované klíčovým slovem const .
- Možná někoho napadne otázka, jestli není lepší napsat atributy jako veřejné a ušetřit psaní metod nastav... a dej... - Veřejné atributy porušují princip zapouzdření. Kdybych se nyní rozhodl nějak změnit reprezentaci čitatele a jmenovatele, musel bych změnit jen metody třídy Zlomek. Objekt se bere jako černá skříňka, která by se změnila jen uvnitř, vůči okolí by se jako celek nezměnila. S veřejnými atributy by to tak lehké nebylo. Musel by se změnit celý program všude tam, kde by byly používány nějaké instance třídy Zlomek . I když uznávám, že v takto jednoduché třídě jako je Zlomek bych velmi těžce odolával pokušení dát atributy jako soukromé. Podle principů OOP je ale určitě správné přistupovat k atributům přes metody. Jestliže máte obavu ze zpomalení programu voláním, můžete metody deklarovat jako inline.
Konstruktory v této třídě jsem napsal tak, aby bylo jasné, že slouží k inicializaci instance. Jsou napsány sice jasně a přehledně, ale ne nejlépe. Všechny konstruktory, které jsem zde napsal, lze napsat efektivněji. Je třeba vzít na vědomí, že před spuštěním samotného těla konstruktoru dojde k inicializaci (volání konstruktorů) všech členských dat třídy. Například v konstruktoru Zlomek(int citatel, int jmenovatel) dojde nejprve k inicializaci položek Citatel, Jmenovatel a poté k provedení těla konstruktoru, kde tyto dvě položky znovu změním. V tomto konkrétním případě to snad ani nevadí, protože int žádné konstruktory nemá. Kdyby se ale jednalo o instance nějaké třídy, zjistili by jste, že je pro položky nejprve zavolán konstruktor bez parametrů a poté přiřazena nějaká hodnota operátorem =. Obojí lze efektivněji provést v jednom kroku. Za název konstruktoru, před jeho tělo umístíme za dvojtečkou seznam položek s inicializačními hodnotami v závorce. Zmiňovaný konstruktor lze přepsat takto:
|
Při vytváření instance třídy již mohu použít její metody, i když vlastně instance je vytvořená až po dokončení konstruktoru.
Někdy by se mohlo zdát, že je zbytečné vytvářet konstruktor bez parametrů. Bezparametrický konstruktor je ale nutný například při vytváření polí objektů a podobně. Vše ukážu dále.
Ke konstruktorům se ještě vrátím.
Destruktor, jak již asi sám jeho název napovídá, slouží k likvidaci objektů. Destruktor (stejně jako konstruktor) je metoda, která je zavolána na instanci v momentě, kdy je instance likvidována. Destruktor se jmenuje stejně jako třída, jen před názvem třídy je znak ~ . Destruktor nesmí mít návratovou hodnotu a žádné parametry. V destruktoru by se měly uvolnit všechny zdroje, se kterými instance pracovala. Například uzavřít datové soubory, uvolnit případnou alokovanou paměť a podobně. Nemá-li třída destruktor, překladač vytvoří implicitní destruktor. Ve třídě Zlomek naprosto stačí implicitní destruktor. Já ale jako příklad uvedu. Připište prosím do třídy Zlomek mezi veřejné prvky deklaraci: ~Zlomek(); a dále připište metodu:
|
Protože požívám cout nezapomeňte na začátek zdrojového textu napsat: #include<iostream.h>
Jak vytvářet instance
Na instance lze v C++ někdy pohlížet jako na proměnné. Instance stejně jako proměnné mohou být "statické", nebo "dynamické". Statická instance má stejně jako proměnná platnost (viditelnost) v aktuálním bloku, kde byla vytvořena. V momentě, kdy její platnost končí, je automaticky zlikvidována zavoláním svého destruktoru. Příklad: (Připište jej do souboru, kde je definována třída Zlomek
|
V programu jsou nejprve zavolány konstruktory globálních instancí, poté je až spuštěna funkce main , ve které jsou volány konstruktory a destruktory na lokální instance. Po skončení main jsou likvidovány globální instance.
Další možností je dynamické alokace paměti na haldě, a vytvoření instance. K takové instanci přistupujeme přes ukazatel, který na ní "ukazuje". Ukazatel deklarujeme jako v jazyce C. Pro alokaci paměti existuje nový operátor new . V takovém případě instance "přežije" konec bloku, a je potřeba ji zrušit operátorem delete . Stejně jako je tomu v C s dynamickými prom. Obdoba new a delete je v C malloc a free . Není správné ale používat funkce malloc a free , protože jen alokují paměť. narozdíl od toho new navíc zavolá konstruktor a delete zavolá destruktor. Jako příklad uvedu novou funkci main :
|
V těchto příkladech jsem vždy přepokládal, že paměť pro instance je vždy k dispozici. To je samozřejmě velmi naivní. Operátor new v případě, že neuspěje s alokací paměti, vrací NULL , nebo vypustí tak zvanou vyjímku. Vyjímkám věnuji jeden z mých dalších článků.
Článek je již dost dlouhý a já jsem se bohužel ještě nezmínil o jednom specielním a velmi důležitém konstruktoru, který se nazývá kopírovací konstruktor. Ve třídě Zlomek nebyl potřeba. Absence kopírovacího konstruktoru je velmi častou chybou a velmi častou příčinou nevysvětlitelných pádů programů. Někdy trvá dost dlouho, než si programátor uvědomí, že příčina nepochopitelných pádů programu je nepřítomnost kopírovacího konstruktoru. Proto vám doporučuji si přečíst můj další článek, který o kopírovacích konstruktorech bude.
Obsah seriálu (více o seriálu):
- Základy OOP v C++: Od C k C++
- Základní pojmy objektově orientovaného programování
- Vytváření tříd, instance třídy, zasílání zpráv v C++
- Vytváření instancí - konstruktory, destruktory
- Kopírovací konstruktor v C++
- Jednoduchá dědičnost v C++
- Časná versus pozdní vazba - úvod do polymorfismu v C++
- Polymorfismus - dokončení
- Vícenásobná dědičnost v C++
- Vícenásobná dědičnost v C++ - opakovaná dědičnost
- Vícenásobná dědičnost v C++ - volání konstruktorů a destruktorů
- Přetěžování operátorů v C++ 1.díl
- Přetěžování operátorů v C++ 2. díl
- Vstupní a výstupní operace pomocí datových proudů v C++
- Přetěžování operátorů << a >> pro datové proudy v C++
- Neformátovaný vstup a výstup v C++
- Paměťové proudy v C++
- Prostory jmen v C++
- Řetězce v C++
- Výjimky v C++
- Výjimky v C++ - výjimky tvoří dědičnou hierarchii
- Výjimky v C++ - dokončení
- Dynamická identifikace typů v C++
- Přetypování v C++
- Problémy s typy při vícenásobné dědičnosti
- Šablony funkcí v C++
- Šablony datových typů v C++
- Vnitřní typy u parametrů šablon, vnořené šablony v C++
- Pole s libovolným intervalem indexování v C++
- Datové kontejnery v C++ - Úvod do STL
- Vector - datový kontejner v C++
- Iterátory v C++
- Šablona vector v C++ a iterátory
- Asociativní pole v C++
- Množina v C++
- Funkční objekty v C++
- Standardní funkční objekty v C++
- Úvod do standardních algoritmů v C++
- Kopírovací a přesouvací algoritmy v C++
- Vyhledávací algoritmy v C++
- Skenovací (prohlížecí) algoritmy v C++
- Transformační algoritmy v C++
- Řadící algoritmy v C++
- Halda v C++
- Standardní algoritmy v C++ - dokončení
- Automatické ukazatele v C++
- Inteligentní ukazatel - čítač referencí v C++
- Použití čítače referencí v C++
- Kopírování velkých objektů v C++
- Řízené kopírování prvků v poli v C++
- Dokončení seriálu objektově orientované programování v C++
-
25. listopadu 2012
-
30. srpna 2002
-
10. října 2002
-
4. listopadu 2002
-
12. září 2002
-
25. listopadu 2012
-
28. července 1998
-
31. července 1998
-
28. srpna 1998
-
6. prosince 2000
-
27. prosince 2007
-
4. května 2007