-
Nßsledujφcφ program je nß╣ prvnφ p°φklad, kter² pou╛φvß ochranu dat. Jestli╛e
jsou datovΘ slo╛ky a metody t°φdy p°edka voln∞ dostupnΘ i ve t°φdßch potomk∙,
dßvß to programßtor∙m v∞t╣φ mo╛nosti p°i odvozovßnφ nov²ch t°φd. To zajistφme
vlo╛enφm klφΦovΘho slova protected p°ed deklaraci t∞chto slo╛ek.
Toto bylo provedeno u deklarace t°φdy vozidlo. U obou odvozen²ch
t°φd je p°ed deklaraci slo╛ek p°idßno klφΦovΘ slovo private (implicitn∞
jsou v╣echna data t°φdy soukromß a p°idßnφ tohoto klφΦovΘho slova tedy
nemß ╛ßdn² v²znam). Souhrnn∞ m∙╛eme popsat v²znam t∞chto klφΦov²ch slov
takto:
-
private - datovΘ slo╛ky a metody jsou dostupnΘ pouze v metodßch
t°φdy, kde jsou deklarovßny a v p°ßtelφch t°φdy.
-
protected - stejnΘ jako private, ale navφc i v odvozen²ch
t°φdßch.
-
public - datovΘ slo╛ky a metody mohou b²t pou╛φvßny kdekoli.
Po provedenφ t∞chto zm∞n jsou v metodßch odvozen²ch t°φd dostupnΘ i slo╛ky
z t°φdy p°edka. Vyzkou╣ejte.
class vozidlo {
protected:
int kola;
float vaha;
public:
void inicializace(int
nova_kola, float nova_vaha);
int ziskej_kola(void){return
kola;}
float ziskej_vahu(void){return
vaha;}
float vaha_na_kolo(void){return
vaha/kola;}
};
class automobil :
public vozidlo {
private:
int osob;
public:
void inicializace(int
nova_kola, float nova_vaha, int lidi = 4);
int pasazeru(void){return
osob;}
};
class nakladni :
public vozidlo {
private:
int osob;
float naklad;
public:
void inic_nakl(int
kolik = 2, float max_naklad = 12000.0);
float vykonost(void);
int pasazeru(void){return
osob;}
};
void vozidlo::inicializace(int
nova_kola, float nova_vaha){
kola = nova_kola;
vaha = nova_vaha;
}
void automobil::inicializace(int
nova_kola, float nova_vaha, int lidi){
osob = lidi;
vozidlo::inicializace(nova_kola,
nova_vaha);
}
void nakladni::inic_nakl(int
kolik, float max_naklad){
osob = kolik;
naklad = max_naklad;
}
float nakladni::vykonost(void){
return naklad
/ (naklad + ziskej_vahu());
}
int main(int argc,
char **argv)
{
vozidlo unicykl;
unicykl.inicializace(1,
7.5);
cout <<
"Unicykl mß " << unicykl.ziskej_kola() << " kol.\n";
cout <<
"Zßt∞╛ na kolo unicyklu je " << unicykl.vaha_na_kolo()<< endl;
cout <<
"Vßha unicyklu je " << unicykl.ziskej_vahu() << " kg.\n";
automobil
sedan;
sedan.inicializace(4,
1500.0, 5);
cout <<
"Sedan mß " << sedan.pasazeru() << " osob.\n";
cout <<
"Sedan mß zßt∞╛ " << sedan.vaha_na_kolo() << " kg na kolo.\n";
cout <<
"Sedan vß╛φ " << sedan.ziskej_vahu() << " kg.\n";
nakladni tatra;
tatra.inicializace(2,
7500.0);
tatra.inic_nakl(1,
7000.0);
cout <<
"Vßha tatry je " << tatra.ziskej_vahu() << " kg.\n";
cout <<
"V²konnost tatry je "<<100.0*tatra.vykonost()<<" procent.\n";
return 0;
}
Specifikßtor p°φstupu uveden² p°ed identifikßtorem t°φdy p°edka urΦuje
p°φstup ke zd∞d∞n²m slo╛kßm t°φdy. Pokud t°φda deklaruje svΘho p°edka se
specifikacφ public, jsou p°φstupovß prßva ke zd∞d∞n²m ve°ejn²m a
chrßn∞n²m slo╛kßm stejnΘ jako ve t°φd∞ p°edka. SoukromΘ slo╛ky jsou nep°φstupnΘ.
Deklarujeme-li p°edka se specifikacφ protected, omezφ se p°φstupovß
prßva k zd∞d∞n²m ve°ejn²m slo╛kßm. Slo╛ky, kterΘ byly v p°edkovi ve°ejnΘ
nebo chrßn∞nΘ, budou v potomkovi vystupovat jako chrßn∞nΘ a slo╛ky, kterΘ
byly soukromΘ, z∙stßvajφ nep°φstupnΘ. Deklarujeme-li p°edka se specifikacφ
private,
budou v╣echny zd∞d∞nΘ ve°ejnΘ a chrßn∞nΘ slo╛ky pova╛ovßny za soukromΘ
(soukromΘ slo╛ky p°edka jsou nep°φstupnΘ). Pokud u p°edka nedeklarujeme
specifikaci p°φstupu, platφ implicitnφ specifikace, kterß je stejnß jako
implicitnφ specifikace p°φstupu k jednotliv²m slo╛kßm: u t°φdy typu struct
je to specifikace public a u t°φd typu class specifikace
private.
-
V dal╣φ verzi tohoto programu jsou pou╛ity konstruktory. T°φda vozidlo
mß konstruktor inicializujφcφ polo╛ky kola a vaha na implicitnφ
hodnoty. Ostatnφ dv∞ t°φdy majφ takΘ konstruktory, inicializujφcφ jejich
polo╛ky na poΦßteΦnφ hodnoty. Jako implicitnφ hodnoty zde byly zadßny neobvyklΘ
hodnoty. V hlavnφm programu byly odstran∞ny p°φkazy provßd∞jφcφ inicializaci
(byly zm∞n∞ny na komentß°). Program vyzkou╣ejte.
class vozidlo {
protected:
int kola;
float vaha;
public:
vozidlo(void){kola
= 7; vaha = -55.7;}
void inicializace(int
nova_kola, float nova_vaha);
int ziskej_kola(void){return
kola;}
float ziskej_vahu(void){return
vaha;}
float vaha_na_kolo(void){return
vaha/kola;}
};
class automobil :
public vozidlo {
private:
int osob;
public:
automobil(void)
{osob = 12;}
void inicializace(int
nova_kola, float nova_vaha, int lidi = 4);
int pasazeru(void){return
osob;}
};
class nakladni :
public vozidlo {
private:
int osob;
float naklad;
public:
nakladni(void)
{osob = 9; naklad = 12.3;}
void inic_nakl(int
kolik = 2, float max_naklad = 12000.0);
float vykonost(void);
int pasazeru(void){return
osob;}
};
void vozidlo::inicializace(int
nova_kola, float nova_vaha){
kola = nova_kola;
vaha = nova_vaha;
}
void automobil::inicializace(int
nova_kola, float nova_vaha, int lidi){
osob = lidi;
vozidlo::inicializace(nova_kola,
nova_vaha);
}
void nakladni::inic_nakl(int
kolik, float max_naklad){
osob = kolik;
naklad = max_naklad;
}
float nakladni::vykonost(void){
return naklad
/ (naklad + ziskej_vahu());
}
int main(int argc,
char **argv)
{
vozidlo unicykl;
//
unicykl.inicializace(1, 7.5);
cout <<
"Unicykl mß " << unicykl.ziskej_kola() << " kol.\n";
cout <<
"Zßt∞╛ na kolo unicyklu je "<< unicykl.vaha_na_kolo() << endl;
cout <<
"Vßha unicyklu je " << unicykl.ziskej_vahu() << " kg.\n";
automobil
sedan;
//
sedan.inicializace(4, 1500.0, 5);
cout <<
"Sedan mß " << sedan.pasazeru() << " osob.\n";
cout <<
"Sedan mß zßt∞╛ " << sedan.vaha_na_kolo() << " kg na kolo.\n";
cout <<
"Sedan vß╛φ " << sedan.ziskej_vahu() << " kg.\n";
nakladni tatra;
//
tatra.inicializace(2, 7500.0);
//
tatra.inic_nakl(1, 7000.0);
cout <<
"Vßha tatry je " << tatra.ziskej_vahu() << " kg.\n";
cout <<
"V²konnost tatry je "<<100.0*tatra.vykonost()<<" procent.\n";
return 0;
}
K zji╣t∞nφ, kdy je kter² konstruktor automaticky volßn p°idejte do
v╣ech konstruktor∙ v tomto programu p°φkazy k v²pisu zprßvy informujφcφ
o
volßnφ konstruktoru. Prozkoumejte po°adφ volßnφ konstruktor∙ (i u odvozen²ch
t°φd).
Pokud neurΦφme n∞co jinΘho, vyvolß C++ nejprve bezparametrick² konstruktor
rodiΦovskΘ t°φdy a potΘ zaΦne provßd∞t vlastnφ konstruktor. Pokud chceme
inicializovat zd∞d∞nΘ slo╛ky jin²m zp∙sobem, musφme v hlaviΦce konstruktoru
uvΘst za dvojteΦkou odpovφdajφcφ volßnφ rodiΦovskΘho konstruktoru.
-
Ve skuteΦn²ch aplikacφch obvykle umis╗ujeme deklaraci a definici t°φdy
do jednoho hlaviΦkovΘho a jednoho zdrojovΘho souboru. Tyto soubory majφ
jmΘno, kterΘ odpovφdß jmΘnu t°φdy. Nap°. pokud mßme t°φdu mojeTrida,
pak umφstφme jejφ definici do zdrojovΘho souboru MOJETRIDA.CPP a jejφ deklaraci
do hlaviΦkovΘho souboru MOJETRIDA.H (m∙╛eme pou╛φvat dlouhß jmΘna soubor∙).
Ukß╛eme si to na nßsledujφcφ konzolovΘ aplikaci. ZaΦneme v²voj novΘ
konzolovΘ aplikace (ulo╛φme ji do souboru LETISTE.CPP). Obsah tohoto souboru
je tento:
#include <condefs.h>
#include <iostream.h>
#include <conio.h>
#pragma hdrstop
USEUNIT("letadlo.cpp");
#include "letadlo.h"
int ziskejVstup(int
max);
void ziskejPrvky(int&
rychlost, int& smer, int& vyska);
int main(int argc,
char **argv)
{
char vracenaZprava[100];
// nastavenφ
pole letadel a vytvo°enφ t°φ objekt∙ letadel
Letadlo* letadla[3];
letadla[0]
= new Letadlo("TWA 1040");
letadla[1]
= new Letadlo("United Express 749", DOPRAVNI);
letadla[2]
= new Letadlo("Cessna 3238T", SOUKROME);
// zaΦßtek
cyklu
do {
int letadlo, zprava, rychlost, vyska, smer;
rychlost = vyska = smer = -1;
cout << endl << "KterΘmu letadlu chcete zaslat zprßvu?";
cout << endl << endl << "0. Konec" << endl;
for (int i = 0; i < 3; i++)
cout << (i + 1) << ". " << letadla[i]->jmeno <<
endl;
// Zφskßnφ Φφsla letadla
letadlo = ziskejVstup(4);
// P°i 0 konec cyklu
if (letadlo == -1) break;
cout << endl<<"Vybrßno "<<letadla[letadlo]->jmeno<<endl<<endl;
cout << "Jakou zprßvu chcete zaslat?" << endl;
cout << endl << "0. Konec" << endl;
cout << "1. Zm∞na stavu" << endl;
cout << "2. Vzlet" << endl;
cout << "3. P°istßnφ" << endl;
cout << "4. Zprßva o stavu" << endl;
zprava = ziskejVstup(5);
if (zprava == -1) break;
if (zprava == 0) ziskejPrvky(rychlost, smer, vyska);
bool dobraZprava = letadla[letadlo]-> PrijmiZpravu(
zprava, vracenaZprava, rychlost, smer, vyska);
if (!dobraZprava) cout << endl << "Nelze provΘst.";
cout << endl << vracenaZprava << endl;
} while (1);
for (int i
= 0; i < 3; i++) delete letadla[i];
return 0;
}
int ziskejVstup(int
max)
{
int volba;
do {
volba = getch();
volba -= 49;
} while (volba
< -1 || volba > max);
return volba;
}
void ziskejPrvky(int&
rychlost, int& smer, int& vyska)
{
cout <<
endl << "Zadej novou rychlost: ";
cin >> rychlost;
cout <<
"Zadej nov² sm∞r: ";
cin >> smer;
cout <<
"Zadej novou v²╣ku: ";
cin >> vyska;
cout <<
endl;
}
Dßle zvolφme File | New | Text a vytvo°φme hlaviΦkov² soubor
t°φdy LETADLO.H (ulo╛φme jej do stejnΘho adresß°e jako LETISTE.CPP). Soubor
bude mφt tento obsah:
#ifndef letadloH
#define letadloH
#define LINKOVE
0
#define DOPRAVNI
1
#define SOUKROME
2
#define VZLET
0
#define LET
1
#define PRISTANI
2
#define NADRAZE
3
#define ZPR_ZMENA
0
#define ZPR_VZLET
1
#define ZPR_PRIST
2
#define ZPR_ZPRAVA
3
class Letadlo {
public:
Letadlo(const char* _jmeno, int _typ = LINKOVE);
~Letadlo();
virtual int ziskejStav(char* stavovyRetezec);
int ziskejStav() {return stav; }
int Rychlost() { return rychlost; }
int Smer() { return smer; }
int Vyska() { return vyska; }
void ZpravaStav();
bool PrijmiZpravu(int zpr, char* odpoved, int rych = -1,
int sme = -1, int vys = -1);
char* jmeno;
protected:
virtual void Vzletni(int smer);
virtual void Pristan();
private:
int rychlost;
int vyska;
int smer;
int stav;
int typ;
int maxVyska;
};
#endif
Obdobn∞ vytvo°φme dal╣φ soubor LETADLO.CPP (ulo╛φme jej op∞t do stejnΘho
adresß°e) s obsahem:
#include <stdio.h>
#include <iostream.h>
#include "letadlo.h"
Letadlo::Letadlo(const
char* _jmeno, int _typ):
typ(_typ),
stav(NADRAZE), rychlost(0), vyska(0), smer(0)
{
switch (typ)
{
case LINKOVE : maxVyska = 10000; break;
case DOPRAVNI : maxVyska = 6000; break;
case SOUKROME : maxVyska = 3000; break;
}
jmeno = new
char[50];
strcpy(jmeno,
_jmeno);
}
Letadlo::~Letadlo()
{
delete[] jmeno;
}
bool Letadlo::PrijmiZpravu(int
zpr, char* odpoved, int rych,
int sme, int vys)
{
if (rych >
800) {
strcpy(odpoved, "Rychlost nem∙╛e b²t v∞t╣φ ne╛ 800.");
return false;
}
if (sme >
360) {
strcpy(odpoved, "Sm∞r nem∙╛e b²t v∞t╣φ ne╛ 360 stupn∙.");
return false;
}
if (vys <
100 && vys != -1) {
strcpy(odpoved, "Jsme p°φli╣ nφzko.");
return false;
}
if (vys >
maxVyska) {
strcpy(odpoved, "To je p°φli╣ vysoko.");
return false;
}
switch (zpr)
{
case ZPR_VZLET : {
if (stav != NADRAZE) {
strcpy(odpoved, "Jsem ji╛ ve vzduchu.");
return false;
}
Vzletni(sme);
break;
}
case ZPR_ZMENA : {
if (stav == NADRAZE) {
strcpy(odpoved, "Jsem na zemi.");
return false;
}
if (rych != -1) rychlost = rych;
if (sme != -1) smer = sme;
if (vys != -1) vyska = vys;
stav = LET;
break;
}
case ZPR_PRIST : {
if (stav == NADRAZE) {
strcpy(odpoved, "Jsme na zemi.");
return false;
}
Pristan();
break;
}
case ZPR_ZPRAVA : ZpravaStav();
}
strcpy(odpoved,
"Provedeno.");
return true;
}
void Letadlo::Vzletni(int
sme)
{
smer = sme;
stav = VZLET;
}
void Letadlo::Pristan()
{
rychlost =
smer = vyska = 0;
stav = NADRAZE;
}
int Letadlo:: ziskejStav(char*
stavovyRetezec)
{
sprintf(stavovyRetezec,
"%s, V²╣ka: %d, Sm∞r: %d, Rychlost: %d\n",
jmeno, vyska, smer, rychlost);
return stav;
}
void Letadlo::ZpravaStav()
{
char buff[100];
ziskejStav(buff);
cout <<
endl << buff << endl;
}
Kdy╛ se podφvßme na hlaviΦkov² soubor t°φdy Letadlo, pak na
jeho zaΦßtku vidφme °adu direktiv #define. Definujeme zde makra,
kterß nahradφ textovΘ °et∞zce Φφseln²mi hodnotami (°et∞zce si zapamatujeme
snadn∞ji ne╛ Φφsla). Posu∩te sami, kter² z nßsledujφcφch p°φkaz∙ je srozumiteln∞j╣φ?
if (typ == LINKOVY)
...
// nebo
if (typ == 0) ...
JmΘna t∞chto konstant obvykle zapisujeme velk²mi pφsmeny (pro snadnΘ
odli╣enφ od prom∞nn²ch). Jin²m zp∙sobem deklarace konstant je deklarace
prom∞nnΘ s modifikßtorem const. Nap°.
const int LINKOVY
= 0;
Pou╛itφ konstantnφ prom∞nnΘ je modern∞j╣φ metoda ne╛ definice konstant
pomocφ maker.
Dal╣φ °ßdky hlaviΦkovΘho souboru obsahujφ deklaraci t°φdy. KrßtkΘ metody
jsou zde deklarovßny jako vlo╛enΘ funkce. Je zde takΘ p°ekrytß funkce ziskejStav.
Pov╣imn∞te si, ╛e ve t°φd∞ je pouze jedna ve°ejnß datovß slo╛ka. Ostatnφ
jsou soukromΘ a jsou tedy dostupnΘ pouze pomocφ metod. Tzn. pokud po╛adujeme
zm∞nu rychlosti, v²╣ky nebo sm∞ru, pak musφme instanci Letadlo zaslat
zprßvu. To odpovφdß skuteΦnosti. ╪φdφcφ letovΘho provozu takΘ nem∙╛e fyzicky
zm∞nit sm∞r letadla. M∙╛e pouze zaslat zprßvu pilotovi a ten po╛adovanou
zm∞nu provede.
Nynφ p°ejdeme k definiΦnφmu souboru t°φdy. Konstruktor provßdφ inicializaci,
vΦetn∞ dynamickΘ alokace mφsta pro pole znak∙ k ulo╛enφ jmΘna letadla.
Tato pam∞╗ je uvol≥ovßna v destruktoru. V∞t╣inu prßce provßdφ metoda PrijmiZpravu.
P°φkaz switch urΦuje, kterß zprßva byla p°ijata a je provedena p°φslu╣nß
akce. Pov╣imn∞te si, ╛e metody Vzletni a Pristan nemohou
b²t volßny p°φmo (jsou chrßn∞nΘ), ale prost°ednictvφm PrijmiZpravu.
Nelze tedy °φci letadlu aby vzlΘtlo nebo p°istßlo, ale lze mu zaslat zprßvu,
aby to provedlo. Metoda ZpravaStav volß ZiskejStav k zφskßnφ
stavovΘho °et∞zce, kter² potom metoda vypφ╣e.
Hlavnφ program deklaruje pole ukazatel∙ na Letadlo a vytvß°φ
t°i instance tΘto t°φdy. Dßle zaΦφnß cyklus ve kterΘm zasφlßme zprßvy objekt∙m
Letadlo
volßnφm funkce PrijmiZpravu. Po odeslßnφ zprßvy, Φekßme na odpov∞∩
od letadla. Tento cyklus pob∞╛φ stßle, dokud nenφ ukonΦen p°φkazem
break.
Rozd∞lovat program do n∞kolika soubor∙ je vhodnΘ u slo╛it∞j╣φch aplikacφ.
U na╣ich (zatφm jednoduch²ch) aplikacφ z∙staneme u jednoho zdrojovΘho souboru.
Kontrolnφ otßzky:
-
Jak m∙╛eme dosßhnou toho, ╛e metody budou nedotupnΘ z vn∞j╣ku t°φdy a budeme
je moci volat v odvozen²ch t°φdßch?
-
Co je to objekt?
-
M∙╛e mφt t°φda vφce ne╛ jeden konstruktor?
-
Jak se li╣φ t°φda od struktury v C++?
-
Jak² v²znam majφ soukromΘ datovΘ slo╛ky?
-
Jak m∙╛eme u soukrom²ch datov²ch slo╛ek umo╛mit u╛ivateli Φφst a nastavovat
jejich hodnoty?
-
Jak a kdy je volßn destruktor t°φdy?
-
K Φemu slou╛φ inicializaΦnφ seznam t°φdy?
-
M∙╛e t°φda obsahovat instance jinΘ t°φdy jako datovΘ slo╛ky?
╪e╣enφ