-
Nßsledujφ program zavßdφ pou╛itφ konstruktor∙ a destruktor∙.
class obdelnik {
// jednoduchß t°φda
int vyska;
int sirka;
public:
obdelnik(void);
// s konstruktorem,
int plocha(void);
// s dv∞mi metodami
void inicializace(int,
int);
~obdelnik(void);
// a s destruktorem
};
obdelnik::obdelnik(void){
// konstruktor
vyska = 6;
sirka = 6;
}
int obdelnik::plocha(void){
// plocha obdΘlnφku
return vyska
* sirka;
}
void obdelnik::inicializace(int
nova_vyska, int nova_sirka){
vyska = nova_vyska;
sirka = nova_sirka;
}
obdelnik::~obdelnik(void){
// destruktor
vyska = 0;
sirka = 0;
}
int main(int argc,
char **argv)
{
obdelnik okno,
ctverec;
cout <<
"Plocha okna je " << okno.plocha() << endl;
cout <<
"Plocha ctverce je " << ctverec.plocha() << endl;
okno.inicializace(12,10);
ctverec.inicializace(8,8);
cout <<
"Plocha okna je " << okno.plocha() << endl;
cout <<
"Plocha ctverce je " << ctverec.plocha() << endl;
return 0;
}
Tento program je identick² s programem uveden²m na konci p°edchozφ
kapitoly (do t°φdy je p°idßn konstruktor a destruktor a je vynechßna struktura).
Konstruktor
je v C++ volßn automaticky p°i deklaraci objektu a je tedy velkou pomocφ
k zabrßn∞nφ pou╛itφ neinicializovan²ch prom∞nn²ch. Kdy╛ deklarujeme objekt
okno,
konstruktor je volßn automaticky systΘmem a nastavφ hodnoty jeho polo╛ek
(v na╣em p°φpad∞ na hodnoty 6). Obdobn∞ to platφ i pro objekt
ctverec.
Konstruktor mß stejnΘ jmΘno jako t°φda (oboje se v na╣em p°φpad∞ jmenuje
obdelnik).
U konstruktoru nedefinujeme nßvratov² typ. I kdy╛ polo╛ky objektu jsou
ji╛ inicializovßny konstruktorem, m∙╛eme jim p°i°adit jinΘ hodnoty. Destruktor
je velmi podobn² konstruktoru, s tφm rozdφlem, ╛e je volßn automaticky,
kdy╛ se objekt dostane mimo rozsah. Destruktor mß stejnΘ jmΘno jako t°φda,
p°edchßzφ mu ale znak ~. Destruktor nemß ╛ßdn² nßvratov² typ. V na╣em p°φpad∞
destruktor provßdφ pouze vynulovßnφ obou polo╛ek. Destruktor je zde pouze
pou╛it pro ilustraci jeho pou╛itφ. Jestli╛e objekt alokoval n∞jakou pam∞╗,
pak destruktor by ji m∞l uvolnit.
-
Do konstruktoru a destruktoru p°idejte p°φkaz vypisujφcφ informaci o volßnφ,
aby jste se p°esv∞dΦili, ╛e jsou opravdu volßny systΘmem automaticky.
-
Podφvejte se na nßsledujφcφ program. Tento program se velmi podobß p°edchozφmu.
T°φda se nynφ jmenuje okno. Program by vßm m∞l b²t srozumiteln²
a╛ na jednu v∞c. Metoda oznaΦenß Φerven∞ obsahuje implementaci metody jako
Φßst deklarace. Je to obdoba vno°enΘ funkce. Program vyzkou╣ejte.
class okno {
// jednoduchß t°φda
int vyska;
int sirka;
public:
okno(void);
// s konstruktorem,
int ziskej_plochu(void){
return vyska * sirka; }; // s dv∞mi metodami
void nastav(int,
int);
~okno(void);
// a s destruktorem
};
okno::okno(void){
// konstruktor
vyska = 6;
sirka = 6;
}
void okno::nastav(int
nova_vyska, int nova_sirka){
vyska = nova_vyska;
sirka = nova_sirka;
}
okno::~okno(void){
// destruktor
vyska = 0;
sirka = 0;
}
int main(int argc,
char **argv)
{
okno male,
stredni, velke;
male.nastav(5,
7);
// stredni okno pou╛ije hodnoty nastavenΘ konstruktorem
velke.nastav(15,
20);
cout <<
"Plocha malΘho okna je " << male.ziskej_plochu() << endl;
cout <<
"Plocha st°ednφho okna je " << stredni.ziskej_plochu() << endl;
cout <<
"Plocha velkΘho okna je " << velke.ziskej_plochu() << endl;
return 0;
}
Namφsto termφnu ?volßnφ funkce pou╛φvßme ?zasφlßnφ zprßv. V t∞chto
dvou operacφch je rozdφl. Jeliko╛ data objektu jsou pevn∞ v objektu obsa╛ena,
neexistuje mimo metod zp∙sob jak tato data zφskat. Za╣leme tedy objektu zprßvu,
aby provedl n∞jakou operaci na sv²ch vnit°nφch datech. P°i volßnφ funkcφ
pou╛φvßme pro p°φstup k dat∙e? pou╛φvßme
-
Nßsledujφcφ program ukazuje pou╛itφ pole objekt∙.
class okno {
int delka;
int sirka;
public:
okno(void);
// konstruktor
void nastav(int
nova_delka, int nova_sirka);
int ziskej_plochu(void)
{return(delka * sirka);}
};
okno::okno(void){
// konstruktor
delka = 8;
sirka = 8;
}
void okno::nastav(int
nova_delka, int nova_sirka){
delka = nova_delka;
sirka = nova_sirka;
}
int main(int argc,
char **argv)
{
okno male,
stredni, velke, skupina[4];
// sedm oken
male.nastav(5,
7);
for (int index
= 1; index < 4; index++)
// skupina[0] je implicitnφ
skupina[index].nastav(index + 10, 10);
cout <<
"Plocha malΘho okna je " << male.ziskej_plochu() << endl;
cout <<
"Plocha st°ednφho okna je " << stredni.ziskej_plochu() << endl;
for (int index
= 0; index < 4; index++)
cout << "Plocha pole okna je " <<
skupina[index].ziskej_plochu() << endl;
return 0;
}
V tomto programu je p°idßna deklarace pole 4 objekt∙ t°φdy okno.
Ka╛d² z t∞chto objekt∙ je inicializovßn na hodnoty uvedenΘ v konstruktoru,
nebo╗ konstruktor je proveden pro v╣echny deklarovanΘ objekty. Pole objekt∙
je v programu dßle pou╛φvßno. Pov╣imn∞te si jak se zasφlajφ zprßvy jednomu
objektu v poli objekt∙. Pokuste se pochopit tento program a vyzkou╣ejte
jej.
-
Dal╣φ program pou╛φvß jako slo╛ku t°φdy °et∞zec znak∙. Ve skuteΦnosti v
objektu nenφ vlo╛en² °et∞zec znak∙, ale je zde ukazatel na °et∞zec znak∙.
class okno {
int delka;
int sirka;
char *radek_textu;
public:
okno(char
*radek);
void nastav(int
nova_delka, int nova_sirka);
int ziskej_plochu(void);
};
okno::okno(char *radek){
delka = 8;
sirka = 8;
radek_textu
= radek;
}
void okno::nastav(int
nova_delka, int nova_sirka){
delka = nova_delka;
sirka = nova_sirka;
}
okno::ziskej_plochu(void){
cout <<
radek_textu << " = ";
return (delka
* sirka);
}
int main(int argc,
char **argv)
{
okno male("malΘ
okno "), stredni("st°ednφ okno "), velke("velkΘ okno ");
male.nastav(5,
7);
// stredni okno pou╛ije hodnoty nastavenΘ konstruktorem
velke.nastav(15,
20);
cout <<
"Plocha ";
cout <<
male.ziskej_plochu() << endl;
cout <<
"Plocha ";
cout <<
stredni.ziskej_plochu() << endl;
cout <<
"Plocha ";
cout <<
velke.ziskej_plochu() << endl;
return 0;
}
V deklaraci t°φdy je nynφ pou╛it ukazatel na char pojmenovan²
radek_textu.
Konstruktor obsahuje vstupnφ parametr, kter²m je ukazatel na °et∞zec a
tento ukazatel bude v konstruktoru p°i°azen slo╛ce radek_textu.
Mohli bychom definovat prom∞nnou radek_textu jako pole znak∙ ve
t°φd∞ a potom pou╛φt funkci strcpy k p°ekopφrovßnφ °et∞zce do objektu.
Tφm se budeme zab²vat v nßsledujφcφm zadßnφ.
Nß╣ konstruktor mß nynφ jeden parametr, kter² slou╛φ k p°edßnφ informacφ
do objektu. Mohli bychom jich pou╛φt i vφce. Kdy╛ nynφ deklarujeme objekty,
p°edßvßme ka╛dΘ instanci jako aktußlnφ parametr °et∞zcovou konstantu, kterß
je potom pou╛ita konstruktorem k p°i°azenφ ukazatele na nφ, slo╛ce radek_textu.
V metod∞ ziskej_plochu tento text vypisujeme. V²pis textu sice s
v²poΦtem plochy nesouvisφ, ale zde je to pou╛ito pro ilustraci toho, ╛e
objekt obsahuje skuteΦn∞ ukazatel na text pou╛it² p°i deklaraci. Vhodn∞j╣φ
by bylo vytvo°it dal╣φ metodu pro zji╣t∞nφ tohoto °et∞zce (a p°φpadn∞ dal╣φ
pro jeho nastavenφ).
-
Zm∞≥te p°edchozφ program tak, aby t°φda pou╛φvala pole znak∙ namφsto ukazatele
na znak a do pole p°ekopφrujte °et∞zec znak∙ parametru konstruktoru. P°idejte
dal╣φ metodu umo╛≥ujφcφ zm∞nit ulo╛enou hodnotu °et∞zce zaslßnφm zprßvy
z hlavnφho programu a pou╛ijte novou metodu ke zm∞n∞ hodnot ulo╛en²ch ve
v╣ech t°ech objektech. V²pisem se p°esv∞dΦte o provedenΘ zm∞n∞.
-
Ve t°φd∞ m∙╛e b²t takΘ obsa╛en ukazatel na n∞jakß dynamicky alokovanß data.
To ukazuje nßsledujφcφ program.
class okno {
int delka;
int sirka;
int *ukazatel;
public:
okno(void);
void nastav(int
nova_delka, int nova_sirka, int ulozena_hodnota);
int ziskej_plochu(void)
{return(delka * sirka);}
int ziskej_hodnotu(void)
{return *ukazatel;}
~okno(void);
};
okno::okno(void){
delka = 8;
sirka = 8;
ukazatel =
new int;
*ukazatel
= 122;
}
void okno::nastav(int
nova_delka, int nova_sirka, int ulozena_hodnota){
delka = nova_delka;
sirka = nova_sirka;
*ukazatel
= ulozena_hodnota;
}
okno::~okno(void){
delka = 0;
sirka = 0;
delete ukazatel;
}
int main(int argc,
char **argv)
{
okno male,
stredni, velke;
male.nastav(5,
7, 177);
velke.nastav(15,
20, 999);
cout <<
"Plocha malΘho okna je " << male.ziskej_plochu() << endl;
cout <<
"Plocha st°ednφho okna je " << stredni.ziskej_plochu() << endl;
cout <<
"Plocha velkΘho okna je " << velke.ziskej_plochu() << endl;
cout <<
"Ulo╛enß hodnota malΘho okna je "<<male.ziskej_hodnotu()<<endl;
cout <<
"Ulo╛enß hodnota st°ednφho okna je "<<stredni.ziskej_hodnotu()<<endl;
cout <<
"Ulo╛enß hodnota velkΘho okna je "<<velke.ziskej_hodnotu()<<endl;
return 0;
}
V na╣em p°φpad∞ jsme do t°φdy p°idali ukazatel na int (je to
pouze ukazatel a alokaci mφsta v hromad∞ musφme provΘst v konstruktoru).
V na╣em programu jsou deklarovßny t°i objekty a ka╛d² z nich obsahuje ukazatel,
kter² ukazuje do hromady na t°i r∙znß mφsta. Ka╛d² objekt mß svou vlastnφ
dynamicky alokovanou datovou slo╛ku pro svΘ vlastnφ soukromΘ pou╛itφ. V
tomto malΘm programu se nedostaneme do situace, kdy bude nedostatek pam∞ti
v hromad∞. Ve skuteΦn²ch programech, je ale vhodnΘ testovat hodnotu vrßcenΘho
ukazatele na NULL a zjistit tak, zda prom∞nnß byla skuteΦn∞ alokovßna.
Metoda nastav mß nynφ t°i parametry a poslednφ z nich se pou╛φvß
k nastavenφ hodnoty novΘ dynamicky alokovanΘ prom∞nnΘ. V programu dßle
zasφlßme dv∞ zprßvy, jednu malΘmu oknu a druhou velkΘmu oknu k nastavenφ
jejich polo╛ek. St°ednφ okno mß stßle implicitnφ hodnoty. Alokovanou dynamickou
pam∞╗ musφme v destruktoru t°φdy op∞t uvolnit. K zji╣t∞nφ hodnoty dynamickΘ
prom∞nnΘ je pou╛ita metoda ziskej_hodnotu. Ulo╛enΘ hodnoty v dynamick²ch
prom∞nn²ch jsou vypsßny na konci programu. Prostudujte si tento program
a vyzkou╣ejte jak pracuje.
-
V nßsledujφcφm programu je pou╛it dynamicky alokovan² objekt. Vidφme, ╛e
pou╛φvßnφ dynamick²ch objekt∙ se neli╣φ od jin²ch dynamick²ch prom∞nn²ch.
Program si prostudujte.
class okno {
int delka;
int sirka;
public:
okno(void);
void nastav(int
nova_delka, int nova_sirka);
int ziskej_plochu(void);
};
okno::okno(void){
delka = 8;
sirka = 8;
}
void okno::nastav(int
nova_delka, int nova_sirka){
delka = nova_delka;
sirka = nova_sirka;
}
okno::ziskej_plochu(void){
return (delka
* sirka);
}
int main(int argc,
char **argv)
{
okno male,
stredni, velke;
okno *ukazatel;
male.nastav(5,
7);
velke.nastav(15,
20);
ukazatel =
new okno;
// pou╛itφ imlicitnφch hodnot
cout <<
"Plocha malΘho okna je " << male.ziskej_plochu() << endl;
cout <<
"Plocha st°ednφho okna je " << stredni.ziskej_plochu() << endl;
cout <<
"Plocha velkΘho okna je " << velke.ziskej_plochu() << endl;
cout <<
"Plocha novΘho okna je " << ukazatel->ziskej_plochu() << endl;
ukazatel->nastav(12,12);
cout <<
"Plocha novΘho okna je " << ukazatel->ziskej_plochu() << endl;
delete ukazatel;
return 0;
}
Na konci programu je pou╛it p°φkaz ukazatel->nastav(12,12).
Zd∙vodn∞te, zda tento p°φkaz by bylo mo╛no nahradit p°φkazem (*ukazatel).nastav(12,
12). Poslednφm p°φkazem programu je dynamicky alokovan² objekt
zru╣en. Zm∞≥te tento program tak, aby takΘ objekty male a stredni
byly alokovßny dynamicky.
-
Nßsledujφcφ program pou╛φvß objekt s vnit°nφm odkazem na jin² objekt svΘ
vlastnφ t°φdy. Je to standardnφ struktura pou╛φvanß pro jednosm∞rn∞ z°et∞zen²
seznam. V na╣em programu je pou╛ita velmi jednoduch²m zp∙sobem.
class okno {
int delka;
int sirka;
okno *dalsi_okno;
public:
okno(void);
void nastav(int
nova_delka, int nova_sirka);
int ziskej_plochu(void);
void nastav_ukazatel(okno
*ktere_okno);
okno *ziskej_dalsi(void);
};
okno::okno(void){
delka = 8;
sirka = 8;
dalsi_okno
= NULL;
}
void okno::nastav(int
nova_delka, int nova_sirka){
delka = nova_delka;
sirka = nova_sirka;
}
int okno::ziskej_plochu(void){
return (delka
* sirka);
}
void okno::nastav_ukazatel(okno
*ktere_okno){
dalsi_okno
= ktere_okno;
}
okno *okno::ziskej_dalsi(void){
return dalsi_okno;
}
int main(int argc,
char **argv)
{
okno male,
stredni, velke;
okno *ukazatel;
male.nastav(5,
7);
velke.nastav(15,
20);
cout <<
"Plocha malΘho okna je " << male.ziskej_plochu() << endl;
cout <<
"Plocha st°ednφho okna je " << stredni.ziskej_plochu() << endl;
cout <<
"Plocha velkΘho okna je " << velke.ziskej_plochu() << endl;
male.nastav_ukazatel(&stredni);
stredni.nastav_ukazatel(&velke);
ukazatel =
♂
ukazatel =
ukazatel->ziskej_dalsi();
cout <<
"Plocha okna je " << ukazatel->ziskej_plochu() << endl;
return 0;
}
V konstruktoru je inicializovßn ukazatel na NULL. Takto je vhodnΘ inicializovat
v╣echny ukazatele, kterΘ zatφm na nic neukazujφ. P°i°azenφ ukazatele v
konstruktoru zajistφ, ╛e v╣echny objekty tΘto t°φdy budou mφt sv∙j ukazatel
inicializovan². Do t°φdy byly p°idßny dal╣φ dv∞ metody. Pokuste se zjistit,
co d∞lajφ a co d∞lß cel² program.
-
V C++ je dal╣φ klφΦovΘ slovo a to this. Toto this je definovßno
v ka╛dΘm objektu a oznaΦuje ukazatel na objekt, ve kterΘm je obsa╛eno.
Je implicitn∞ deklarovßno jako
jmeno_t°idy *this;
a je inicializovßno k ukazovßnφ na objekt jeho╛ metoda je volßna. Ukazatel
this
nesmφme nikdy modifikovat. Tento ukazatel je velmi u╛iteΦn² pro prßci s
ukazateli a obzvlß╣t∞ se z°et∞zen²mi seznamy, kterΘ pot°ebujφ ukazatel
na objekt p°i vklßdßnφ do seznamu. Ukßzka pou╛itφ bude uvedena pozd∞ji.
-
Ukazatel this se takΘ Φasto pou╛φvß v aplikacφch GUI. Kdy╛ v aplikaci
GUI vklßdßme komponenty na formulß°, pak je v∞t╣ina prßce ud∞lßna za nßs.
Komponentu lze ale takΘ vytvo°it za b∞hu aplikace. Nap°. p°i stisku tlaΦφtka
m∙╛eme chtφt vytvo°it na formulß°i jinΘ tlaΦφtko. Obsluha stisku tlaΦφtka
v tomto p°φpad∞ bude:
void __fastcall TForm1::Button1Click(TObject
*Sender)
{
TButton *tlacitko
= new TButton(this);
tlacitko->Parent
= this;
tlacitko->Caption
= "NovΘ tlaΦφtko";
tlacitko->Left
= 100;
tlacitko->Top
= 50;
tlacitko->Show();
// dal╣φ k≤d
}
V tomto k≤du vidφme pou╛itφ ukazatele this (parametr konstruktoru
tlaΦφtka a vlastnost Parent vytvo°enΘho tlaΦφtka). Vyzkou╣ejte.
NovΘ pojmy:
-
Konstruktor je funkce, kterß je automaticky volßna p°i vytvß°enφ
instance t°φdy.
-
Destruktor je specißlnφ funkce, kterß je automaticky volßna p°i
ru╣enφ objektu.