#include <iostream>
int main()
{
std::cout << "Nazdar lidi!\n";
return 0;
}
Program nedělá nic jiného než výpis na obrazovku.
#include <iostream.h>
int main()
{
cout << "Nazdar lidi!\n";
return 0;
}
#include <iostream>
int main()
{
std::cout << "Dobry den.\n";
std::cout << "Zde je cislo 5: " << 5 << "\n";
std::cout << "Manipulacni objekt std::endl ";
std::cout << "zpusobi zalomeni radku na obrazovce.";
std::cout << std::endl;
std::cout << "Zde je velke cislo:\t\t" << 70000;
std::cout << std::endl;
std::cout << "Tady je soucet 8 a 5:\t\t";
std::cout << 8+5 << std::endl;
std::cout << "A tady mame zlomek:\t\t";
std::cout << (float) 5/8 << std::endl;
std::cout << "Zde je velmi velke cislo:\t";
std::cout << (double) 7000 * 7000 << std::endl;
std::cout << "Nezapomente zmenit Jesse Liberty ";
std::cout << "na vase vlastni jmeno...\n";
std::cout << "Jesse Liberty je programator C++!\n";
return 0;
}
Pro výpis výsledku po nějaké operaci, je někdy nutné uvést výpočet do závorek, tedy např.:
std::cout << (8+5) << std::endl;
// Používání klíčového slova "using"
#include <iostream>
int main()
{
using std::cout;
using std::endl;
cout << "Dobry den.\n";
cout << "Zde je cislo 5: " << 5 << "\n";
cout << "Manipulacni objekt endl ";
cout << "zpusobi zalomeni radku na obrazovce.";
cout << endl;
cout << "Zde je velke cislo:\t\t" << 70000;
cout << endl;
cout << "Tady je soucet 8 a 5:\t\t";
cout << 8+5 << endl;
cout << "A tady mame zlomek:\t\t";
cout << (float) 5/8 << endl;
cout << "Zde je velmi velke cislo:\t";
cout << (double) 7000 * 7000 << endl;
cout << "Nezapomente zmenit Jesse Liberty ";
cout << "na vase vlastni jmeno...\n";
cout << "Jesse Liberty je programator C++!\n";
return 0;
}
Použitím using std::cout jsme kompilátoru sdělili, že má jako objekt cout použít objekt
standardní knihovny std...
// Používání klíčového slova "namespace"
#include <iostream>
int main()
{
using namespace std;
cout << "Dobry den.\n";
cout << "Zde je cislo 5: " << 5 << "\n";
cout << "Manipulacni objekt endl ";
cout << "zpusobi zalomeni radku na obrazovce.";
cout << endl;
cout << "Zde je velke cislo:\t\t" << 70000;
cout << endl;
cout << "Tady je soucet 8 a 5:\t\t";
cout << 8+5 << endl;
cout << "A tady mame zlomek:\t\t";
cout << (float) 5/8 << endl;
cout << "Zde je velmi velke cislo:\t";
cout << (double) 7000 * 7000 << endl;
cout << "Nezapomente zmenit Jesse Liberty ";
cout << "na vase vlastni jmeno...\n";
cout << "Jesse Liberty je programator C++!\n";
return 0;
}
#include <iostream>
int main()
{
using std::cout;
/* toto je komentář
and sahá až po ukončující
značku hvězdičky a lomítka */
cout << "Nazdar lidi!\n";
// tento komentář končí s koncem řádku
cout << "Komentar skoncil!\n";
// komentáře s dvojitým lomítkem mohou být na samostatném řádku
/* stejně jako komentáře s lomítkem a hvězdičkou */
return 0;
}
Komentáře by neměly říkat co se děje, ale PROČ se to děje!
#include <iostream>
// funkce IlustracniFunkce
// vytiskne velmi užitečnou zprávu
void IlustracniFunkce()
{
std::cout << "Uvnitr Ilustracni funkce\n";
}
// funkce main - vytiskne zprávu, pak zavolá
// ilustrační funkci a nakonec vytiskne
// druhou zprávu
int main()
{
std::cout << "Ve funkci main\n";
IlustracniFunkce();
std::cout << "Zpet ve funkci main\n";
return 0;
}
#include <iostream>
int Soucet(int x, int y)
{
std::cout << "Ve funkci Soucet(), prijato " << x << " a " << y << "\n";
return (x+y);
}
int main()
{
using std::cout;
using std::cin;
cout << "Ve funkci main()!\n";
int a, b, c;
cout << "Vlozte dve cisla: ";
cin >> a;
cin >> b;
cout << "\nVolani funkce Soucet()\n";
c=Soucet(a,b);
cout << "\nZpet ve funkci main().\n";
cout << "c bylo nastaveno na " << c;
cout << "\nKonec...\n\n";
return 0;
}
cin >> slouží k získání vstupních hodnot od uživatele.
Ve funkci main()! Vlozte dve cisla: 2 7 Volani funkce Soucet() Ve funkci soucet(), prijato 2 a 7 Zpet ve funkci main(). c bylo nastaveno na 8 Konec...
| TYP | VELIKOST (Bajtů) | HODNOTY |
|---|---|---|
| bool | 1 | true, false |
| unsigned short int | 2 | 0..65 535 |
| short int | 2 | -32 768..32 767 |
| unsigned long int | 4 | 0..4 294 967 295 |
| long int | 4 | -2 147 483 648..2 147 483 647 |
| int (16b) | 2 | -32 768..32 767 |
| int (32b) | 4 | -2 147 483 648..2 147 483 647 |
| unsigned int (16b) | 2 | 0..65 535 |
| unsigned int (32b) | 4 | 0..4 294 967 295 |
| char | 1 | 256 znakových hodnot |
| float | 4 | 1,2e-38..3,4e38 |
| double | 8 | 2,2e-308..1,8e308 |
#include <iostream>
int main()
{
using std::cout;
cout << "Velikost typu int je:\t\t"
<< sizeof(int) << " bajtu.\n";
cout << "Velikost typu short je:\t\t"
<< sizeof(short) << " bajtu.\n";
cout << "Velikost typu long je:\t\t"
<< sizeof(long) << " bajtu.\n";
cout << "Velikost typu char je:\t\t"
<< sizeof(char) << " bajtu.\n";
cout << "Velikost typu float je:\t\t"
<< sizeof(float) << " bajtu.\n";
cout << "Velikost typu double je:\t"
<< sizeof(double) << " bajtu.\n";
cout << "Velikost typu bool je:\t\t"
<< sizeof(bool) << " bajtu.\n";
return 0;
}
Kde sizeof(argument) vrací velikost argumentu v bajtech.
int main()
{
unsigned short int promenna;
long a,b,treti_promenna;
...
return promenna;
}
Proměnné lze definovat a rovnou inicializovat: unsigned short a=5;
// Ukázka použití proměnných
#include <iostream>
int main()
{
using std::cout;
using std::endl;
unsigned short int Sirka = 5, Delka;
Delka = 10;
// vytvoření proměnné typu unsigned short a její inicializace
// na výsledek násobení šířky délkou
unsigned short int Plocha = (Sirka * Delka);
cout << "Sirka: " << Sirka << "\n";
cout << "Delka: " << Delka << endl;
cout << "Plocha: " << Plocha << endl;
return 0;
}
// Ukázka použití klíčového slova typedef
#include <iostream>
typedef unsigned short int USHORT; // definice USHORT
int main()
{
using std::cout;
using std::endl;
USHORT Sirka = 5;
USHORT Delka;
Delka = 10;
USHORT Plocha = Sirka * Delka;
cout << "Sirka: " << Sirka << "\n";
cout << "Delka: " << Delka << endl;
cout << "Plocha: " << Plocha << endl;
return 0;
}
kdy místo opisování "unsigned short int" napíšeme kratší USHORT
#include <iostream>
int main()
{
for (int i = 32; i<128; i++)
std::cout << (char) i;
return 0;
}
| ZNAK | Význam |
|---|---|
| \a | pípnutí |
| \b | smazání předchozího znaku |
| \f | posun o stránku |
| \n | nový řádek |
| \r | návrat vozíku |
| \t | tabulátor |
| \v | vertikální tabulátor |
| \' | apostrof |
| \" | uvozovky |
| \? | otazník |
| \\ | zpětné lomítko |
| \000 | oktalový zápis |
| \xhhh | šestnáctkový zápis |
#include <iostream>
int main()
{
enum Dny { Pondeli, Utery, Streda,
Ctvrtek, Patek, Sobota, Nedele };
Dny dnes;
dnes = Pondeli;
if ( dnes == Sobota || dnes == Nedele )
std::cout << "\nMiluji vikendove dny!\n";
else
std::cout << "\nVzhuru do prace.\n";
return 0;
}
{
pom=a;
a=b;
b=pom;
}
je blok, který se provede jako jeden příkaz (dojde k výměně obsahu proměnných a,b)
x=y=a+b;bude vyhodnoceno a+b a výsledek součtu bude přiřazen do y a následně do x.
#include <iostream>
int main()
{
using std::cout;
using std::endl;
int a=0, b=0, x=0, y=35;
cout << "a: " << a << " b: " << b;
cout << " x: " << x << " y: " << y << endl;
a = 9;
b = 7;
y = x = a+b;
cout << "a: " << a << " b: " << b;
cout << " x: " << x << " y: " << y << endl;
return 0;
}
| Symbol | Význam |
|---|---|
| + | Sčítání |
| - | Odčítání |
| * | Násobení |
| / | Dělení |
| % | Zbytek po celočíselném dělení |
// demonstruje odečítání a
// přetečení celočíselné proměnné
#include <iostream>
int main()
{
using std::cout;
using std::endl;
unsigned int rozdil;
unsigned int velkeCislo = 100;
unsigned int maleCislo = 50;
rozdil = velkeCislo - maleCislo;
cout << "Rozdil je: " << rozdil;
rozdil = maleCislo - velkeCislo;
cout << "\nRozdil nyni: " << rozdil << endl;
return 0;
}
Výstup bude:Rozdíl je: 50 Rozdíl nyní: 4294968246
zvys: 4zvys = zvys - 3;
zvys: 1zvys += 5;
zvys: 6zvys -= 2;
zvys: 4zvys /= 2;
zvys: 2atd... kdy operátor += přičte k hodnotě vlevo hodnotu vpravo
// používání operátoru inkrementace a dekrementace
// (zvýšení a snížení hodnoty o 1)
// s prefixovým a postfixovým zápisem
#include <iostream>
int main()
{
using std::cout;
int mujVek = 39; // inicializace dvou celočíselných proměnných
int tvujVek = 39;
cout << "Mam " << mujVek << " let.\n";
cout << "Mas " << tvujVek << " let.\n";
mujVek++; // postfixová inkrementace
++tvujVek; // prefixová inkrementace
cout << "Uplynul jeden rok...\n";
cout << "Mam " << mujVek << " let.\n";
cout << "Mas " << tvujVek << " let.\n";
cout << "Uplynul dalsi rok...\n";
cout << "Mam " << mujVek++ << " let.\n";
cout << "Mas " << ++tvujVek << " let.\n";
cout << "Vytiskneme to znovu.\n";
cout << "Mam " << mujVek << " let.\n";
cout << "Mas " << tvujVek << " let.\n";
return 0;
}
Mam 39 let. Mas 39 let. Uplynul jeden rok... Mam 40 let. Mas 40 let. Uplynul dalsi rok... Mam 40 let. Mas 41 let. Vytiskeme to znovu. Mam 41 let. Mas 41 let.
x: 104
| Postavení | Název | Operátor |
|---|---|---|
| 1 | stanovení oboru platnosti | :: |
| 2 | výběr členů,dolní index,volání funkcí, postfixová inkrementace a dekrementace | .--> () ++ -- |
| 3 | sizeof, prefixová inkrementace a dekrementace komplement, AND, NOT, unární minus a plus adresa a zrušení odkazů, new, new[],delete, delete[], typová konverze, sizeof() | ++ -- ^ ! - + & * () |
| 4 | výběr člena pro ukazatel | .* .->* |
| 5 | násobení, dělení, dělení se zbytkem | * / % |
| 6 | sčítání odečítání | + - |
| 7 | bitový posun vlevo a vpravo | << >> |
| 8 | relační operátory nerovnosti | < <= > >= |
| 9 | rovnost, nerovnost | == != |
| 10 | bitový operátor AND (a zároveň) | & |
| 11 | bitový operátor XOR (výhradně nebo) | ^ |
| 12 | bitový operátor OR (nebo) | | |
| 13 | logický operátor AND (a zároveň) | && |
| 14 | logický operátor OR (nebo) | || |
| 15 | podmínkový ternární operátor | ?: |
| 16 | operátory přiřazení | = *= /= %= += -= <<= >>= &= |= ^= |
| 17 | operátor throw | throw |
| 18 | operátor čárka | , |
| Název | Operátor |
|---|---|
| Rovná se | == |
| Nerovná se | != |
| Vetší než | > |
| Vetší nebo rovno | >= |
| Menší než | < |
| Menší nebo rovno | <= |
if (výraz)
{
příkaz;
příkaz2;
}
if (podminka)
{
příkazy po splnění...
}
else
{
příkazy pokud není podminka pravSPANá
}
Příklad.:
// složitý vnořený
// příkaz if
#include <iostream>
int main()
{
// Požádá o zadaní dvou čísel
// Přiřadí čísla do proměnných prvniCislo a druheCislo
// Pokud je prvniCislo větší než druheCislo,
// zjistí, zda jsou dělitelná beze zbytku
// Pokud jsou, zjistí, zda se jedná o stejné číslo
using namespace std;
int prvniCislo, druheCislo;
cout << "Zadejte dve cisla.\nPrvni: ";
cin >> prvniCislo;
cout << "\nDruhe: ";
cin >> druheCislo;
cout << "\n\n";
if (prvniCislo >= druheCislo)
{
if ( (prvniCislo % druheCislo) == 0) // dělitelná beze zbytku?
{
if (prvniCislo == druheCislo)
cout << "Jsou stejna!\n";
else
cout << "Jsou delitelna beze zbytku!\n";
}
else
cout << "Nejsou delitelna beze zbytku!\n";
}
else
cout << "Druhe cislo je vetsi!\n";
return 0;
}
| Operátor | Symbol | Příklad |
|---|---|---|
| AND | && | vyraz1 & vyraz2 |
| OR | || | vyraz1 | vyraz2 |
| NOT | ! | !vyraz1 |
// demonstruje operátor podmínky
//
#include <iostream>
int main()
{
using namespace std;
int x, y, z;
cout << "Vlozte dve cisla.\n";
cout << "Prvni: ";
cin >> x;
cout << "\nDruhe: ";
cin >> y;
cout << "\n";
if (x > y)
z = x;
else
z = y;
cout << "z: " << z;
cout << "\n";
z = (x > y) ? x : y;
cout << "z: " << z;
cout << "\n";
return 0;
}
// demonstruje používání prototypu funkcí
#include <iostream>
int Plocha(int delka, int sirka); //prototyp funkce
int main()
{
using std::cout;
using std::cin;
int delkaDvorku;
int sirkaDvorku;
int plochaDvorku;
cout << "\nJak siroky je Vas dvorek? ";
cin >> sirkaDvorku;
cout << "\nJak dlouhy je Vas dvorek? ";
cin >> delkaDvorku;
plochaDvorku= Plocha(delkaDvorku,sirkaDvorku);
cout << "\nVas dvorek ma plochu ";
cout << plochaDvorku;
cout << " ctverecnich metru.\n\n";
return 0;
}
int Plocha(int d, int s)
{
return d * s;
}
// využití lokálních proměnných a parametrů
#include <iostream>
float Prevod(float);
int main()
{
using namespace std;
float TeplotaFer;
float TeplotaCel;
cout << "Vlozte prosim teplotu v jednotkach Fahrenheita: ";
cin >> TeplotaFer;
TeplotaCel = Prevod(TeplotaFer);
cout << "\nA zde je teplota v jednotkach Celsia: ";
cout << TeplotaCel << endl;
return 0;
}
float Prevod(float TeplotaFer)
{
float TeplotaCel;
TeplotaCel = ((TeplotaFer - 32) * 5) / 9;
return TeplotaCel;
}
// s oborem platnosti bloku
#include <iostream>
void mojeFunkce();
int main()
{
int x = 5;
std::cout << "\nV main je hodnota x: " << x;
mojeFunkce();
std::cout << "\nZpatky v main, hodnota x je: " << x;
return 0;
}
void mojeFunkce()
{
int x = 8;
std::cout << "\nUvnitr mojeFunkce, lokalni promenna x: " << x << std::endl;
{
std::cout << "\nV bloku funkce mojeFunkce, hodnota x je: " << x;
int x = 9;
std::cout << "\nZcela lokalni promenna x: " << x;
}
std::cout << "\nMimo blok, uvnitr mojeFunkce, x: " << x << std::endl;
}
V main je hodnota x: 5 Uvnitr mojeFunkce , lokalni promenna x: 8 V bloku funkce mojeFunkce, hodnota x je: 8 Zcela lokalni promenna x: 9 Mimo blok, unvitr mojeFunkce, x: 8 Zpatky v main, hodnota x je: 5
#include <iostream>
void mojeFunkce(); // prototyp
int x = 5, y = 7; // globální proměnné
int main()
{
using std::cout;
cout << "x ve funkci main: " << x << "\n";
cout << "y ve funkci main: " << y << "\n\n";
mojeFunkce();
cout << "Navrat z mojeFunkce!\n\n";
cout << "x ve funkci main: " << x << "\n";
cout << "y ve funkci main: " << y << "\n";
return 0;
}
void mojeFunkce()
{
using std::cout;
int y = 10;
cout << "x ve funkci mojeFunkce: " << x << "\n";
cout << "y ve funkci mojeFunkce: " << y << "\n\n";
}
//demonstruje vícenasobný příkaz return
#include <iostream>
int Dvojnasobek(int MnozstviKeZdvojnasobeni);
int main()
{
using std::cout;
int vysledek = 0;
int vstup;
cout << "Vlozte cislo mezi 0 a 10 000 ke zdvojnasobeni: ";
std::cin >> vstup;
cout << "\nPred volanim dvojnasobku... ";
cout << "\nvstup: " << vstup << " vysledek: " << vysledek << "\n";
vysledek = Dvojnasobek(vstup);
cout << "\nPo volani dvojnasobku...\n";
cout << "\nvstup: " << vstup << " vysledek: " << vysledek << "\n";
return 0;
}
int Dvojnasobek(int puvodni)
{
if (puvodni <= 10000)
return puvodni * 2;
else
return -1;
std::cout << "Sem se neni mozne dostat!\n";
}
// používání výchozích hodnot parametrů
#include <iostream>
int ObjemKrychle(int delka, int sirka = 25, int vyska = 1);
int main()
{
int delka = 100;
int sirka = 50;
int vyska = 2;
int objem;
objem = ObjemKrychle(delka, sirka, vyska);
std::cout << "Prvni objem je: " << objem << "\n";
objem = ObjemKrychle(delka, sirka);
std::cout << "Druhy objem je: " << objem << "\n";
objem = ObjemKrychle(delka);
std::cout << "Treti objem je: " << objem << "\n";
return 0;
}
int ObjemKrychle(int delka, int sirka, int vyska)
{
return (delka * sirka * vyska);
}
parametr delka musí být vždy zadán...
Výsledkem programu je:
Prvni objem je: 10000 Druhy objem je: 5000 Treti objem je: 2500
int mojeFunkce(int,int); int mojeFunkce(long);Dvě funkce se stejným názvem a seznamem parametrů, ale různým návratovým typem způsobí chybu při kompilaci! Pokud je různý návratový typ, musí se lišit taky buď název nebo seznam parametrů, aby byl kompilátor schopen rozeznat, kterou funkci má použít.
// demonstruje funkční polymorfismus
#include <iostream>
int Dvojnasobek(int);
long Dvojnasobek(long);
float Dvojnasobek(float);
double Dvojnasobek(double);
using namespace std;
int main()
{
int mujInt = 6500;
long mujLong = 65000;
float mujFloat = 6.5F;
double mujDouble = 6.5e20;
int dvakratInt;
long dvakratLong;
float dvakratFloat;
double dvakratDouble;
cout << "mujInt: " << mujInt << "\n";
cout << "mujLong: " << mujLong << "\n";
cout << "mujFloat: " << mujFloat << "\n";
cout << "mujDouble: " << mujDouble << "\n";
dvakratInt = Dvojnasobek(mujInt);
dvakratLong = Dvojnasobek(mujLong);
dvakratFloat = Dvojnasobek(mujFloat);
dvakratDouble = Dvojnasobek(mujDouble);
cout << "dvakratInt: " << dvakratInt << "\n";
cout << "dvakratLong: " << dvakratLong << "\n";
cout << "dvakratFloat: " << dvakratFloat << "\n";
cout << "dvakratDouble: " << dvakratDouble << "\n";
return 0;
}
int Dvojnasobek(int puvodni)
{
cout << "Ve funkci Dvojnasobek(int)\n";
return 2 * puvodni;
}
long Dvojnasobek(long puvodni)
{
cout << "Ve funkci Dvojnasobek(long)\n";
return 2 * puvodni;
}
float Dvojnasobek(float puvodni)
{
cout << "Ve funkci Dvojnasobek(float)\n";
return 2 * puvodni;
}
double Dvojnasobek(double puvodni)
{
cout << "Ve funkci Dvojnasobek(double)\n";
return 2 * puvodni;
}
// demonstruje inline funkce
#include <iostream>
inline int Dvojnasobek(int);
int main()
{
int cil;
using std::cout;
using std::cin;
using std::endl;
cout << "Vlozte cislo, se kterym se bude pracovat: ";
cin >> cil;
cout << "\n";
cil = Dvojnasobek(cil);
cout << "Cil: " << cil << endl;
cil = Dvojnasobek(cil);
cout << "Cil: " << cil << endl;
cil = Dvojnasobek(cil);
cout << "Cil: " << cil << endl;
return 0;
}
int Dvojnasobek(int cil)
{
return 2*cil;
}
// výpočet mocniny čísla rekurzí
#include <iostream>
using namespace std;
typedef unsigned short int USHORT;
typedef unsigned long int ULONG;
ULONG Umocni(USHORT n, USHORT mocnina);
int main()
{
USHORT cislo,mocnina;
ULONG vysl;
cout << "Zadejte cislo: "; cin >> cislo;
cout << "Na kolikatou?: "; cin >> mocnina;
vysl = Umocni(cislo,mocnina);
cout << cislo << "na" << mocnina <<"-tou je: " << vysl << "/n";
return 0;
}
ULONG Umocni(USHORT n,USHORT mocnina)
{
if (mocnina==1) return n;
else
return (n * Umocni(n,mocnina-1));
}
class Kocka
{
unsigned int jejiVek;
unsigned int jejiVaha;
void Mnau();
};
Deklarací se nevzhrazuje v paměti místo.
Deklarace říká, co to vlastně je kočka - jaké datové typy používá a co umí (funkce).
Kocka Micka; Micka.jejiVek=5;
// Demonstruje deklaraci trídy a definici objektu této trídy
#include <iostream>
class Kocka // deklarace trídy Kocka
{
public: // následující clenové jsou verejní (public)
int jejiVek; // clenská promenná
int jejiVaha; // clenská promenná
}; // všimnete si stredníku
int main()
{
Kocka Micka;
Micka.jejiVek = 5; // prírazení hodnoty do clenské promenné
std::cout << "Micka je kocka, ktere je " ;
std::cout << Micka.jejiVek << " let.\n";
return 0;
}
Pokud by byly datové členy tridy Kocka privátní, tj. bylo by užito
private nebo by nebylo uvedeno nic, pak by nebylo možné napsat pro objekt
Micka:
// Deklarace trídy Kocka
// Clenské promenné jsou privátní, verejné prístupové metody
// zprostredkovávají nastavení a získaní hodnot privatních dat
class Kocka
{
public:
// verejné prístupové metody
unsigned int ZiskejVek();
void NastavVek(unsigned int Vek);
unsigned int ZiskejVahu();
void NastavVahu(unsigned int Vaha);
// verejné clenské funkce
void Mnau();
// privátní clenské promenné
private:
unsigned int jejiVek;
unsigned int jejiVaha;
};
V objektu této třídy je možné přiřadit a zpětně získat hodnotu privátní
proměnné Micka.jejiVek pomocí přístupových funkcí
Micka.NastavVek() a Micka.ZiskejVek(), které jsou PUBLIC.
// Demonstruje deklaraci trídy
// definici metod této trídy
#include <iostream> // kvuli cout
class Kocka // zacátek deklarace trídy
{
public: // zacátek sekce public
int ZiskejVek(); // funkce pro prístup k datum
void NastavVek (int vek); // funkce pro prístup k datum
void Mnau(); // obecná funkce
private: // zacátek sekce private
int jejiVek; // clenská promenná
};
// ZiskejVek, verejná funkce pro prístup k datum
// vrací hodnotu clenské promenné jejiVek
int Kocka::ZiskejVek()
{
return jejiVek;
}
// definice NastavVek, verejné
// funkce pro prístup k datum
// nastavuje clenskou promennou jejiVek
void Kocka::NastavVek(int vek)
{
// nastavení clenské promenné jejiVek na
// hodnotu predanou parametrem vek
jejiVek = vek;
}
// definice metody Mnau
// vrací: void
// parametry: Žádne
// akce: Vytiskne na obrazovku "Mnau"
void Kocka::Mnau()
{
std::cout << "Mnau.\n";
}
// založí objekt kocky, nastaví její vek, nechá ji zamnoukat,
// vytiskne její vek, pak zamnouká znovu.
int main()
{
Kocka Micka;
Micka.NastavVek(5);
Micka.Mnau();
std::cout << "Micka je kocka, ktere je " ;
std::cout << Micka.ZiskejVek() << " let.\n";
Micka.Mnau();
return 0;
}
Mnau. Micka je kocka, ktere je 5 let. Mnau.
// Demonstruje deklaraci konstruktoru a
// destruktoru pro trídu Kocka
// Programatorem vytvorený výchozí konstruktor
#include <iostream> // kvuli cout
class Kocka // zacátek deklarace trídy
{
public: // zacátek sekce public
Kocka(int iniVek); // konstruktor
~Kocka(); // destruktor
int ZiskejVek(); // funkce pro prístup k datum
void NastavVek (int vek); // funkce pro prístup k datum
void Mnau(); // obecná funkce
private: // zacátek sekce private
int jejiVek; // clenská promenná
};
// konstruktor tridy Kocka
Kocka::Kocka(int iniVek)
{
jejiVek = iniVek;
}
Kocka::~Kocka() // destruktor, žádná akce
{
}
// ZiskejVek, verejná funkce pro prístup k datum
// vrací hodnotu clenské promenné jejiVek
int Kocka::ZiskejVek()
{
return jejiVek;
}
// definice NastavVek, verejné
// funkce pro prístup k datum
// nastavuje clenskou promennou jejiVek
void Kocka::NastavVek(int vek)
{
// nastavení clenské promenné jejiVek na
// hodnotu predanou parametrem vek
jejiVek = vek;
}
// definice metody Mnau
// vrací: void
// parametry: Žádné
// akce: Vytiskne na obrazovku "Mnau"
void Kocka::Mnau()
{
std::cout << "Mnau.\n";
}
// založí objekt kocky, nastaví její vek, nechá ji zamnoukat,
// vytiskne její vek, pak zamnouká znovu.
int main()
{
Kocka Micka(5);
Micka.Mnau();
std::cout << "Micka je kocka, ktere je " ;
std::cout << Micka.ZiskejVek() << " let.\n";
Micka.Mnau();
Micka.NastavVek(7);
std::cout << "Micce je nyni " ;
std::cout << Micka.ZiskejVek() << " let.\n";
return 0;
}
Mnau. Micka je kocka, ktere je 5 let. Mnau. Micce je nyni 7 let.Pomocí konstruktoru je po vytvoření objektu nastaven věk na 5 let, proto není nutné volat funkci NastavVek().
void MojeFunkce() const;Takto definované funkce NEZMĚNÍ HODNOTU ŽÁDNÉHO ČLENU Z TŘÍDY
void NastavVek(int Vek); int ZiskejVek() const;Funkce ZiskejVek() má vrátit věk kočky, to jest zjistit číslo, ale nemá ho nijak měnit, proto je deklarována jako konstantní. Kdybychom naopak deklarovali jako konstantní funkci NastavVek(), tak by nám byla k ničemu, protože jakýkoliv pokus o přiřazení do členské proměnné by kompilátor hlásil jako chybu.
00 // Demonstruje chyby kompilátoru
01 // Tento program nelze zkompilovat!
02
03 #include <iostream> // kvuli cout
04
05 class Kocka
06 {
07 public:
08 Kocka(int iniVek);
09 ~Kocka();
10 int ZiskejVek() const; // konstantní funkce pro prístup k datum
11 void NastavVek (int vek);
12 void Mnau();
13 private:
14 int jejiVek;
15 };
16
17 // konstruktor objektu Kocka
18 Kocka::Kocka(int iniVek)
19 {
20 jejiVek = iniVek;
21 std::cout << "Konstruktor Kocka\n";
22 }
23
24 Kocka::~Kocka() // destruktor, žádná akce
25{
26 std::cout << "Destruktor Kocka\n";
27 }
28 // ZiskejVek je konstantní funkce,
29 // ale tato vlastnost je porušená!
30 int Kocka::ZiskejVek() const
31 {
32 return (jejiVek++); // porušuje klauzuli const!
33 }
34
35 // definice NastavVek, verejné
36 // funkce pro prístup k datum
37
38 void Kocka::NastavVek(int vek)
39 {
40 // nastavuje clenskou promennou vek na
41 // hodnotu predanou parametrem vek
42 jejiVek = vek;
43 }
44
45 // definice metody Mnau
46 // vrací: hodnotu void
47 // parametry: Žadné
48 // akce: Vytiskne na obrazovku "Mnau"
49 void Kocka::Mnau()
50 {
51 std::cout << "Mnau.\n";
52 }
53
54 // demonstruje nekolik porušeni rozhraní objektu
55 // a výsledné chyby kompilátoru
56 int main()
57 {
58 Kocka Micka; // neodpovídá deklaraci
59 Micka.Mnau();
60 Micka.Haf(); // Kocky prece neštekají!
61 Micka.jejiVek = 7; // jejiVek je privatní promenná
62 return 0;
63 }
Analýza:
inline int Kocka::ZiskatVahu()
{
return jejiVaha;
}
je definována řádková funkce
class Kocka
{
public:
int ZiskatVahu()
{
return jejiVaha;
}
void NastavVahu(int vaha);
};
Příklad rozdělení programu:
// Ukázka hlavičkového souboru Kocka.hpp
#include <iostream>
class Kocka
{
public:
Kocka (int iniVek);
~Kocka();
int ZiskejVek() const { return jejiVek;} // inline!
void NastavVek (int vek) { jejiVek = vek;} // inline!
void Mnau() const { std::cout << "Mnau.\n";} // inline!
private:
int jejiVek;
};
// Ukázka implementace třídy Kocka ze souboru Kocka.hpp, souboru Kocka.cpp
// Demonstruje inline funkce
// a vložení hlavickového souboru
// vloženi hlavickového souboru!
#include "kocka.hpp"
Kocka::Kocka(int iniVek) //konstruktor
{
jejiVek = iniVek;
}
Kocka::~Kocka() //destruktor, žádná akce
{
}
// založí objekt kocky, nastaví její vek, nechá ji zamnoukat,
// vytiskne její vek, pak zamnouká znovu.
int main()
{
Kocka Micka(5);
Micka.Mnau();
std::cout << "Micka je kocka, ktere je " ;
std::cout << Micka.ZiskejVek() << " let.\n";
Micka.Mnau();
Micka.NastavVek(7);
std::cout << "Micce je nyni " ;
std::cout << Micka.ZiskejVek() << " let.\n";
return 0;
}
// Zacátek Obdélník.hpp
#include <iostream>
class Bod // udržuje souradnice x,y
{
// žádný konstruktor, používá se výchozí
public:
void NastavX(int x) { hodnotaX = x; }
void NastavY(int y) { hodnotaY = y; }
int ZiskejX()const { return hodnotaX;}
int ZiskejY()const { return hodnotaY;}
private:
int hodnotaX;
int hodnotaY;
}; // konec deklarace trídy Bod
class Obdelnik
{
public:
Obdelnik (int horni, int levy, int spodni, int pravy);
~Obdelnik () {}
int ZiskejHorni() const { return hodnotaHorni; }
int ZiskejLevy() const { return hodnotaLevy; }
int ZiskejSpodni() const { return hodnotaSpodni; }
int ZiskejPravy() const { return hodnotaPravy; }
Bod ZiskejHorniLevy() const { return hodnotaHorniLevy; }
Bod ZiskejSpodniLevy() const { return hodnotaSpodniLevy; }
Bod ZiskejHorniPravy() const { return hodnotaHorniPravy; }
Bod ZiskejSpodniPravy() const { return hodnotaSpodniPravy; }
void NastavHorniLevy(Bod Umisteni) {hodnotaHorniLevy = Umisteni;}
void NastavSpodniLevy(Bod Umisteni) {hodnotaSpodniLevy = Umisteni;}
void NastavHorniPravy(Bod Umisteni) {hodnotaHorniPravy = Umisteni;}
void NastavSpodniPravy(Bod Umisteni) {hodnotaSpodniPravy = Umisteni;}
void NastavHorni(int horni) { hodnotaHorni = horni; }
void NastavLevy (int levy) { hodnotaLevy = levy; }
void NastavSpodni (int spodni) { hodnotaSpodni = spodni; }
void NastavPravy (int pravy) { hodnotaPravy = pravy; }
int ZiskejPlochu() const;
private:
Bod hodnotaHorniLevy;
Bod hodnotaHorniPravy;
Bod hodnotaSpodniLevy;
Bod hodnotaSpodniPravy;
int hodnotaHorni;
int hodnotaLevy;
int hodnotaSpodni;
int hodnotaPravy;
};
// konec Obdelnik.hpp
Zde je možná implementace třídy
// Zacátek Obdelnik.cpp
#include "obdelnik.hpp"
Obdelnik::Obdelnik(int horni, int levy, int spodni, int pravy)
{
hodnotaHorni = horni;
hodnotaLevy = levy;
hodnotaSpodni = spodni;
hodnotaPravy = pravy;
hodnotaHorniLevy.NastavX(levy);
hodnotaHorniLevy.NastavY(horni);
hodnotaHorniPravy.NastavX(pravy);
hodnotaHorniPravy.NastavY(horni);
hodnotaSpodniLevy.NastavX(levy);
hodnotaSpodniLevy.NastavY(spodni);
hodnotaSpodniPravy.NastavX(pravy);
hodnotaSpodniPravy.NastavY(spodni);
}
// spocítá plochu obdélníku tak, ze získa šírku a výšku jako
// rozdíly v souradnicích rohových bodu a pak je vynásobí
int Obdelnik::ZiskejPlochu() const
{
int Sirka = hodnotaPravy-hodnotaLevy;
int Vyska = hodnotaHorni - hodnotaSpodni;
return (Sirka * Vyska);
}
int main()
{
//inicializace lokální promenné Obdelnik
Obdelnik MujObdelnik (100, 20, 50, 80 );
int Plocha = MujObdelnik.ZiskejPlochu();
std::cout << "Plocha: " << Plocha << "\n";
std::cout << "X-ova souradnice horniho leveho bodu: ";
std::cout << MujObdelnik.ZiskejHorniLevy().ZiskejX();
return 0;
}
while (podmínka) příkaz;Příklad:
// Smyčka s while
#include <iostream>
int main()
{
int citac = 0; // inicializace podmínky
while(citac < 5) // test, zda je podmínka stále pravSPANá
{
citac++; // tělo smyčky
std::cout << "citac: " << citac << "\n";
}
std::cout << "Hotovo, citac: " << citac << ".\n";
return 0;
}
Podmínku lze vytvořit pomocí logických operátorů.
// Složitější výraz v podmínce smyčky while
#include <iostream>
using namespace std;
int main()
{
unsigned short male;
unsigned long velke;
const unsigned short MAXMALE=65535;
cout << "Vlozte male cislo: ";
cin >> male;
cout << "Vlozte velke cislo: ";
cin >> velke;
cout << "male: " << male << "...";
// při každé iteraci testujeme tři podmínky
while (male < velke && velke > 0 && male < MAXMALE)
{
if (male % 5000 == 0) // zapsání tečky za každých 5000 řádek
cout << ".";
male++;
velke-=2;
}
cout << "\nMale: " << male << " Velke: " << velke << endl;
return 0;
}
while (podmínka)
{
if (podmínka2)
break;
//příkazy;
}
Příklad:
// Demonstruje příkazy break a continue
#include <iostream>
int main()
{
using namespace std;
unsigned short male;
unsigned long velke;
unsigned long preskoc;
unsigned long cil;
const unsigned short MAXMALE=65535;
cout << "Vlozte male cislo: ";
cin >> male;
cout << "Vlozte velke cislo: ";
cin >> velke;
cout << "Vlozte cislo pro preskoceni: ";
cin >> preskoc;
cout << "Vlozte cilove cislo: ";
cin >> cil;
cout << "\n";
// nastavení tří podmínek pro ukončení smyčky
while (male < velke && velke > 0 && male < MAXMALE)
{
male++;
if (male % preskoc == 0) // přeskočit odečítání?
{
cout << "preskoceni na cisle " << male << endl;
continue;
}
if (velke == cil) // dosažení přesné cílové hodnoty?
{
cout << "Cíl dosažen!";
break;
}
velke-=2;
} // konec smyčky while
cout << "\nMale: " << male << " Velke: " << velke << endl;
return 0;
}
Tyto dva příkazy by se měli používat s rozvahou, protože způsobují nepřehlednost
kódu.
do příkaz; while (podmínka);Funguje podobně jako smyčka while, ale podmínka se testuje na konci cyklu. Posloupnost příkazů tedy proběhne alespon jednou.
// Demonstruje smyčku do while
#include <iostream>
int main()
{
using namespace std;
int citac;
cout << "Kolik pozdravu? ";
cin >> citac;
do
{
cout << "Ahoj\n";
citac--;
} while (citac > 0);
cout << "Hodnota citace: " << citac << endl;
return 0;
}
for (inicializace;test;akce) příkaz;Inicializace slouží k inicializaci stavu čítače, podmínka se prověřuje při každém průchodu smyčkou, akce - obvykle zvýšení stavu čítače
// Smyčka for
#include <iostream>
int main()
{
int citac;
for (citac = 0; citac < 5; citac++)
std::cout << "Smycka! ";
std::cout << "\nCitac: " << citac << ".\n";
return 0;
}
Vícenásobná inicializace a zvýšení hodnoty
// Demonstruje vícenásobný výraz
// ve smyčce for
#include <iostream>
int main()
{
for (int i=0, j=0; i<3; i++, j++)
std::cout << "i: " << i << " j: " << j << std::endl;
return 0;
}
Prázdné příkazy ve smyčce for
// Smyčka for s prázdnými výrazy
#include <iostream>
int main()
{
int citac = 0;
for( ; citac < 5; )
{
citac++;
std::cout << "Smycka! ";
}
std::cout << "\nCitac: " << citac << ".\n";
return 0;
}
Příklad: Prázdný příkaz for
// Ilustrace prázdného výrazu for
#include <iostream>
int main()
{
int citac=0; // inicializace
int max;
std::cout << "Kolik pozdravu?";
std::cin >> max;
for (;;) // nekonečná smyčka for
{
if (citac < max) // test
{
std::cout << "Ahoj!\n";
citac++; // inkrementace
}
else
break;
}
return 0;
}
Pokud za hlavičku smyčky vložíme středník, nemá žádné tělo. Bere se jako
prázdný příkaz. Budou se tedy vykonávat jenom příkazy v hlavičce.
// Demonstruje prázdný výraz
// v těle smyčky for
#include <iostream>
int main()
{
for (int i = 0; i<5; std::cout << "i: " << i++ << std::endl)
;
return 0;
}
Smyčky lze do sebe vnářet!
// Ilustruje vnořené smyčky for
#include <iostream>
int main()
{
using namespace std;
int radky, sloupce;
char znak;
cout << "Kolik radku? ";
cin >> radky;
cout << "Kolik sloupcu? ";
cin >> sloupce;
cout << "Jaky znak? ";
cin >> znak;
for (int i = 0; i < radky; i++)
{
for (int j = 0; j<sloupce; j++)
cout << znak;
cout << "\n";
}
return 0;
}
// Demonstruje spočítání n-tého
// Fibonacciho čísla s pomocí iterace
#include <iostream>
int fib(int pozice);
int main()
{
using namespace std;
int odpoved, pozice;
cout << "Jaka pozice? ";
cin >> pozice;
cout << "\n";
odpoved = fib(pozice);
cout << pozice << ". Fibonacciho cislo je ";
cout << odpoved << ".\n";
return 0;
}
int fib(int n)
{
int minusDva=1, minusJeden=1, odpoved=2;
if (n < 3)
return 1;
for (n -= 3; n; n--)
{
minusDva = minusJeden;
minusJeden = odpoved;
odpoved = minusJeden + minusDva;
}
return odpoved;
}
switch (věraz)
{
case hodnota1: příkaz;
case hodnota2: příkaz;
...
case hodnotaN: příkaz;
default: příkaz;
}
Jestliže se se shoduje hodnota s hodnotou výrazu je proveden daný příkaz.
Za příkazem je nutné uvést příkaz break! Pokud se tento příkaz neuvede, pokračuje
provádění příkazů i pro jiné hodnoty! Pokud je záměrně break vypuštěn, mělo by se
to objevit v komentáři, že se nejedná o omyl.
switch (věraz)
{
case hodnota1: příkaz;
break;
case hodnota2: příkaz;
break;
...
}
Pokud nesedí ani jedna hodnota, je proveden příkaz za default - pokud je uveden.
// Ukázka příkazu switch
#include <iostream>
int main()
{
using namespace std;
unsigned short int cislo;
cout << "Vlozte cislo mezi 1 a 5: ";
cin >> cislo;
switch (cislo)
{
case 0: cout << "Prilis male!";
break;
case 5: cout << "Dobra prace!\n"; // spada do rozmezi
case 4: cout << "Hezka volba!\n"; // spada do rozmezi
case 3: cout << "Vynikajici!\n"; // spada do rozmezi
case 2: cout << "Skvele!\n"; // spada do rozmezi
case 1: cout << "Neuveritelne!\n";
break;
default: cout << "Prilis velke!\n";
break;
}
cout << "\n\n";
return 0;
}
#define EVER ;;
for (EVER)
{
příkazy;
}
FOREVER - navždy
// Použití nekonečné smyčky for
// pro řízení interakce s uživatelem
#include <iostream>
// prototypy
int nabidka();
void ProvedUkolJedna();
void ProvedUkoly(int);
using namespace std;
int main()
{
bool konec = false;
for (;;)
{
int volba = nabidka();
switch(volba)
{
case (1):
ProvedUkolJedna();
break;
case (2):
ProvedUkoly(2);
break;
case (3):
ProvedUkoly(3);
break;
case (4):
continue; // nadbytečné!
break;
case (5):
konec=true;
break;
default:
cout << "Prosim vyberte znovu!\n";
break;
} // konec příkazu switch
if (konec)
break;
} // ukončení smyčky for
return 0;
} // konec funkce main()
int nabidka()
{
int volba;
cout << " **** Nabidka ****\n\n";
cout << "(1) Volba jedna.\n";
cout << "(2) Volba dva.\n";
cout << "(3) Volba tri.\n";
cout << "(4) Znovuzobrazeni nabidky.\n";
cout << "(5) Konec.\n\n";
cout << ": ";
cin >> volba;
return volba;
}
void ProvedUkolJedna()
{
cout << "Ukol jedna!\n";
}
void ProvedUkoly(int ktery)
{
if (ktery == 2)
cout << "Ukol dva!\n";
else
cout << "Ukol tri!\n";
}
#include <iostream>
using namespace std;
enum VOLBA { KresliObd = 1, SpoctiObsah, SpoctiObvod,
ZmenRozmery, Konec };
// Deklarace třídy Obdélník
class Obdelnik
{
public:
// konstruktory
Obdelnik(int sirka, int vyska);
~Obdelnik();
// přístupové funkce
int ZiskejVysku() const { return vyskaObd; }
int ZiskejSirku() const { return sirkaObd; }
int SpoctiObsah() const { return vyskaObd * sirkaObd; }
int SpoctiObvod() const { return 2*vyskaObd + 2*sirkaObd; }
void NastavVelikost(int novaSirka, int novaVyska);
// Různé metody
private:
int sirkaObd;
int vyskaObd;
};
// Implementace metod třídy
void Obdelnik::NastavVelikost(int novaSirka, int novaVyska)
{
sirkaObd = novaSirka;
vyskaObd = novaVyska;
}
Obdelnik::Obdelnik(int sirka, int vyska)
{
sirkaObd = sirka;
vyskaObd = vyska;
}
Obdelnik::~Obdelnik() {}
int Nabidka();
void KresbaObd(Obdelnik);
void VypocetObsahu(Obdelnik);
void VypocetObvodu(Obdelnik);
int main ()
{
// inicializace obdélníka na 30, 5
Obdelnik obd(30,5);
int volba = KresliObd;
int fKonec = false;
while (!fKonec)
{
volba = Nabidka();
if (volba < KresliObd || volba > Konec)
{
cout << "\nNeplatna volba, zkuste prosim znovu.\n\n";
continue;
}
switch (volba)
{
case KresliObd:
KresbaObd(obd);
break;
case SpoctiObsah:
VypocetObsahu(obd);
break;
case SpoctiObvod:
VypocetObvodu(obd);
break;
case ZmenRozmery:
int novaDelka, novaSirka;
cout << "\nNova sirka: ";
cin >> novaSirka;
cout << "Nova vyska: ";
cin >> novaDelka;
obd.NastavVelikost(novaSirka, novaDelka);
KresbaObd(obd);
break;
case Konec:
fKonec = true;
cout << "\nUkonceni programu...\n\n";
break;
default:
cout << "Chybna volba!\n";
fKonec = true;
break;
} // konec switch
} // konec while
return 0;
} // konec main
int Nabidka()
{
int volba;
cout << "\n\n *** Nabidka *** \n";
cout << "(1) Kresba Obdelnika\n";
cout << "(2) Obsah\n";
cout << "(3) Obvod\n";
cout << "(4) Zmena rozmeru\n";
cout << "(5) Konec\n";
cin >> volba;
return volba;
}
void KresbaObd(Obdelnik obd)
{
int vyska = obd.ZiskejVysku();
int sirka = obd.ZiskejSirku();
for (int i = 0; i<vyska; i++)
{
for (int j = 0; j<sirka; j++)
cout << "*";
cout << "\n";
}
}
void VypocetObsahu(Obdelnik obd)
{
cout << "Obsah: " << obd.SpoctiObsah() << endl;
}
void VypocetObvodu(Obdelnik obd)
{
cout << "Obvod: " << obd.SpoctiObvod() << endl;
}
// Demonstruje operátor adresy a adresy lokálních proměnných
#include <iostream>
int main()
{
using namespace std;
unsigned short promennaShort=5;
unsigned long promennaLong=65535;
long zPromenna = -65535;
cout << "promenna typu Short:\t" << promennaShort;
cout << "\tAdresa promenne typu Short:\t";
cout << &promennaShort << "\n";
cout << "promenna typu Long:\t" << promennaLong;
cout << "\tAdresa promenne typu Long:\t";
cout << &promennaLong << "\n";
cout << "promenna se znamenkem:\t" << zPromenna;
cout << "\tAdresa promenne se znamenkem:\t";
cout << &zPromenna << "\n";
return 0;
}
Kde k výpisu adresy proměnné použijeme & a název proměnné, tedy například:
&promennaShortunsigned short int tvujVek,jakStary = 50; unsigned short int *ukVek = &jakStary; tvujVek=*ukVek;Proměnné‚ tvujVek byla přiřazena hodnota proměnné jakStary, pomocí ukazatele ukVek. Tj. nepřímým přístupem. Ukazatel ukVek ukazuje na adresu proměnné‚ jakStary a pomocí operátoru * umí získat hodnotu uloženou na této adrese.
unsigned short int * tvujVek = 0;PŘI RUŠENÍ ODKAZU UKAZATELE INDIKUJE OPERÁTOR NEPŘÍMÉHO PŘÍSTUPU, ŽE JDE O PŘÍSTUP K HODNOTĚ NA PAMĚŤOVÉM MÍSTĚ ULOŽENÉHO V TOMTO UKAZATELI A NIKOLI O ADRESU SAMOTNOU:
*ukVek = 5
// Používání ukazatelů
#include <iostream>
typedef unsigned short int USHORT;
int main()
{
using std::cout;
USHORT mujVek; // proměnná
USHORT *ukVek; // ukazatel
mujVek = 5;
cout << "mujVek: " << mujVek << "\n";
ukVek = &mujVek; // přiřazení adresy proměnné mujVek do ukVek
cout << "*ukVek: " << *ukVek << "\n\n";
cout << "Nastaveni *ukVek na 7...\n";
*ukVek = 7; // nastavení mujVek na 7
cout << "*ukVek: " << *ukVek << "\n";
cout << "mujVek: " << mujVek << "\n\n";
cout << "Nastaveni mujVek na 9...\n";
mujVek = 9;
cout << "mujVek: " << mujVek << "\n";
cout << "*ukVek: " << *ukVek << "\n";
return 0;
}
mujVek: 5 *ukVek: 5 Nastavení *ukVek na 7... *ukVek: 7 mujVek: 7 Nastaven mujVek na 9... mujVek: 9 *ukVek: 9Příklad: Hodnoty ukazatelů
// Hodnoty ukazatelů
#include <iostream>
int main()
{
using std::cout;
unsigned short int mujVek = 5, tvujVek = 10;
// ukazatel
unsigned short int * ukVek = &mujVek;
cout << "mujVek:\t\t" << mujVek
<< "\t\ttvujVek:\t" << tvujVek << "\n";
cout << "&mujVek:\t" << &mujVek
<< "\t&tvujVek:\t" << &tvujVek << "\n";
cout << "ukVek:\t\t" << ukVek << "\n";
cout << "*ukVek:\t\t" << *ukVek << "\n";
cout << "\nPrenastaveni ukVek = &tvujVek...\n\n";
ukVek = &tvujVek; // přenastavení ukazatele
cout << "mujVek:\t\t" << mujVek
<< "\t\ttvujVek:\t" << tvujVek << "\n";
cout << "&mujVek:\t" << &mujVek
<< "\t&tvujVek:\t" << &tvujVek << "\n";
cout << "ukVek:\t\t" << ukVek << "\n";
cout << "*ukVek:\t\t" << *ukVek << "\n";
cout << "\n&ukVek:\t\t" << &ukVek << "\n";
return 0;
}
Příklad možného výstupu (adresy se mohou lišit):
mujVek: 5 tvujVek: 10 &mukVek: 0012FF7C &tvujVek: 0012FF78 ukVek: 0012FF7C *ukVek: 5 Prenastaveni ukVek = &tvujVek... mujvek: 5 tvujVek: 10 &mujVek: 0012FF7C &tvujVek: 0012FF78 ukVek: 0012FF78 *ukVek: 10 &ukVek: 0012FF74
|
Používání ukazatelů Ukazatel se deklaruje zápisem typu proměnné nebo objektu, jehož adresa se má do ukazatele uložit. Za typem nýsleduje operátor ukazatele (*) a název ukazatele. Příklad: unsigned short int * ukUkazatel = 0;Pro přiřazení neboli inicializaci ukazeatele uveďte název proměnné, jejíž adresa se přiřazuje, s předřazeným operátorem adresy (&). Například: unsigned short int Promenna = 5; unsigned short int * ukUkazatel = &Promenna;Při zrušení odkazu ukazatele se název ukazatele předřadí operátorem dereference (*). Např.: unsigned short int hodnota = *ukUkazatel; |
new unsigned short int; //vyhradˇ se 2B pamŘti new unsigned long int; //vyhradˇ se 4B pamŘtiNávratová hodnota operátoru new je PAMĚŤOVÁ ADRESA, kterou je nutné přiřadit ukazateli!!!
unsigned short int * ukUkazatel; ukUkazatel = new unsigned short int;nebo třeba přímo:
unsigned short int * ukUkazatel = new unsigned short int;Ukazatel ukUkazatel se bude odkazovat ne objekt typu unsigned short int ve volné oblasti paměti. Ukazatel se používá stejně jako každý jiný ukazatel (viz. výše).
*ukUkazatel = 150;"Vlož 150 do odkazu ukazatel".
delete ukUkazatel;vrátí vyhrazenou pamět (2B pro unsigned short) zpět do volné oblasti paměti.
Zvire *ukPes=new Zvire;
delete ukPes; //uvolnění paměti
ukPes=0; //nastav ukazatel na nulu
delete ukPes; //neškodné‚
unsigned short int * ukUkazatel=new unsigned short int; *ukUkazatel = 72; ukUkazatel=new unsigned short int; *ukUkazatel=84;Pokud nyní zavoláme delete ukUkazatel; uvolní se pamět na adrese, kam byla vložena hodnota 84. Ale paměť na adrese, kde je vložena hodnota 72 už uvolnit nejde, protože se na ni nemáme jak dostat!!!
// Alokace a smazání ukazatele
#include <iostream>
int main()
{
using std::cout;
int lokalniPromenna = 5;
int * ukLokalni = &lokalniPromenna;
int * ukHromada = new int;
*ukHromada = 7;
cout << "lokalniPromenna: " << lokalniPromenna << "\n";
cout << "*ukLokalni: " << *ukLokalni << "\n";
cout << "*ukHromada: " << *ukHromada << "\n";
delete ukHromada;
ukHromada = new int;
*ukHromada = 9;
cout << "*ukHromada: " << *ukHromada << "\n";
delete ukHromada;
return 0;
}
lokalniPromenna: 5 *ukLokalni: 5 *ukHromada: 7 *ukHromada: 9
Kocka *ukKocka = new Kocka;Dojde k zavolání výchozího konstuktoru (bez parametrů). Tento konstruktor je volán vždy při vytvoření objektu (v zásobníku nebo volném úložišti).
// Vytváření objektů ve volné oblasti paměti
// prostřednictvím příkazů new a delete
#include <iostream>
class ProstaKocka
{
public:
ProstaKocka();
~ProstaKocka();
private:
int vekKocky;
};
ProstaKocka::ProstaKocka()
{
std::cout << "Zavolan konstruktor.\n";
vekKocky = 1;
}
ProstaKocka::~ProstaKocka()
{
std::cout << "Zavolan destruktor.\n";
}
int main()
{
std::cout << "ProstaKocka Micka...\n";
ProstaKocka Micka;
std::cout << "ProstaKocka * ukMourek = new ProstaKocka...\n";
ProstaKocka * ukMourek = new ProstaKocka;
std::cout << "delete ukMourek...\n";
delete ukMourek;
std::cout << "Konec programu, vsimnete si destrukce Micky...\n";
return 0;
}
ProstaKocka Micka... Zavolan konstruktor. ProstaKocka * ukMourek=new ProstaKocka... Zavolan konstruktor. delete ukMourek... Zavolan destruktor. Konec programu, vsimnete si destrukce Micky... Zavolan destruktor.
(*ukMourek).ZiskejVek();Závorky se používají proto, aby bylo zřejmé, že nejprve má dojít ke zrušení odkazu ukazatele ukMourek a potom se má zpřístupnit funkce ZiskejVek().
// Přístup k datovým členům objektů na hromadě
// prostřednictvím operátoru ->
#include <iostream>
class ProstaKocka
{
public:
ProstaKocka() { vekKocky = 2; }
~ProstaKocka() {}
int ZiskejVek() const { return vekKocky; }
void NastavVek(int vek) { vekKocky = vek; }
private:
int vekKocky;
};
int main()
{
ProstaKocka * Micka = new ProstaKocka;
std::cout << "Micka ma " << Micka->ZiskejVek() << " roku\n";
Micka->NastavVek(5);
std::cout << "Micka ma " << Micka->ZiskejVek() << " roku\n";
delete Micka;
return 0;
}
Micka ma 2 roku. Micka ma 5 roku.
// Ukazatele jako datoví členové,
// ke kterým se přistupuje operátorem >
#include <iostream>
class ProstaKocka
{
public:
ProstaKocka();
~ProstaKocka();
int ZiskejVek() const { return *vekKocky; }
void NastavVek(int vek) { *vekKocky = vek; }
int ZiskejVahu() const { return *vahaKocky; }
void NastavVahu(int vaha) { *vahaKocky = vaha; }
private:
int * vekKocky;
int * vahaKocky;
};
ProstaKocka::ProstaKocka()
{
vekKocky = new int(2);
vahaKocky = new int(5);
}
ProstaKocka::~ProstaKocka()
{
delete vekKocky;
delete vahaKocky;
}
int main()
{
ProstaKocka * Micka = new ProstaKocka;
std::cout << "Micka ma " << Micka->ZiskejVek() << " roku\n";
Micka->NastavVek(5);
std::cout << "Micka ma " << Micka->ZiskejVek() << " roku\n";
delete Micka;
return 0;
}
Micka ma 2 roku. Micka ma 5 roku.Členské proměnné třídy se deklarují jako ukazatele na celočíselný typ (int * vekKocky; int vahaKocky;).
// Používání speciálního ukazatele "this"
#include <iostream.h>
class Obdelnik
{
public:
Obdelnik();
~Obdelnik();
void NastavDelku(int delka)
{ this->delkaObd = delka; }
int ZiskejDelku() const
{ return this->delkaObd; }
void NastavSirku(int sirka)
{ sirkaObd = sirka; }
int ZiskejSirku() const
{ return sirkaObd; }
private:
int delkaObd;
int sirkaObd;
};
Obdelnik::Obdelnik()
{
sirkaObd = 5;
delkaObd = 10;
}
Obdelnik::~Obdelnik()
{}
int main()
{
Obdelnik obd;
cout <<"obd je " << obd.ZiskejDelku()
<<" centimetru dlouhy.\n";
cout <<"obd je " << obd.ZiskejSirku()
<<" centimetru siroky.\n";
obd.NastavDelku(20);
obd.NastavSirku(10);
cout <<"obd je " << obd.ZiskejDelku()
<<" centimetru dlouhy.\n";
cout <<"obd je " << obd.ZiskejSirku()
<<" centimetru siroky.\n";
return 0;
}
Mezi chováním funkcí pro délku a šířku není rozdíl - i bez
ukazatele this, fungují stejně.
|
Rozdíl mezi nulovým a zbloudilým ukazatelem
Když se vymaže ukazatel, kompilátor uvolní paměť, ale ukazatel samotný i nadále existuje. Stane se z něj zbloudilý ukazatel. Když se pak napíše mujUkazatel=0;, stane se ze zbloudilého ukazatele nulový ukazatel. Za normálních okolností platí, že pokud se vymaže ukazatel a poté se vymaže znovu už jako zbloudilý ukazatel, bude chování programu nedefinované. To znamená, že se může stát ledacos; při troše štěstí může dojít ke zhroucení programu. Jestliže se vymaže nulový ukazatel, nestane se nic, což je bezpečnější. Používání zbloudilého nebo nulového ukazatele NENÍ DOVOLENO! (*mujUkazatel=5;)a může vést ke zhroucení programu. Je-li však ukazatel nulový, program se zhroutí určítě, což je další výhoda proti zbloudilému ukazateli. Dává se přednost předvídanému zhroucení programu, protože se snáz ladí chyby. |
const int * uk1; int * const uk2; const int * const uk3;
// Používání ukazatelů spolu s konstantními metodami
#include <iostream>
using namespace std;
class Obdelnik
{
public:
Obdelnik();
~Obdelnik();
void NastavDelku(int delka) { delkaObd = delka; }
int ZiskejDelku() const { return delkaObd; }
void NastavSirku(int sirka) { sirkaObd = sirka; }
int ZiskejSirku() const { return sirkaObd; }
private:
int delkaObd;
int sirkaObd;
};
Obdelnik::Obdelnik()
{
sirkaObd = 5;
delkaObd = 10;
}
Obdelnik::~Obdelnik()
{}
int main()
{
Obdelnik * ukObd = new Obdelnik;
const Obdelnik * ukKonstObd = new Obdelnik;
Obdelnik * const ukKonstUkaz = new Obdelnik;
cout <<"ukObd sirka: " << ukObd->ZiskejSirku()
<<" centimetru\n";
cout <<"ukKonstObd sirka: " << ukKonstObd->ZiskejSirku()
<<" centimetru\n";
cout <<"ukKonstUkaz sirka: " << ukKonstUkaz->ZiskejSirku()
<<" centimetru\n";
ukObd->NastavSirku(10);
// ukKonstObd->NastavSirku(10);
ukKonstUkaz->NastavSirku(10);
cout <<"ukObd sirka: " << ukObd->ZiskejSirku()
<<" centimetru\n";
cout <<"ukKonstObd sirka: " << ukKonstObd->ZiskejSirku()
<<" centimetru\n";
cout <<"ukKonstUkaz sirka: " << ukKonstUkaz->ZiskejSirku()
<<" centimetru\n";
return 0;
}
ukObd sirka: 5 centimetru ukKonstObd sirka: 5 centimetru ukKonstUkaz sirka: 5 centimetru ukObd sirka: 10 centimetru ukKonstObd: 5 centimetru ukKonstUkaz sirka: 10 centimetru
#include <iostream>
#include <ctype.h>
#include <string.h>
bool ZiskejSlovo(char * retezec,
char * slovo, int& posunSlovo);
// řídicí program
int main()
{
const int velPamet = 255;
char pamet[velPamet+1]; // paměť pro uchování celého řetězce
char slovo[velPamet+1]; // paměť pro uchování slova
int posunSlovo = 0; // začínáme na začátku
std::cout <<"Vlozte retezec: ";
std::cin.getline(pamet,velPamet);
while (ZiskejSlovo(pamet,slovo,posunSlovo))
{
std::cout <<"Ziskano slovo: " << slovo << std::endl;
}
return 0;
}
// funkce pro rozklad řetězce a získání slova
bool ZiskejSlovo(char* retezec, char* slovo, int& posunSlovo)
{
if (!retezec[posunSlovo]) // konec řetězce?
return false;
char *p1, *p2;
p1 = p2 = retezec+posunSlovo; // ukaž na následující slovo
// pohlcení počátečních mezer
for (int i = 0; i<(int)strlen(p1) && !isalnum(p1[0]); i++)
p1++;
// podívejme se, jestli máme slovo
if (!isalnum(p1[0]))
return false;
// p1 nyní ukazuje na začátek následujícího slova
// nechme p2 ukazovat na stejné místo
p2 = p1;
// přejděme s p2 na konec slova
while (isalnum(p2[0]))
p2++;
// p2 nyní ukazuje na konec slova
// p1 nyní ukazuje na začátek slova
// délka slova je jejich rozdíl
int delka = int (p2 - p1);
// zkopírování slova do připravené paměti
strncpy (slovo,p1,delka);
// ukončíme řetězec nulou
slovo[delka]='\0';
// nyní najdeme začátek následujícího slova
for (int j = int(p2-retezec); j<(int)strlen(retezec)
&& !isalnum(p2[0]); j++)
{
p2++;
}
posunSlovo = int(p2-retezec);
return true;
}
Vlozte retezec: zprava o jazyce C++ Ziskano slovo: zprava Ziskano slovo: o Ziskano slovo: jazyce Ziskano slovo: CŘádek 32: if (!retezec[posunSlovo]) využívá vlastnosti C++, kde se hodnota 0 považuje za false. Tento řádek by se dal nahradit následovně: if (retezec[posunSlovo]==0)
int &odNejakýOdkaz = nejakaPromenna;Kde odkaz odNejakyOdkaz je odkazem na celočíselnou promměnnou nejakaPromenna a lze jej kdykoliv použít místo samotné proměnné.
int &odNejakýOdkaz = nejakaPromenna;je totožné s
int & odNejakýOdkaz = nejakaPromenna;a také s
int& odNejakyOdkaz=nejakaPromenna;
KOCKA& odOdkaz1,odOdkaz2Znamená to, že odOdkaz1 je odkaz na objekt KOCKA, ale odOdkaz2 je pouze objekt typu KOCKA.
// Ukázka používání odkazů
#include <iostream>
int main()
{
using namespace std;
int prvniProm;
int &odkaz = prvniProm;
prvniProm = 5;
cout << "prvniProm: " << prvniProm << endl;
cout << "odkaz: " << odkaz << endl;
odkaz = 7;
cout << "prvniProm: " << prvniProm << endl;
cout << "odkaz: " << odkaz << endl;
return 0;
}
prvniProm: 5 odkaz: 5 PrvniProm: 7 odkaz: 7
#include <iostream>
int main()
{
using namespace std;
int prvniProm;
int &odkaz = prvniProm;
prvniProm = 5;
cout << "prvniProm: " << prvniProm << endl;
cout << "odkaz: " << odkaz << endl;
cout << "&prvniProm: " << &prvniProm << endl;
cout << "&odkaz: " << &odkaz << endl;
return 0;
}
prvniProm: 5 odkaz: 5 &prvniProm: 0012FF7C &odkaz: 0012FF7C
// Přiřazení nové hodnoty odkazu
#include <iostream>
int main()
{
using namespace std;
int prvniProm;
int &odkaz = prvniProm;
prvniProm = 5;
cout << "prvniProm:\t " << prvniProm << endl;
cout << "odkaz:\t\t " << odkaz << endl;
cout << "&prvniProm:\t " << &prvniProm << endl;
cout << "&odkaz:\t\t " << &odkaz << endl;
int druhaProm = 8;
odkaz = druhaProm; // Co myslíte, že se stane?
cout << "\nprvniProm:\t " << prvniProm << endl;
cout << "druhaProm:\t " << druhaProm << endl;
cout << "odkaz:\t\t " << odkaz << endl;
cout << "&prvniProm:\t " << &prvniProm << endl;
cout << "&druhaProm:\t " << &druhaProm << endl;
cout << "&odkaz:\t\t " << &odkaz << endl;
return 0;
}
prvniProm: 5 odkaz: 5 &prvniProm: 0012FF7C &odkaz: 0012FF7C prvniProm: 8 druhaProm: 8 odkaz: 8 &prvniProm: 0012FF7C &druhaProm: 0012FF74 &odkaz: 0012FF7CODKAZOVAT SE LZE NA LIBOVOLNÝ OBJEKT! I UŽIVATELEM VYTVOŘENÝ. NELZE SE VŠAK ODKAZOVAT NA TYP!!!
// Odkazy na objekty tříd
#include <iostream>
class ProstaKocka
{
public:
ProstaKocka (int vek, int vaha);
~ProstaKocka() {}
int ZiskejVek() { return vekKocky; }
int ZiskejVahu() { return vahaKocky; }
private:
int vekKocky;
int vahaKocky;
};
ProstaKocka::ProstaKocka(int vek, int vaha)
{
vekKocky = vek;
vahaKocky = vaha;
}
int main()
{
ProstaKocka Micka(5,8);
ProstaKocka & odKocka = Micka;
std::cout << "Micka ma ";
std::cout << Micka.ZiskejVek() << " roku. \n";
std::cout << "A Micka vazi ";
std::cout << odKocka.ZiskejVahu() << " kilogramu. \n";
return 0;
}
Micka ma 5 roku. A Micka vazi 8 kilogramu.
//demonstruje předání hodnotou
#include <iostream>
void zamena(int x, int y);
int main()
{
int x = 5, y = 10;
std::cout << "Funkce main. Pred zamenou, x: " << x << " y: " << y << "\n";
zamena(x,y);
std::cout << "Funkce main. Po zamene, x: " << x << " y: " << y << "\n";
return 0;
}
void zamena (int x, int y)
{
int pom;
std::cout << "Funkce zamena. Pred zamenou, x: " << x << " y: " << y << "\n";
pom = x;
x = y;
y = pom;
std::cout << "Funkce zamena. Po zamene, x: " << x << " y: " << y << "\n";
}
Uvnitř funkce nedošlo ke změně, protože jde o předání hodnotou.
Pro správnou funkčnost musíme předávat hodtnoty odkazem, například pomocí ukazatelů:
//Demonstruje předání odkazem
#include <iostream>
void zamena(int *x, int *y);
int main()
{
int x = 5, y = 10;
std::cout << "Funkce main. Pred zamenou, x: " << x << " y: " << y << "\n";
zamena(&x,&y);
std::cout << "Funkce main. Po zamene, x: " << x << " y: " << y << "\n";
return 0;
}
void zamena (int *ox, int *oy)
{
int pom;
std::cout << "Funkce zamena. Pred zamenou, *ox: " << *ox <<
" *oy: " << *oy << "\n";
pom = *ox;
*ox = *oy;
*oy = pom;
std::cout << "Funkce zamena. Po zamene, *ox: " << *ox <<
" *oy: " << *oy << "\n";
}
a nebo pomocí odkazů:
// demonstruje předání odkazem s pomocí odkazu!
#include <iostream>
void zamena(int &x, int &y);
int main()
{
int x = 5, y = 10;
std::cout << "Funkce main. Pred zamenou, x: " << x <<
" y: " << y << "\n";
zamena(x,y);
std::cout << "Funkce main. Po zamene, x: " << x <<
" y: " << y << "\n";
return 0;
}
void zamena (int &ox, int &oy)
{
int pom;
std::cout << "Funkce zamena. Pred zamenou, ox: " << ox <<
" oy: " << oy << "\n";
pom = ox;
ox = oy;
oy = pom;
std::cout << "Funkce zamena. Po zamene, ox: " << ox <<
" oy: " << oy << "\n";
}
Funkce main. Pred zamenou, x: 5 y: 10 Funkce zamena. Pred zamenou, ox: 5 oy: 10 Funkce zamena. Po zamene, ox: 10 oy: 5 Funkce main. Po zamene, x: 10 y: 5
// Vrácení různých hodnot funkcí
#include <iostream>
using namespace std;
short Faktor(int c, int* oDruhaMocnina, int* oTretiMocnina);
int main()
{
int cislo, druhaMocnina, tretiMocnina;
short chyba;
cout << "Vlozte cislo (0 - 20): ";
cin >> cislo;
chyba = Faktor(cislo, &druhaMocnina, &tretiMocnina);
if (!chyba)
{
cout << "cislo: " << cislo << "\n";
cout << "druha mocnina: " << druhaMocnina << "\n";
cout << "treti mocnina: " << tretiMocnina << "\n";
}
else
cout << "Doslo k chybe!!\n";
return 0;
}
short Faktor(int c, int* oDruhaMocnina, int* oTretiMocnina)
{
short Hodnota = 0;
if (c > 20)
Hodnota = 1;
else
{
*oDruhaMocnina = c*c;
*oTretiMocnina = c*c*c;
Hodnota = 0;
}
return Hodnota;
}
Funkci faktor se předá zadané číslo a adresy proměnných drhuhaMocnina a
tretiMocninave funkci se ukazatelům přiřadí hodnota, která je dostupná
i ve funkci main.
// Vrácení různých hodnot funkcí za pomoci odkazů
#include <iostream>
using namespace std;
typedef unsigned short USHORT;
enum KOD_CHYBY { USPECH, CHYBA };
KOD_CHYBY Faktor(USHORT, USHORT&, USHORT&);
int main()
{
USHORT cislo, druhaMocnina, tretiMocnina;
KOD_CHYBY vysledek;
cout << "Vlozte cislo (0 - 20): ";
cin >> cislo;
vysledek = Faktor(cislo, druhaMocnina, tretiMocnina);
if (vysledek == USPECH)
{
cout << "cislo: " << cislo << "\n";
cout << "druha mocnina: " << druhaMocnina << "\n";
cout << "treti mocnina: " << tretiMocnina << "\n";
}
else
cout << "Doslo k chybe!!\n";
return 0;
}
KOD_CHYBY Faktor(USHORT c, USHORT &oDruhaMocnina, USHORT &oTretiMocnina)
{
if (c > 20)
return CHYBA; // jednoduchý kód chyby
else
{
oDruhaMocnina = c*c;
oTretiMocnina = c*c*c;
return USPECH;
}
}
// Předávání ukazatelů objektům
#include <iostream>
using namespace std;
class ProstaKocka
{
public:
ProstaKocka (); // konstruktor
ProstaKocka(ProstaKocka&); // konstruktor pro kopírování
~ProstaKocka(); // destruktor
};
ProstaKocka::ProstaKocka()
{
cout << "Prosta Kocka: Konstruktor...\n";
}
ProstaKocka::ProstaKocka(ProstaKocka&)
{
cout << "Prosta Kocka: Konstruktor pro kopirovani...\n";
}
ProstaKocka::~ProstaKocka()
{
cout << "Prosta Kocka: Desktruktor...\n";
}
ProstaKocka Funkce1 (ProstaKocka kocka);
ProstaKocka* Funkce2 (ProstaKocka *kocka);
int main()
{
cout << "Vytvoreni kocky...\n";
ProstaKocka Micka;
cout << "Volani Funkce1...\n";
Funkce1(Micka);
cout << "Volani Funkce2...\n";
Funkce2(&Micka);
return 0;
}
// Funkce1, předání hodnotou
ProstaKocka Funkce1 (ProstaKocka kocka)
{
cout << "Funkce1, navrat...\n";
return kocka;
}
// Funkce1, předání odkazem
ProstaKocka* Funkce2 (ProstaKocka *kocka)
{
cout << "Funkce2, navrat...\n";
return kocka;
}
Vytvoreni kocky... Prosta Kocka: Konstruktor... Volani Funkce1... Prosta Kocka: Konstruktor pro kopirovani... Funkce1, navrat... Prosta Kocka: Konstruktor pro kopirovani... Prosta Kocka: Destruktor... Prosta Kocka: Destruktor... Volani Funkce2... Funkce2, navrat... Prosta Kocka: Destruktor...
// Předávání ukazatelů objektům
#include <iostream>
using namespace std;
class ProstaKocka
{
public:
ProstaKocka ();
ProstaKocka(ProstaKocka&);
~ProstaKocka();
int ZiskejVek() const { return vekKocky; }
void NastavVek(int vek) { vekKocky = vek; }
private:
int vekKocky;
};
ProstaKocka::ProstaKocka()
{
cout << "Prosta Kocka: Konstruktor...\n";
vekKocky = 1;
}
ProstaKocka::ProstaKocka(ProstaKocka&)
{
cout << "Prosta Kocka: Konstruktor pro kopirovani...\n";
}
ProstaKocka::~ProstaKocka()
{
cout << "Prosta Kocka: Desktruktor...\n";
}
const ProstaKocka* const Funkce2
(const ProstaKocka * const kocka);
int main()
{
cout << "Vytvoreni kocky...\n";
ProstaKocka Micka;
cout << "Micka ma ";
cout << Micka.ZiskejVek();
cout << " roku\n";
int vek = 5;
Micka.NastavVek(vek);
cout << "Micka ma ";
cout << Micka.ZiskejVek();
cout << " roku\n";
cout << "Volani Funkce2...\n";
Funkce2(&Micka);
cout << "Micka ma ";
cout << Micka.ZiskejVek();
cout << " roku\n";
return 0;
}
// Funkce2, předání konstatním odkazem
const ProstaKocka * const Funkce2
(const ProstaKocka * const kocka)
{
cout << "Funkce2, navrat...\n";
cout << "Micka ma nyni " << kocka->ZiskejVek();
cout << " roku\n";
// kocka->NastavVek(8); const!
return kocka;
}
ProstaKocka má dvě nové přístupové proměnné - ZiskejVek(), která je konstantní a
NastavVek(), které konstantní není.
// Předávání odkazů na objekty
#include <iostream>
using namespace std;
class ProstaKocka
{
public:
ProstaKocka ();
ProstaKocka(ProstaKocka&);
~ProstaKocka();
int ZiskejVek() const { return vekKocky; }
void NastavVek(int vek) { vekKocky = vek; }
private:
int vekKocky;
};
ProstaKocka::ProstaKocka()
{
cout << "Prosta Kocka: Konstruktor...\n";
vekKocky = 1;
}
ProstaKocka::ProstaKocka(ProstaKocka&)
{
cout << "Prosta Kocka: Konstruktor pro kopirovani...\n";
}
ProstaKocka::~ProstaKocka()
{
cout << "Prosta Kocka: Desktruktor...\n";
}
const ProstaKocka & Funkce2 (const ProstaKocka & kocka);
int main()
{
cout << "Vytvoreni kocky...\n";
ProstaKocka Micka;
cout << "Micka ma " << Micka.ZiskejVek() << " roku\n";
int vek = 5;
Micka.NastavVek(vek);
cout << "Micka ma " << Micka.ZiskejVek() << " roku\n";
cout << "Volani Funkce2...\n";
Funkce2(Micka);
cout << "Micka ma " << Micka.ZiskejVek() << " roku\n";
return 0;
}
// Funkce2, předání odkazem
const ProstaKocka & Funkce2 (const ProstaKocka & kocka)
{
cout << "Funkce2, navrat...\n";
cout << "Micka ma nyni " << kocka.ZiskejVek();
cout << " roku\n";
// kocka.NastavVek(8); const!
return kocka;
}
|
Konstantní odkazy
Programátoři C++ obvykle nerozlišují mezi "konstantním odkazem na objekt ProstaKocka" a "odkazem na konstantní objekt ProstaKocka". Odkazy samotné nelze nikdy změnit tak, aby odkazovali na jiný objekt, proto jsou z principu vždy konstantní. Jestliže se u odkazu použije klíčové slovo const, znamená to, že konstantní má být odkazovaný objekt. |
int *ukInt=new Int; if (ukInt !=NULL) int &odInt = *ukInt;
// Vrácení odkazu na objekt, který neexistuje
#include <iostream>
class ProstaKocka
{
public:
ProstaKocka (int vek, int vaha);
~ProstaKocka() {}
int ZiskejVek() const { return vekKocky; }
int ZiskejVahu() const { return vahaKocky; }
private:
int vekKocky;
int vahaKocky;
};
ProstaKocka::ProstaKocka(int vek, int vaha)
{
vekKocky = vek;
vahaKocky = vaha;
}
ProstaKocka &Funkce();
int main()
{
ProstaKocka &oKocka = Funkce();
int vek = oKocka.ZiskejVek();
std::cout << "oKocka ma " << vek << " roku!\n";
return 0;
}
ProstaKocka &Funkce()
{
ProstaKocka Micka(5,9);
return Micka;
}
V programu inicializujeme odkaz na typ ProstaKocka návratovou hodnotou Funkce(), která
je deklarována tak, že vrací odkaz na objekt ProstaKocka.
// Vyřešení problému s životností lokální proměnné
#include <iostream>
class ProstaKocka
{
public:
ProstaKocka (int vek, int vaha);
~ProstaKocka() {}
int ZiskejVek() const { return vekKocky; }
int ZiskejVahu() const { return vahaKocky; }
private:
int vekKocky;
int vahaKocky;
};
ProstaKocka::ProstaKocka(int vek, int vaha)
{
vekKocky = vek;
vahaKocky = vaha;
}
ProstaKocka &Funkce();
int main()
{
ProstaKocka & oKocka = Funkce();
int vek = oKocka.ZiskejVek();
std::cout << "oKocka ma " << vek << " roku!\n";
std::cout << "&oKocka: " << &oKocka << std::endl;
// Jak se zbavit této struktury v paměti?
ProstaKocka * pKocka = &oKocka;
delete pKocka;
// Hmm, kam nyní ukazuje oKocka??
return 0;
}
ProstaKocka & Funkce()
{
ProstaKocka * pMicka = new ProstaKocka(5,9);
std::cout << "pMicka: " << pMicka << std::endl;
return *pMicka;
}
Vytvořením ukazatele ve Funkci() vytvoříme objekt ve volném úložišti. Ale pokud chceme
zamezit úniku paměti, musíme deklarovat nový ukazatel na adresu paměti, kterou lze získat
z odkazu na objekt. Ale po provedení delete, se budeme odkazovat na prázdný objekt!!!
// Přetížení členských funkcí třídy
#include <iostream>
// Deklarace třídy Obdélník
class Obdelnik
{
public:
// konstruktory
Obdelnik(int sirka, int vyska);
~Obdelnik(){}
// přetížená členská funkce KresliTvar třídy
void KresliTvar() const;
void KresliTvar(int sirkaA, int vyskaA) const;
private:
int sirkaObd;
int vyskaObd;
};
// Implementace konstruktoru
Obdelnik::Obdelnik(int sirka, int vyska)
{
sirkaObd = sirka;
vyskaObd = vyska;
}
// Přetížená funkce KresliTvar - nepřijímá žádné vstupní parametry
// Kreslí na základě aktuálních hodnot členských proměnnýcg
void Obdelnik::KresliTvar() const
{
KresliTvar(sirkaObd, vyskaObd);
}
// Přetížená funkce KresliTvar - přijímá dva vstupní parametry
// Kreslí podle předaných parametrů
void Obdelnik::KresliTvar(int sirka, int vyska) const
{
for (int i = 0; i<vyska; i++)
{
for (int j = 0; j<sirka; j++)
{
std::cout << "*";
}
std::cout << "\n";
}
}
// Hlavní program pro demonstraci přetížených funkcí
int main()
{
// inicializace obdélníka na rozměry 30,5
Obdelnik obd(30,5);
std::cout << "KresliTvar(): \n";
obd.KresliTvar();
std::cout << "\nKresliTvar(40,2): \n";
obd.KresliTvar(40,2);
return 0;
}
// Výchozí hodnoty členských funkcí třídy
#include <iostream>
using namespace std;
// Deklarace třídy Obdélník
class Obdelnik
{
public:
// konstruktory
Obdelnik(int sirka, int vyska);
~Obdelnik(){}
void KresliTvar(int sirkaA, int vyskaA,
bool PouzitAktualni = false) const;
private:
int sirkaObd;
int vyskaObd;
};
// Implementace konstruktoru
Obdelnik::Obdelnik(int sirka, int vyska):
sirkaObd(sirka), // inicializace
vyskaObd(vyska)
{} // prázdné tělo
// Třetí parametr má výchozí hodnotu
void Obdelnik::KresliTvar(
int sirka,
int vyska,
bool PouzitAktualni
) const
{
int sirkaTisku;
int vyskaTisku;
if (PouzitAktualni == true)
{
sirkaTisku = sirkaObd; // použití aktuálních hodnot objektu
vyskaTisku = vyskaObd;
}
else
{
sirkaTisku = sirka; // použití hodnot parametrů
vyskaTisku = vyska;
}
for (int i = 0; i<vyskaTisku; i++)
{
for (int j = 0; j<sirkaTisku; j++)
{
cout << "*";
}
cout << "\n";
}
}
// Hlavní program pro demonstraci přetížených funkcí
int main()
{
// inicializace obdélníka na rozměry 30,5
Obdelnik obd(30,5);
cout << "KresliTvar(0,0,true): \n";
obd.KresliTvar(0,0,true);
cout << "\nKresliTvar(40,2): \n";
obd.KresliTvar(40,2);
return 0;
}
Metoda kresli tvar má výchozí hodnotu třetího parametru nastavenou na false a
podle její hodnoty dochází ke kreslení správného tvaru.
// Přetížení konstruktorů
#include <iostream>
using namespace std;
class Obdelnik
{
public:
Obdelnik();
Obdelnik(int sirka, int delka);
~Obdelnik() {}
int ZiskejSirku() const { return sirkaObd; }
int ZiskejDelku() const { return delkaObd; }
private:
int sirkaObd;
int delkaObd;
};
Obdelnik::Obdelnik()
{
sirkaObd = 5;
delkaObd = 10;
}
Obdelnik::Obdelnik (int sirka, int delka)
{
sirkaObd = sirka;
delkaObd = delka;
}
int main()
{
Obdelnik Obd1;
cout << "Sirka Obd1: " << Obd1.ZiskejSirku() << endl;
cout << "Delka Obd1: " << Obd1.ZiskejDelku() << endl;
int sirkaA, delkaA;
cout << "Zadejte sirku: ";
cin >> sirkaA;
cout << "\nZadejte delku: ";
cin >> delkaA;
Obdelnik Obd2(sirkaA, delkaA);
cout << "\nSirka Obd2: " << Obd2.ZiskejSirku() << endl;
cout << "Delka Obd2: " << Obd2.ZiskejDelku() << endl;
return 0;
}
Sirka Obdl: 5 Delka Obdl: 10 Zadejte sirku: 20 Zadejte delku: 50 Sirka Obdl: 20 Delka Obdl: 50
KOCKA(): //název konstruktoru a parametry
vekKocky(5), vahaKocky(8) //inicializační seznam
{} //tělo konstruktoru
Za pravou závorkou uzavírající seznam parametrů konstruktoru následuje dvojtečka, za
níž je název členské proměnné a pár závorek. Výraz uvnitř závorek se použije k inicializaci
členské proměnné. Pokud je inicializací více, oddělují se od sebe čárkami.
Obdelnik::Obdelnik():
sirkaObd(5),
delkaObd(10)
{
}
Obdelnik::Obdelnik (int sirka, int delka):
sirkaObd(5),
delkaObd(10)
{
}
KOCKA (const KOCKA & Kocka);Konstruktor KOCKA si zde bere jako parametr konstantní odkaz na existující objekt KOCKA. Úkolem konstruktoru pro kopírování je vyzvořit kopii objektu Kocka.
// Konstruktory pro kopírování
#include <iostream>
using namespace std;
class KOCKA
{
public:
KOCKA(); // výchozí konstruktor
KOCKA (const KOCKA &); // konstruktor pro kopírování
~KOCKA(); // destruktor
int ZiskejVek() const { return *vekKocky; }
int ZiskejVahu() const { return *vahaKocky; }
void NastavVek(int vek) { *vekKocky = vek; }
private:
int *vekKocky;
int *vahaKocky;
};
KOCKA::KOCKA()
{
vekKocky = new int;
vahaKocky = new int;
*vekKocky = 5;
*vahaKocky = 9;
}
KOCKA::KOCKA(const KOCKA & ptr)
{
vekKocky = new int;
vahaKocky = new int;
*vekKocky = ptr.ZiskejVek(); // veřejný přístup
*vahaKocky = *(ptr.vahaKocky); // privátní přístup
}
KOCKA::~KOCKA()
{
delete vekKocky;
vekKocky = 0;
delete vahaKocky;
vahaKocky = 0;
}
int main()
{
KOCKA micka;
cout << "Vek Micky je: " << micka.ZiskejVek() << endl;
cout << "Nastaveni veku Micky na 6...\n";
micka.NastavVek(6);
cout << "Vytvoreni Mourka na zaklade Micky\n";
KOCKA mourek(micka);
cout << "Vek Micky je: " << micka.ZiskejVek() << endl;
cout << "Vek Mourka je: " << mourek.ZiskejVek() << endl;
cout << "Nastaveni veku Micky na 7...\n";
micka.NastavVek(7);
cout << "Vek Micky je: " << micka.ZiskejVek() << endl;
cout << "Vek Mourka je: " << mourek.ZiskejVek() << endl;
return 0;
}
Vek Micky je: 5 Nastaveni veku Micky na 6... Vytvoreni Mourka na zaklade Micky Vek Micky je: 6 Vek Mourka je: 6 Nastaveni veku Micky na 7... Vek Micky je: 7 Vek Mourka je 6
// Třída Čítač
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
int main()
{
Citac i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
return 0;
}
V této podobě se jedná o špatně použitelnou třídu. Na rozdíl od celočíselné hodnoty není
možné hodnotu typu Citac inkrementovat, dekrementovat, nelze tyto objekty sčítat.
// Třída Čítač
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
void Inkrementace() { ++hodnota; }
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
int main()
{
Citac i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
i.Inkrementace();
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
return 0;
}
Hodnota citace i je 0 Hodnota citace i je 1
// Třída Čítač
// prefixový operátor inkrementace
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
void Inkrementace() { ++hodnota; }
void operator++ () { ++hodnota; }
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
int main()
{
Citac i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
i.Inkrementace();
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
++i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
return 0;
}
Hodnota citace i je 0 Hodnota citace i je 1 Hodnota citace i je 2Takto popsaný operátor má nedostatek - pokud jej použijeme na pravé straně výrazu, nepodaří se to.
Citac c= ++i;Operátor inkrementace totiž nevrací žádnou hodnotu (void), proto hodnota c nebude inicializována.
// operátor++ vrací dočasný objekt
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
void Inkrementace() { ++hodnota; }
Citac operator++ ();
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
Citac Citac::operator++()
{
++hodnota;
Citac pom;
pom.NastavHodnotu(hodnota);
return pom;
}
int main()
{
Citac i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
i.Inkrementace();
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
++i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
Citac a = ++i;
cout << "Hodnota a: " << i.ZiskejHodnotu();
cout << " a hodnota i: " << i.ZiskejHodnotu() << endl;
return 0;
}
Hodnota citace i je 0 Hodnota citace i je 1 Hodnota citace i je 2 Hodnota a: 3 a hodnota i: 3
// operátor++ vrací bezejmenný dočasný objekt
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
Citac(int hodnotaA);
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
void Inkrementace() { ++hodnota; }
Citac operator++ ();
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
Citac::Citac(int hodnotaA):
hodnota(hodnotaA)
{}
Citac Citac::operator++()
{
++hodnota;
return Citac (hodnota);
}
int main()
{
Citac i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
i.Inkrementace();
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
++i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
Citac a = ++i;
cout << "Hodnota a: " << i.ZiskejHodnotu();
cout << " a hodnota i: " << i.ZiskejHodnotu() << endl;
return 0;
}
Citac má nyní konstruktor přijímající parametr typu int. V implementaci operátoru ++
se vytvoří dočasný objekt, který se inicializuje hodnotou proměnné hodntota.
Dočasné objekty se však musí vytvářet pomocí konstruktoru a zničit pomocí destruktoru, což
jsou zbytečné operace.
// Vrácení dereferencovaného ukazatele "this"
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
void Inkrementace() { ++hodnota; }
const Citac& operator++ ();
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
const Citac& Citac::operator++()
{
++hodnota;
return *this;
}
int main()
{
Citac i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
i.Inkrementace();
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
++i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
Citac a = ++i;
cout << "Hodnota a: " << i.ZiskejHodnotu();
cout << " a hodnota i: " << i.ZiskejHodnotu() << endl;
return 0;
}
Vrácený objekt Citac je konstantní. Kdyby nebyl, daly by se měnit jeho hodnoty např.
Citac a = ++++i;
// Vrácení dereferencovaného ukazatele "this"
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
const Citac& operator++ (); // prefixový operátor
const Citac operator++ (int); // postfixový operátor
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
const Citac& Citac::operator++()
{
++hodnota;
return *this;
}
const Citac Citac::operator++(int priznak)
{
Citac pom(*this);
++hodnota;
return pom;
}
int main()
{
Citac i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
i++;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
++i;
cout << "Hodnota citace i je " << i.ZiskejHodnotu() << endl;
Citac a = ++i;
cout << "Hodnota a: " << a.ZiskejHodnotu();
cout << " a hodnota i: " << i.ZiskejHodnotu() << endl;
a = i++;
cout << "Hodnota a: " << a.ZiskejHodnotu();
cout << " a hodnota i: " << i.ZiskejHodnotu() << endl;
return 0;
}
Hodnota citace i je 0 Hodnota citace i je 1 Hodnota citace i je 2 Hodnota a: 3 a hodnota i: 3 Hodnota a: 3 a hodnota i: 4Postfixovému operátoru se předává parametr (priznak), který slouží jako signál, že se jedná právě o postfix, ale jeho hodnota se nikdy nepoužije.
// Funkce Přičti
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
Citac(int uvodniHodnota);
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
Citac Pricti(const Citac &);
private:
int hodnota;
};
Citac::Citac(int uvodniHodnota):
hodnota(uvodniHodnota)
{}
Citac::Citac():
hodnota(0)
{}
Citac Citac::Pricti(const Citac & ptr)
{
return Citac(hodnota + ptr.ZiskejHodnotu());
}
int main()
{
Citac citac1(2), citac2(4), citac3;
citac3 = citac1.Pricti(citac2);
cout << "citac1: " << citac1.ZiskejHodnotu() << endl;
cout << "citac2: " << citac2.ZiskejHodnotu() << endl;
cout << "citac3: " << citac3.ZiskejHodnotu() << endl;
return 0;
}
// Přetížení operátoru plus (+)
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
Citac(int uvodniHodnota);
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
Citac operator+ (const Citac &);
private:
int hodnota;
};
Citac::Citac(int uvodniHodnota):
hodnota(uvodniHodnota)
{}
Citac::Citac():
hodnota(0)
{}
Citac Citac::operator+ (const Citac & ptr)
{
return Citac(hodnota + ptr.ZiskejHodnotu());
}
int main()
{
Citac citac1(2), citac2(4), citac3;
citac3 = citac1 + citac2;
cout << "citac1: " << citac1.ZiskejHodnotu() << endl;
cout << "citac2: " << citac2.ZiskejHodnotu() << endl;
cout << "citac3: " << citac3.ZiskejHodnotu() << endl;
return 0;
}
Řádek citac3=citac2+citac1; kompilátor přeloží jako
citac3=citac1.Operator+(citac2);, protože metoda operator+ se volá s
operandem na levé straně operátoru a jako argument je jí předán operand na pravé straně.
KOCKA kocka1(5,7); KOCKA kocka2(3,4); kocka2=kocka1;Co když je proměnná vekKocky ukazatelem? Co se stane s původními hodnotamiv objektu kocka2?
// Konstruktory pro kopírování
#include <iostream>
using namespace std;
class KOCKA
{
public:
KOCKA(); // výchozí konstruktor
// konstruktor pro kopírování a destruktor zmizely!
int ZiskejVek() const { return *vekKocky; }
int ZiskejVahu() const { return *vahaKocky; }
void NastavVek(int vek) { *vekKocky = vek; }
KOCKA & operator=(const KOCKA &);
private:
int *vekKocky;
int *vahaKocky;
};
KOCKA::KOCKA()
{
vekKocky = new int;
vahaKocky = new int;
*vekKocky = 5;
*vahaKocky = 9;
}
KOCKA & KOCKA::operator=(const KOCKA & ptr)
{
if (this == &ptr)
return *this;
*vekKocky = ptr.ZiskejVek();
*vahaKocky = ptr.ZiskejVahu();
return *this;
}
int main()
{
KOCKA micka;
cout << "Vek Micky je: " << micka.ZiskejVek() << endl;
cout << "Nastaveni veku Micky na 6...\n";
micka.NastavVek(6);
KOCKA fousek;
cout << "Vek Fouska je: " << fousek.ZiskejVek() << endl;
cout << "Zkopirovani Micky na Fouska...\n";
fousek = micka;
cout << "Vek Fouska je: " << fousek.ZiskejVek() << endl;
return 0;
}
Vek Micky je: 5 Nastaveni veku Micky na 6... Vek Fouska je: 5 Zkopirovani Micky na Fouska... Vek Fouska je: 6K porovnání, jestli se nejedná o přiřazení sobě samému, slouží ukazatel this.
// Tento kód nelze zkompilovat!
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
int main()
{
int promShort = 5;
Citac citac1 = promShort;
cout << "citac1: " << citac1.ZiskejHodnotu() << endl;
return 0;
}
Program nelze zkompilovat, protože int nelze převést na Citac.
// Konstruktor jako operátor konverze
#include <iostream>
using namespace std;
class Citac
{
public:
Citac();
Citac(int hodnotaA);
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
Citac::Citac(int hodnotaA):
hodnota(hodnotaA)
{}
int main()
{
int promShort = 5;
Citac citac1 = promShort;
cout << "citac1: " << citac1.ZiskejHodnotu() << endl;
return 0;
}
Deklatujeme přetížený konstruktor, který přijímá hodnotu typu int. Tento konstruktor má z
typu int vytvořit typ Citac.
// Operátory konverze
#include <iostream>
class Citac
{
public:
Citac();
Citac(int hodnotaA);
~Citac(){}
int ZiskejHodnotu()const { return hodnota; }
void NastavHodnotu(int x) { hodnota = x; }
operator unsigned short();
private:
int hodnota;
};
Citac::Citac():
hodnota(0)
{}
Citac::Citac(int hodnotaA):
hodnota(hodnotaA)
{}
Citac::operator unsigned short ()
{
return ( int (hodnota) );
}
int main()
{
Citac citac1(5);
int promShort = citac1;
std::cout << "promShort: " << promShort << std::endl;
return 0;
}
Operátor konverze je deklarován bez návratového typu operator unsigned short();
a vrací hodnotu proměnné hodnota převedenou na typ int.
Případ použití: Klient vybírá hotovost Scénář: Úspěšný výběr hotovosti z běžného účtu Vstupní podmínky: Klient je přihlášený do systému Spoušť: Klient požaduje "výběr" Popis: Klient zvolí výbet hotovosti z běžného účtu. Na účtu je dostatek hotovosti, v bankomatu je dostatek hotovosti a papíru pro účtenku a síť je aktivní a funguje. Bankomat požádá klienta o určení množství daného výběru a klient požádá o 5000Kč, což je za dané situace platné množství. Přístroj vydá 5000Kč a vytiskne účtenku. Klient si vezme peníze a účtenku. Výstupní podmínky: Stav účtu klienta se sníží o 5000Kč a klient má 5000Kč v hotovosti.
class Pes : public SavecTřída, te které se odvozuje, musí být deklarována dříve.
#include <iostream>
using namespace std;
enum RASA { ZLATY_RETRIEVER, PUDL, JEZEVCIK, OVCAK, DOBRMAN, LABRADOR };
class Savec
{
public:
// Konstruktory
Savec();
~Savec();
// Přístupové metody
int ZjistitVek() const;
void ZadatVek(int);
int ZjistitVahu() const;
void ZadatVahu();
// Další metody
void Promluvit() const;
void Spat() const;
protected:
int jehoVek;
int jehoVaha;
};
class Pes : public Savec
{
public:
// Konstruktory
Pes();
~Pes();
// Přístupové metody
RASA ZjistitRasu() const;
void ZadatRasu(RASA);
// Další metody
VrtetOcasem();
PrositOJidlo();
protected:
RASA jehoRasa;
};
//Použití odvozeného objektu
#include <iostream>
using std::cout;
enum RASA { ZLATY_RETRIEVER, PUDL, JEZEVCIK, OVCAK, DOBRMAN, LABRADOR };
class Savec
{
public:
// Konstruktory
Savec():jehoVek(2), jehoVaha(5){}
~Savec(){}
// Přístupové metody
int ZjistitVek() const { return jehoVek; }
void ZadatVek(int vek) { jehoVek = vek; }
int ZjistitVahu() const { return jehoVaha; }
void ZadatVahu(int vaha) { jehoVaha = vaha; }
// Další metody
void Promluvit()const { cout << "Zvuk savce!\n"; }
void Spat()const { cout << "Psssst. Prave spim.\n"; }
protected:
int jehoVek;
int jehoVaha;
};
class Pes : public Savec
{
public:
// Konstruktory
Pes():jehoRasa(ZLATY_RETRIEVER){}
~Pes(){}
// Přístupové metody
RASA ZjistitRasu() const { return jehoRasa; }
void ZadatRasu(RASA rasa) { jehoRasa = rasa; }
// Další metody
void VrtetOcasem() const { cout << "Vrti ocasem...\n"; }
void PrositOJidlo() const { cout << "Prosi o jidlo...\n"; }
private:
RASA jehoRasa;
};
int main()
{
Pes fido;
fido.Promluvit();
fido.VrtetOcasem();
cout << "Fidovi je " << fido.ZjistitVek() << " let\n";
return 0;
}
Zvuk savce! Vrti ocasem... Fidovi je 2 let
//Volání konstruktorů a destruktorů
#include <iostream>
enum RASA { ZLATY_RETRIEVER, PUDL, JEZEVCIK, OVCAK, DOBRMAN, LABRADOR };
class Savec
{
public:
// Konstruktory
Savec();
~Savec();
// Přístupové metody
int ZjistitVek() const { return jehoVek; }
void ZadatVek(int vek) { jehoVek = vek; }
int ZjistitVahu() const { return jehoVaha; }
void ZadatVahu(int vaha) { jehoVaha = vaha; }
// Další metody
void Promluvit() const { std::cout << "Zvuk savce!\n"; }
void Spat() const { std::cout << "Psssst. Prave spim.\n"; }
protected:
int jehoVek;
int jehoVaha;
};
class Pes : public Savec
{
public:
// Konstruktory
Pes();
~Pes();
// Přístupové metody
RASA ZjistitRasu() const { return jehoRasa; }
void ZadatRasu(RASA rasa) { jehoRasa = rasa; }
// Další metody
void VrtetOcasem() const { std::cout << "Vrti ocasem...\n"; }
void PrositOJidlo() const { std::cout << "Prosi o jidlo...\n"; }
private:
RASA jehoRasa;
};
Savec::Savec():
jehoVek(1),
jehoVaha(5)
{
std::cout << "Konstruktor Savec...\n";
}
Savec::~Savec()
{
std::cout << "Destruktor Savec...\n";
}
Pes::Pes():
jehoRasa(ZLATY_RETRIEVER)
{
std::cout << "Konstruktor Pes...\n";
}
Pes::~Pes()
{
std::cout << "Destruktor Pes...\n";
}
int main()
{
Pes fido;
fido.Promluvit();
fido.VrtetOcasem();
std::cout << "Fidovi je " << fido.ZjistitVek() << " let\n";
return 0;
}
Konstruktor Savec... Konstruktor Pes... Zvuk savce! Vrti ocasem... Fidovi je 1 let Destruktor Pes... Destruktor Savec...
//Přetěžování konstruktorů v odvozených třídách
#include <iostream>
using namespace std;
enum RASA { ZLATY_RETRIEVER, PUDL, JEZEVCIK, OVCAK, DOBRMAN, LABRADOR };
class Savec
{
public:
// Konstruktory
Savec();
Savec(int vek);
~Savec();
// Přístupové metody
int ZjistitVek() const { return jehoVek; }
void ZadatVek(int vek) { jehoVek = vek; }
int ZjistitVahu() const { return jehoVaha; }
void ZadatVahu(int vaha) { jehoVaha = vaha; }
// Další metody
void Promluvit() const { cout << "Zvuk savce!\n"; }
void Spat() const { cout << "Psssst. Prave spim.\n"; }
protected:
int jehoVek;
int jehoVaha;
};
class Pes : public Savec
{
public:
// Konstruktory
Pes();
Pes(int vek);
Pes(int vek, int vaha);
Pes(int vek, RASA rasa);
Pes(int vek, int vaha, RASA rasa);
~Pes();
// Přístupové metody
RASA ZjistitRasu() const { return jehoRasa; }
void ZadatRasu(RASA rasa) { jehoRasa = rasa; }
// Další metody
void VrtetOcasem() const { cout << "Vrti ocasem...\n"; }
void PrositOJidlo() const { cout << "Prosi o jidlo...\n"; }
private:
RASA jehoRasa;
};
Savec::Savec():
jehoVek(1),
jehoVaha(5)
{
cout << "Konstruktor Savec...\n";
}
Savec::Savec(int vek):
jehoVek(vek),
jehoVaha(5)
{
cout << "Konstruktor Savec(int)...\n";
}
Savec::~Savec()
{
cout << "Destruktor Savec...\n";
}
Pes::Pes():
Savec(),
jehoRasa(ZLATY_RETRIEVER)
{
cout << "Konstruktor Pes...\n";
}
Pes::Pes(int vek):
Savec(vek),
jehoRasa(ZLATY_RETRIEVER)
{
cout << "Konstruktor Pes(int)...\n";
}
Pes::Pes(int vek, int vaha):
Savec(vek),
jehoRasa(ZLATY_RETRIEVER)
{
jehoVaha = vaha;
cout << "Konstruktor Pes(int, int)...\n";
}
Pes::Pes(int vek, int vaha, RASA rasa):
Savec(vek),
jehoRasa(rasa)
{
jehoVaha = vaha;
cout << "Konstruktor Pes(int, int, RASA)...\n";
}
Pes::Pes(int vek, RASA rasa):
Savec(vek),
jehoRasa(rasa)
{
cout << "Konstruktor Pes(int, RASA)...\n";
}
Pes::~Pes()
{
cout << "Destruktor Pes...\n";
}
int main()
{
Pes fido;
Pes punta(5);
Pes bastr(6,8);
Pes lassie(3,ZLATY_RETRIEVER);
Pes hasky(4,20,DOBRMAN);
fido.Promluvit();
punta.VrtetOcasem();
cout << "Lassie je " << lassie.ZjistitVek() << " let\n";
cout << "Hasky vazi ";
cout << hasky.ZjistitVahu() << " kilogramu\n";
return 0;
}
//Překrytí metody bázové třídy v odvozené třídě
#include <iostream>
using std::cout;
enum RASA { ZLATY_RETRIEVER, PUDL, JEZEVCIK, OVCAK, DOBRMAN, LABRADOR };
class Savec
{
public:
// Konstruktory
Savec() { cout << "Konstruktor Savec...\n"; }
~Savec() { cout << "Destruktor Savec...\n"; }
// Další metody
void Promluvit() const { cout << "Zvuk savce!\n"; }
void Spat() const { cout << "Psssst. Prave spim.\n"; }
protected:
int jehoVek;
int jehoVaha;
};
class Pes : public Savec
{
public:
// Konstruktory
Pes(){ cout << "Konstruktor Pes...\n"; }
~Pes(){ cout << "Destruktor Pes...\n"; }
// Další metody
void VrtetOcasem() const { cout << "Vrti ocasem...\n"; }
void PrositOJidlo() const { cout << "Prosi o jidlo...\n"; }
void Promluvit() const { cout << "Haf!\n"; }
private:
RASA jehoRasa;
};
int main()
{
Savec velkeZvire;
Pes fido;
velkeZvire.Promluvit();
fido.Promluvit();
return 0;
}
Konstruktor Savec... Konstruktor Savec... Konstruktor Pes... Zvuk savce! Haf! Destruktor Pes... Destruktor Savec... Destruktor Savec...
//Skrývání metod
#include <iostream>
class Savec
{
public:
void Pohnout() const { std::cout << "Savec se posune o krok\n"; }
void Pohnout(int vzdalenost) const
{
std::cout << "Savec se posune o ";
std::cout << vzdalenost <<" kroku.\n";
}
protected:
int jehoVek;
int jehoVaha;
};
class Pes : public Savec
{
public:
// Můžete obdržet varování, že skrýváte nějakou funkci!
void Pohnout() const { std::cout << "Pes se posune o 5 kroku.\n"; }
};
int main()
{
Savec velkeZvire;
Pes fido;
velkeZvire.Pohnout();
velkeZvire.Pohnout(2);
fido.Pohnout();
// fido.Pohnout(10);
return 0;
}
Pokud chceme používat metodu Pohnout(int vzdalenost) const musíme ji také překrýt, protože
překrytím metody bez parametru byla tato metoda skryta a nelze použít. Proto je řádek
vykomentován - způsobil by chybu kompilace.
fido.Savec::Pohnout(10);
//Volání bázové metody z překryté metody
#include <iostream>
using namespace std;
class Savec
{
public:
void Pohnout() const { cout << "Savec se posune o krok\n"; }
void Pohnout(int vzdalenost) const
{
cout << "Savec se posune o " << vzdalenost;
cout << " kroku.\n";
}
protected:
int jehoVek;
int jehoVaha;
};
class Pes : public Savec
{
public:
void Pohnout() const;
};
void Pes::Pohnout() const
{
cout << "V pohybu psa...\n";
Savec::Pohnout(3);
}
int main()
{
Savec velkeZvire;
Pes fido;
velkeZvire.Pohnout(2);
fido.Savec::Pohnout(6);
return 0;
}
Savec se posune o 2 kroku. Savec se posune o 6 kroku.
//Použití virtuálních metod
#include <iostream>
using std::cout;
class Savec
{
public:
Savec():jehoVek(1) { cout << "Konstruktor Savec...\n"; }
virtual ~Savec() { cout << "Destruktor Savec...\n"; }
void Pohnout() const { cout << "Savec se posune o krok\n"; }
virtual void Promluvit() const { cout << "Savec hovori!\n"; }
protected:
int jehoVek;
};
class Pes : public Savec
{
public:
Pes() { cout << "Konstruktor Pes...\n"; }
virtual ~Pes() { cout << "Destruktor Pes...\n"; }
void VrtetOcasem() { cout << "Vrti ocasem...\n"; }
void Promluvit()const { cout << "Haf!\n"; }
void Pohnout()const { cout << "Pes se posune o 5 kroku...\n"; }
};
int main()
{
Savec *pPes = new Pes;
pPes->Pohnout();
pPes->Promluvit();
return 0;
}
Konstruktor Savec... Konstruktor Pes... Savec se posune o krok. Haf!Deklarování metody jako virtuální značí, že metoda bude překryta jinou metodou ve vlastní třídě.
//Více postupně volaných virtuálních funkcí
#include <iostream>
using namespace std;
class Savec
{
public:
Savec():jehoVek(1) { }
virtual ~Savec() { }
virtual void Promluvit() const { cout << "Savec hovori!\n"; }
protected:
int jehoVek;
};
class Pes : public Savec
{
public:
void Promluvit()const { cout << "Haf!\n"; }
};
class Kocka : public Savec
{
public:
void Promluvit()const { cout << "Mnau!\n"; }
};
class Kun : public Savec
{
public:
void Promluvit()const { cout << "Iihaha!\n"; }
};
class Vepr : public Savec
{
public:
void Promluvit()const { cout << "Chrocht!\n"; }
};
int main()
{
Savec* toPole[5];
Savec* ukz;
int volba, i;
for ( i = 0; i<5; i++)
{
cout << "(1)pes (2)kocka (3)kun (4)vepr: ";
cin >> volba;
switch (volba)
{
case 1: ukz = new Pes;
break;
case 2: ukz = new Kocka;
break;
case 3: ukz = new Kun;
break;
case 4: ukz = new Vepr;
break;
default: ukz = new Savec;
break;
}
toPole[i] = ukz;
}
for (i=0;i<5;i++)
toPole[i]->Promluvit();
return 0;
}
(1)pes (2)kocka (3)kun (4)vepr: 1 (1)pes (2)kocka (3)kun (4)vepr: 2 (1)pes (2)kocka (3)kun (4)vepr: 3 (1)pes (2)kocka (3)kun (4)vepr: 4 (1)pes (2)kocka (3)kun (4)vepr: 5 Haf! Mnau! Iihaha! Chrocht! Savec hovori!Během kompilace není možné určit, které metody se budou volat. Dochází k dynamickému vázání za běhu programu.
//Data slistd:std::cing s předáváním hodnotou
#include <iostream>
class Savec
{
public:
Savec():jehoVek(1) { }
virtual ~Savec() { }
virtual void Promluvit() const { std::cout << "Savec hovori!\n"; }
protected:
int jehoVek;
};
class Pes : public Savec
{
public:
void Promluvit()const { std::cout << "Haf!\n"; }
};
class Kocka : public Savec
{
public:
void Promluvit()const { std::cout << "Mnau!\n"; }
};
void HodnotovaFunkce (Savec);
void UkazatelovaFunkce (Savec*);
void OdkazovaFunkce (Savec&);
int main()
{
Savec* ukz=0;
int volba;
while (1)
{
bool fKonec = false;
std::cout << "(1)pes (2)kocka (0)Konec: ";
std::cin >> volba;
switch (volba)
{
case 0: fKonec = true;
break;
case 1: ukz = new Pes;
break;
case 2: ukz = new Kocka;
break;
default: ukz = new Savec;
break;
}
if (fKonec)
break;
UkazatelovaFunkce(ukz);
OdkazovaFunkce(*ukz);
HodnotovaFunkce(*ukz);
}
return 0;
}
void HodnotovaFunkce (Savec HodnotaSavec)
{
HodnotaSavec.Promluvit();
}
void UkazatelovaFunkce (Savec * pSavec)
{
pSavec->Promluvit();
}
void OdkazovaFunkce (Savec & rSavec)
{
rSavec.Promluvit();
}
(1)pes (2)kocka (0)konec: 1 Haf! Haf! Savec hovori! (1)pes (2)kocka (0)konec: 2 Mnau! Mnau! Savec hovori! (1)pes (2)kocka (0)konec: 0
//Virtuální kopírovací konstruktor
#include <iostream>
using namespace std;
class Savec
{
public:
Savec():jehoVek(1) { cout << "Konstruktor Savec...\n"; }
virtual ~Savec() { cout << "Destruktor Savec...\n"; }
Savec (const Savec & rhs);
virtual void Promluvit() const { cout << "Savec hovori!\n"; }
virtual Savec* Klonovat() { return new Savec(*this); }
int ZjistitVek()const { return jehoVek; }
protected:
int jehoVek;
};
Savec::Savec (const Savec & rhs):jehoVek(rhs.ZjistitVek())
{
cout << "Kopirovaci konstruktor Savec...\n";
}
class Pes : public Savec
{
public:
Pes() { cout << "Konstruktor Pes...\n"; }
virtual ~Pes() { cout << "Destruktor Pes...\n"; }
Pes (const Pes & rhs);
void Promluvit()const { cout << "Haf!\n"; }
virtual Savec* Klonovat() { return new Pes(*this); }
};
Pes::Pes(const Pes & rhs):
Savec(rhs)
{
cout << "Kopirovaci konstruktor Pes...\n";
}
class Kocka : public Savec
{
public:
Kocka() { cout << "Konstruktor Kocka...\n"; }
~Kocka() { cout << "Destruktor Kocka...\n"; }
Kocka (const Kocka &);
void Promluvit()const { cout << "Mnau!\n"; }
virtual Savec* Klonovat() { return new Kocka(*this); }
};
Kocka::Kocka(const Kocka & rhs):
Savec(rhs)
{
cout << "Kopirovaci konstruktor Kocka...\n";
}
enum ZVIRATA { SAVEC, PES, KOCKA};
const int pocetTypuZvirat = 3;
int main()
{
Savec *toPole[pocetTypuZvirat];
Savec* ukz;
int volba, i;
for ( i = 0; i<pocetTypuZvirat; i++)
{
cout << "(1)pes (2)kocka (3)Savec: ";
cin >> volba;
switch (volba)
{
case PES: ukz = new Pes;
break;
case KOCKA: ukz = new Kocka;
break;
default: ukz = new Savec;
break;
}
toPole[i] = ukz;
}
Savec *JinePole[pocetTypuZvirat];
for (i=0;i<pocetTypuZvirat;i++)
{
toPole[i]->Promluvit();
JinePole[i] = toPole[i]->Klonovat();
}
for (i=0;i<pocetTypuZvirat;i++)
JinePole[i]->Promluvit();
return 0;
}
(1)pes (2)kocka (3)savec: 1 Konstruktor Savec... Konstruktor Pes... (1)pes (2)kocka (3)savec: 2 Konstruktor Savec... Konstruktor Kocka... (1)pes (2)kocka (3)savec: 3 Konstruktor Savec... Haf! Kopirovaci konstruktor Savec... Kopirovaci konstruktor Pes... Mnau! Kopirovaci konstruktor Savec... Kopirovaci konstruktor Kocka... Savec hovori! Kopirovaci konstruktor Savec... Haf! Mnau! Savec hovori!Metoda Savec::Klonovat() vrací ukazatel na nový objekt Savec voláním kopírovacího konstruktoru, přičemž objekt předává sáme sebe jako konstantní odkaz.
long PoleDlouhych[25];deklaruje pole dlouhých celých čísel o velikosti 25 prvků.
#include <iostream>
int main()
{
int mojePole[5];
int i;
for ( i=0; i<5; i++) // 0-4
{
std::cout <<"Hodnota mojePole[" << i <<"]: ";
std::cin >> mojePole[i];
}
for (i = 0; i<5; i++)
std::cout << i <<": " << mojePole[i] <<"\n";
return 0;
}
// Ukazuje, co se stane při zápisu za konec pole
#include <iostream>
using namespace std;
int main()
{
// hlídky
long hlidkaJedna[3];
long CilovePole[25]; // naplňované pole
long hlidkaDve[3];
int i;
for (i=0; i < 3; i++)
hlidkaJedna[i] = hlidkaDve[i] = 0;
for (i=0; i<25; i++)
CilovePole[i] = 0;
cout <<"Test 1: \n"; // testování aktuálních hodnot (měly by být 0)
cout <<"CilovePole[0]: " << CilovePole[0] <<"\n";
cout <<"CilovePole[24]: " << CilovePole[24] <<"\n\n";
for (i = 0; i<3; i++)
{
cout <<"hlidkaJedna[" << i <<"]: ";
cout << hlidkaJedna[i] <<"\n";
cout <<"hlidkaDve[" << i <<"]: ";
cout << hlidkaDve[i]<<"\n";
}
cout <<"\nPrirazuji...";
for (i = 0; i<=25; i++)
CilovePole[i] = 20;
cout <<"\nTest 2: \n";
cout <<"CilovePole[0]: " << CilovePole[0] <<"\n";
cout <<"CilovePole[24]: " << CilovePole[24] <<"\n";
cout <<"CilovePole[25]: " << CilovePole[25] <<"\n\n";
for (i = 0; i<3; i++)
{
cout <<"hlidkaJedna[" << i <<"]: ";
cout << hlidkaJedna[i]<<"\n";
cout <<"hlidkaDve[" << i <<"]: ";
cout << hlidkaDve[i]<<"\n";
}
return 0;
}
Chyba zápisu za konec pole je tak obvyklá, že má své vlastní jméno. Označuje se jako chyba sloupků
u plotu. Jedná se o problém výpočtu, kolik sloupků potřebujeme na 10ti metrový plot, když na jeden metr
je potřeba jeden sloupek. Je potřeba 11 sloupků.
int PoleCelych[5]={10,20,30,40,50};
Pokud chceme zjistit velikost pole, lze ji vypočítat:
const unsigned shor int DelkaPole=sizeof(PoleCelych)/sizeof(PoleCelych[0]];
// Dimenzování polí konstantami a výčty
#include <iostream>
int main()
{
enum DnyTydne { Ned, Pon, Ute,
Str, Crt, Pat, Sob, DnyVTydnu };
int PoleTydne[DnyVTydnu] = { 10, 20, 30, 40, 50, 60, 70 };
std::cout << "Hodnota v utery je: " << PoleTydne[Ute];
return 0;
}
Hodnota v utery je: 30
|
POLE Pro deklaraci pole napíšeme typ uloženého objektu, název pole a index s počtem objektů obsažených v daném poli. Příklad 1: int MojeCelociselnePole[90];Příklad2: long * PoleUkazateluNaDlouhaCisla[100];Pro přístup k členům pole, slouží operátor indexu. Příklad 1: int devateCeleCislo=MojeCelociselnePole[8];Příklad 2: long * plong = PoleUkazateluNaDlouhaCisla[8];Pole se počítají od nuly. Pole s počtem n položek se čísluje od 0 do n-1. |
// Pole objektů
#include <iostream>
using namespace std;
class KOCKA
{
public:
KOCKA() { jejiVek = 1; jejiVaha=5; }
~KOCKA() {}
int ZjistitVek() const { return jejiVek; }
int ZjistitVahu() const { return jejiVaha; }
void ZadatVek(int vek) { jejiVek = vek; }
private:
int jejiVek;
int jejiVaha;
};
int main()
{
KOCKA Kosik[5];
int i;
for (i = 0; i < 5; i++)
Kosik[i].ZadatVek(2*i +1);
for (i = 0; i < 5; i++)
{
cout << "Kocka cislo " << i+1<< ": ";
cout << Kosik[i].ZjistitVek() << endl;
}
return 0;
}
Kocka cislo 1: 1 Kocka cislo 2: 3 Kocka cislo 3: 5 Kocka cislo 4: 7 Kocka cislo 5: 9Analýza: Třída KOCKA musí mít výchozí konstruktor. Jestliže vytvoříme jiný konstruktor, pak kompilátor výchozí konstruktor nevytvoří, ale musíme jej udělat sami!!!
CTVEREC Sachovnice[8][8];deklaruje dvojrozměrné pole čtverců (třída CTVEREC musí být vytvořena).
CTVEREC Sachovnice[64];V tomto poli si ale težko představíme rozestavění figur. Král na začátku hry stojí na čtvrtém poli v první řadě, tedy:
Sachovnice[0][3];pokud první index vyjadřuje řádek a druhý sloupec.
int toPole[5][3];Pak pokud chceme inicializovat pole hodnotami, tak se první tři hodnoty uloží do toPole[0], další tři do toPole[1] atd.
int toPole[5][3]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
Pro zřetelnost lze seskupit inicializace složenými závorkami:
int toPole[5][3]={ {1,2,3},
{4,5,5},
{7,8,9},
{10,11,12},
{13,14,15} };
Kompilátor vnitří závorky ignoruje. Pouze zlepšují přehlednost
zápisu.
Všechny prvky pole musí být odděleny čárkami, bez ohledu na vnitřní závorky!!
// Vytváření vícerozměrného pole
#include <iostream>
using namespace std;
int main()
{
int nejakePole[5][2] = { {0,0}, {1,2}, {2,4}, {3,6}, {4,8}};
for (int i = 0; i<5; i++)
for (int j=0; j<2; j++)
{
cout << "nejakePole[" << i << "][" << j << "]: ";
cout << nejakePole[i][j]<< endl;
}
return 0;
}
nejakePole[0][0]: 0 nejakePole[0][1]: 0 nejakePole[1][0]: 1 nejakePole[1][1]: 2 nejakePole[2][0]: 2 nejakePole[2][1]: 4 nejakePole[3][0]: 3 nejakePole[3][1]: 6 nejakePole[4][0]: 4 nejakePole[4][1]: 8
// Pole ukazatelů na objekty
#include <iostream>
using namespace std;
class KOCKA
{
public:
KOCKA() { jejiVek = 1; jejiVaha=5; }
~KOCKA() {} // Destruktor
int ZjistitVek() const { return jejiVek; }
int ZjistitVahu() const { return jejiVaha; }
void ZadatVek(int vek) { jejiVek = vek; }
private:
int jejiVek;
int jejiVaha;
};
int main()
{
KOCKA * Rodina[500];
int i;
KOCKA * pKocka;
for (i = 0; i < 500; i++)
{
pKocka = new KOCKA;
pKocka->ZadatVek(2*i +1);
Rodina[i] = pKocka;
}
for (i = 0; i < 500; i++)
{
cout << "Kocka cislo " << i+1 << ": ";
cout << Rodina[i]->ZjistitVek() << endl;
}
return 0;
}
Kocka cislo 1: 1 Kocka cislo 2: 3 Kocka cislo 3: 5 Kocka cislo 5: 7 ... Kocka cislo 498: 995 Kocka cislo 499: 997 Kocka cislo 500: 999Analýza: Deklarujeme pole Rodina, které obsahuje 500 ukazatelů na objekty KOCKA.
KOCKA *Rodina = new KOCKA[500];deklaruje Rodina jako ukazatel na první polozku v poli 500 koček.
Lze například zapsat: KOCKA *Rodina = new KOCKA[500]; KOCKA *pKocka=Rodina; //pKocka ukazuje na Rodina[0] pKocka->ZadatVek(10);= //nastavit Rodina[0] na 10 pKocka++; //postoupit na Rodina[1] pKocka->ZadatVek(20); //nastavit Rodina[1] na 20
1: KOCKA RodinaJedna[500]; 2: KOCKA * RodinaDve[500]; 3: KOCKA * RodinaTri=new KOCKA[500];RodinaJedna je pole 500 kocek.
KOCKA Rodina[50];je Rodina ukazatel na &Rodina[0], což je adresa prvního prvku pole Rodina. Je povoleno pracovat s názvy polí jako s konstantními ukazateli a naopak. Proto je Rodina + 4 platným způsobem přistupu k datům v Rodina[4].
// Pole na volném úložišti
#include <iostream>
class KOCKA
{
public:
KOCKA() { jejiVek = 1; jejiVaha=5; }
~KOCKA();
int ZjistitVek() const { return jejiVek; }
int ZjistitVahu() const { return jejiVaha; }
void ZadatVek(int vek) { jejiVek = vek; }
private:
int jejiVek;
int jejiVaha;
};
KOCKA :: ~KOCKA()
{
// cout << "Zavolán destruktor!\n";
}
int main()
{
KOCKA * Rodina = new KOCKA[500];
int i;
for (i = 0; i < 500; i++)
{
Rodina[i].ZadatVek(2*i +1);
}
for (i = 0; i < 500; i++)
{
std::cout << "Kocka cislo " << i+1 << ": ";
std::cout << Rodina[i].ZjistitVek() << std::endl;
}
delete [] Rodina;
return 0;
}
Analýza: Celé pole se vytvoří ve volném úložišti pomocí volání new KOCKA[500].
cout << "Ahoj, svete.\n";Deklarovat a inicializovat řetězec C můžeme stejným způsobem jako kterékoliv jiné pole.
char Pozdrav[]=['A', 'h', 'o', 'j', ',', ' ', 's','v','e','t','e','.','\0'];Poslední znak je znak null, který mnoho funkcí jazyka C++ rozpoznává jako ukončovač řetězce ve stylu jazyka C.
char Pozdrav[]="Ahoj, svete.";Místo jednotlivých znaků vymezených apostrofy, oddělených čárkami a uzavřených ve složených závorkách je řetezec vymezený uvozovkami, bez čárek a bez složených závorek. Nemusí se přidávat znak null, je doplněn kompilátorem.
//Vyrovnávací paměť pole znaků
#include <iostream>
int main()
{
char buffer[80];
std::cout << "Zadejte retezec: ";
std::cin >> buffer;
std::cout << "Zde mame buffer: " << buffer << std::endl;
return 0;
}
Zadejte retezec: Ahoj, svete Zde mame buffer: Ahoj,
Analýza: Program vykazuje dva problémy. Jestliže uživatel zadá více než 79 znaků, pak cin zapíše za konec bufferu. Pokud uživatel zadá nějakou mezeru, cin ji považuje za konec řetězce a ukončí zápis do vyrovnávací paměti. Pozn.: Je součástí syntaxe cin, aby zapsal ukončovací nulu do vyrovnávací paměti po zadání řetězce.Pro řešení těchto dvou problémů lze použít speciální metodu cin zvanou get().
//Použití cin.get()
#include <iostream>
using namespace std;
int main()
{
char buffer[80];
cout << "Zadejte retezec: ";
cin.get(buffer, 79); // převzít až 79 znaků nebo po nový řádek
cout << "Zde mame buffer: " << buffer << endl;
return 0;
}
Zadejte retezec: Ahoj, svete Zde mame buffer: Ahoj, svete
Analýza: Prvním parametrem metody cin.get() je námi naplněný buffer. Maximální počet přebíraných znaků je 79, aby zbylo místo pro ukončovací nulu. Ukončovací znak není potřeba zadávat, protože znak ukončení řádku vyhovuje.
//Použití strcpy()
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char Retezec1[] = "Zadny clovek neni ostrov";
char Retezec2[80];
strcpy(Retezec2,Retezec1);
cout << "Retezec1: " << Retezec1 << endl;
cout << "Retezec2: " << Retezec2 << endl;
return 0;
}
Retezec1: Zadny clovek neni ostrov Retezec2: Zadny clovek neni ostrov
Analýza: strcpy(cíl, zdroj); zkopíruje řetězec zdroj do cíl. Pokud je zdroj větší než cíl, dojde k zápisu za konec vyrovnávací paměti.strncpy() - kopíruje do cílového bufferu až po první znak null nebo po nejvyšší zadaný počet znaků.
// Použití strncpy()
#include <iostream>
#include <string.h>
int main()
{
const int MaxDelka = 80;
char Retezec1[] = " Zadny clovek neni ostrov";
char Retezec2[MaxDelka+1];
strncpy(Retezec2,Retezec1,MaxDelka);
std::cout << "Retezec1: " << Retezec1 << std::endl;
std::cout << "Retezec2: " << Retezec2 << std::endl;
return 0;
}
Retezec1: Zadny clovek neni ostrov Retezec2: Zadny clovek neni ostrov
Analýza: strncpy(cíl, zdroj, maxDelka); Buffer Retezec2 je deklarovaný pro MaxDelka+1 znak. Znak navíc je pro nulu, kterou jak strcpy() tak i strncpy() automaticky přidávají na konec řetězce.
// Použití třídy Retezec
#include <iostream>
#include <string.h>
using namespace std;
// Základní řetězcová třída
class Retezec
{
public:
//10
// Konstruktory
Retezec();
Retezec(const char *const);
Retezec(const Retezec &);
~Retezec();
// Přetížené operátory
char & operator[](unsigned short odsazeni);
char operator[](unsigned short odsazeni) const;
Retezec operator+(const Retezec&);
//20
void operator+=(const Retezec&);
Retezec & operator= (const Retezec &);
// Obecné přístupové funkce
unsigned short PrevzitDelku()const { return jehoDelka; }
const char * PrevzitRetezec() const { return jehoRetezec; }
private:
Retezec (unsigned short); // Soukromý konstruktor
char * jehoRetezec;
//30
unsigned short jehoDelka;
};
// Výchozí konstruktor vytváří řetězec o délce 0 bajtů
Retezec::Retezec()
{
jehoRetezec = new char[1];
jehoRetezec[0] = '\0';
jehoDelka=0;
}
//40
// Soukromý (pomocný) konstruktor používaný pouze
// metodami třídy k vytvoření nového řetězce
// požadované velikosti. Naplněný nulami.
Retezec::Retezec(unsigned short len)
{
jehoRetezec = new char[len+1];
for (unsigned short i = 0; i<=len; i++)
jehoRetezec[i] = '\0';
jehoDelka=len;
//50
}
// Převádí znakové pole na Retezec
Retezec::Retezec(const char * const cRetezec)
{
jehoDelka = strlen(cRetezec);
jehoRetezec = new char[jehoDelka+1];
for (unsigned short i = 0; i<jehoDelka; i++)
jehoRetezec[i] = cRetezec[i];
jehoRetezec[jehoDelka]='\0';
//60
}
// Kopírovací konstruktor
Retezec::Retezec (const Retezec & rhs)
{
jehoDelka=rhs.PrevzitDelku();
jehoRetezec = new char[jehoDelka+1];
for (unsigned short i = 0; i<jehoDelka;i++)
jehoRetezec[i] = rhs[i];
jehoRetezec[jehoDelka] = '\0';
//70
}
// Destruktor, uvolňuje přiřazenou paměť
Retezec::~Retezec ()
{
delete [] jehoRetezec;
jehoDelka = 0;
}
// Operátor rovno, uvolňuje existující paměť
//80
// a pak kopíruje řetězec a délku
Retezec& Retezec::operator=(const Retezec & rhs)
{
if (this == &rhs)
return *this;
delete [] jehoRetezec;
jehoDelka=rhs.PrevzitDelku();
jehoRetezec = new char[jehoDelka+1];
for (unsigned short i = 0; i<jehoDelka;i++)
jehoRetezec[i] = rhs[i];
//90
jehoRetezec[jehoDelka] = '\0';
return *this;
}
// Nekonstantní operátor odsazení, vrací
// odkaz na znak, aby jej bylo možné
// změnit!
char & Retezec::operator[](unsigned short odsazeni)
{
if (odsazeni > jehoDelka)
//100
return jehoRetezec[jehoDelka-1];
else
return jehoRetezec[odsazeni];
}
// Konstantní operátor odsazení pro použití
// s konstantními objekty (viz kopírovací konstruktor!)
char Retezec::operator[](unsigned short odsazeni) const
{
if (odsazeni > jehoDelka)
//110
return jehoRetezec[jehoDelka-1];
else
return jehoRetezec[odsazeni];
}
// Vytváří nový řetězec přidáním aktuálního
// řetězce k rhs
Retezec Retezec::operator+(const Retezec& rhs)
{
unsigned short celkovaDelka = jehoDelka + rhs.PrevzitDelku();
//120
Retezec docasny(celkovaDelka);
unsigned short i;
for ( i= 0; i<jehoDelka; i++)
docasny[i] = jehoRetezec[i];
for (unsigned short j = 0; j<rhs.PrevzitDelku(); j++, i++)
docasny[i] = rhs[j];
docasny[celkovaDelka]='\0';
return docasny;
}
//130
// Mění aktuální řetězec, nevrací nic
void Retezec::operator+=(const Retezec& rhs)
{
unsigned short rhsDelka = rhs.PrevzitDelku();
unsigned short celkovaDelka = jehoDelka + rhsDelka;
Retezec docasny(celkovaDelka);
unsigned short i;
for (i = 0; i<jehoDelka; i++)
docasny[i] = jehoRetezec[i];
for (unsigned short j = 0; j<rhs.PrevzitDelku(); j++, i++)
//140
docasny[i] = rhs[i-jehoDelka];
docasny[celkovaDelka]='\0';
*this = docasny;
}
int main()
{
Retezec s1("pocatecni test");
cout << "S1:\t" << s1.PrevzitRetezec() << endl;
//150
char * docasny = "Ahoj, svete";
s1 = docasny;
cout << "S1:\t" << s1.PrevzitRetezec() << endl;
char docasnyDve[20];
strcpy(docasnyDve,"; jsem tu rad!");
s1 += docasnyDve;
cout << "docasnyDve:\t" << docasnyDve << endl;
cout << "S1:\t" << s1.PrevzitRetezec() << endl;
//160
cout << "S1[4]:\t" << s1[4] << endl;
s1[4]='x';
cout << "S1:\t" << s1.PrevzitRetezec() << endl;
cout << "S1[999]:\t" << s1[999] << endl;
Retezec s2(" Jiny retezec");
Retezec s3;
s3 = s1+s2;
cout << "S3:\t" << s3.PrevzitRetezec() << endl;
//170
Retezec s4;
s4 = "Proc tohle funguje?";
cout << "S4:\t" << s4.PrevzitRetezec() << endl;
return 0;
}
S1: pocatecni test S1: Ahoj, svete docasnyDve: ;jsem tu rad! S1: Ahoj, svete;jsem tu rad! S1[4]: , S1: Ahojx svete;jsem tu rad! S1[999]: ! S3: Ahojx svete;jsem tu rad! Jiny retezec S4: Proc tohle funguje?
Analýza: Řádky 7-31 jsou deklaracemi jednoduché třídy Retezec.
11-13 obsahují tři konstruktory: výchozí konstruktor, kopírovací konstruktor a konstruktor přebírající existující řetězec ukončený znakem null (ve stylu jazyka C).
Třída Retezec přetěžuje operátor odsazení [], operátor plus + a operátor plus-rovno +=.
Operátor odsazení je přetížený dvakrát: jednou jako konstantní funkce vracející nějaký znak a jednou jako nekonstantní funkce vracející odkaz na znak.
Nekonstantní verze se používá v příkazech jako: NejakyRetezec[4]='x'; jak je patrné z řádku 161. To umožňuje přímý přístup ke každému znaku v řetězci. Vrací se odkaz na daný znak, takže s ním volající funkce může manipulovat.
Konstantní veetze se používá, když se jedná o přístup ke konstantnímu objektu Retezec, jako například v implementaci kopírovacího konstruktoru (řádek 63).
Všimněte si, že se přistupuje k rhs[i], přičemž však rhs je deklarovaný jako const String &.
Není povoleno přistupovat k tomuto objektu pomocí nekonstantní členské funkce. Proto je zapotřebí přetížit operátor odazení konstantní přístupovou funkcí.
Kdyby byl vracený objekt velký, pak by bylo vhodné deklarovat návratovou hodnotu jako konstantní odkaz. Protože je však znak jen jediným bajtem, nemá to žádný smysl.
Výchozí konstruktor je implementován na řádcích 33-39.
Vytváří řetězec, jehož délka je 0. Je konvencí této třídy Retezec hlásit délku bez ukončovacího znaku null. Tento výchozí řetezec obsahuje pouze ukončovací nulu.
Kopírovací konstruktor 63-70 nastavuje délku nového řetězce na délku existujícího řetězce - plus 1 pro ukončovací znak null. Kopíruje jednotlivé znaky z existujícího řetězce do nového řetězce a nový řetězec pak ukončuje nulou.
Řádky 53-60 implementují konstruktor, který přebírá existující řetězec ve stylu C. Tento konstruktor se podobá kopírovacímu konstruktoru. Délka existujícího řetězce se určí voláním standardní funkce strlen() třídy String.
Na řádku 28 je další konstrukor, Retezec(unsigned short) deklarovaný jako soukromá členská funkce. Cílem návrháře této třídy je, aby žádná klientská třída nikdy nemohla vytvořit řetězec zadané délky. Tento konstruktor existuje jen proto, aby pomáhal podle potřeby internímu vytváření řetězců například operátorem += na řádku 130.
Konstruktor Retezec(unsigned short) naplňuje všechny členy svého pole hodnotami null. Proto smyčka for kontroluje i<=delka a nikoli <delka
Destruktor implementovaný na řádcích 73-77 odstraňuje znakový řetězec udržovaný třídou. Nezapoměňte u volání operátorů uvést hranaté závorky, aby došlo k odstranění všech členů pole a nikoli jen toho prvního.
Operátor přiřazení nejprve zkontroluje, zda je pravá strana přiřazení stejná jako levá strana. Není-li, pak se odstraní aktuální řetězec a nová řetězec se vytvoří a zkopíruje na místo. Vracen je odkaz, aby bylo možné vytvbářet podobná přiřazení: Retezec=Retezec2=Retezec3
Operátor odsazení je pretížen dvakrát. Základní kontrola hranic se vykonává v obou prípadech. Pokusí-li se uživatel o prístup k nejakému znaku na míste za koncem pole, vrátí se poslední znak, tedy delka-1.
Rádky 117-127 implementují operátor plus + jako operátor spojení. Je pohodlné mít možnost zapsat: Retezec3=Retezec1 + Retezec2; a obdržet Retezec3 jako spojení zbývajících dvou retezcu. Abychom toho dosáhli, pocítá funkce operátoru plus kombinovanou délku obou retezcu a vytvárí docasný retezec docasny. Tím se volá soukromý konstruktor, který prebírá celé císlo a vytvárí retezec naplnení nulami. Znaky null se pak nahradá osbsahem obou retezcu. Nejprve se zkopíruje levý retezec (*this) a pak se zkopíruje pravý retezec (rhs).
První smycka for prochází retezcem vlevo a pridává jednotlivé znaky do nového retezce.
Druhá smycka for prochází pravou stranou. Všimnete si, že i pokracuje v pocítání místa nového retezce, i když j již prochází retezcem rhs.
Operátor plus vrací retezec docasny hodnotou, která se priradí retezci na levé strane prirazení (Retezec1). Operátor += pracuje s existujícím retezcem, tedy s levou stranou príkazu Retezec+=Retezec2. Funguje stejne jako operátor plus, jenom se hodnota docasny priradí aktuálnímu retezci (*this=docasny) na rádku 142.
Funkce main() 145-175 funguje jako testovací program pro tuto trídu.
147 - vytvárí objekt Retezec pomocí konstruktoru, který prebírá retezec ukoncený nulou ve stylu jazyka C.
148 - tiskne jeho obsah pomocí prístupové funkce PrevzitRetezec().
150 - vytvárí další retezec ve stylu C. 151 - testuje operátor prirazení.
152 - tiskne výsledek. 154 - vytvárí tretí retezec ve stylu C nazvaný docasnyDve.
155 - volá strcpy() aby došlo k naplnení bufferu znaky ";jsem tu rad!"
156 - volá operátor += a pripojuje docasnyDve k existujícímu retezci s1.
158 - tiskne výsledek
160 - zjištuje a tiskne pátý znak retezce s1
161 - priradí novou hodnotu na toto místo. Tím se zavolá nekonstantní operátor odsazení [].
162 - tiskne výsledek, který skutecne zachycuje zmenu hodnoty.
164 - se pokouší o prístup ke znaku za koncem pole. Vrátí se poslední znak pole, presne jak je požadováno
166-167 - vytvárejí dva další objekty Retezec
168 - volá operátor prictení.
169 - tiskne výsledek
171 - vytvárí nový objekt Retezec nazvaný s4.
172 - volá operátor prirazení.
173 - tiskne výsledek
21 - operátor prirazení je definován pro prevzetí konstantního odkazu na Retezec, zde však program predává retezec ve stylu jazyka C. Proc je to možné?
Odpovedí je, že kompilátor ocekává Retezec, ale dostane se mu znakové pole. Proto zjistí, zda muže vytvorit Retezec z toho, co má k dispozici. Na rádku 12 je deklarován konstruktor, který vytvárí retezce ze znakových polí. Kompilátor tedy vytvorí docasný objekt Retezec z daného znakového pole a predá jej operátoru prirazení. To se oznacuje za implicitní prevod neboli povýšení. Pokud bychom nedeklarovali konstruktoru, který prebírá pole znaku, toto prirazení by zpusobilo chybu kompilace.
// ***********************************************
// SOUBOR: Výpis 13.13
//
// ÚČEL: Ukázat propojený seznam
// POZNÁMKY:
//
// COPYRIGHT: Copyright (C) 1998 Liberty Associates, Inc.
// All Rights Reserved
//
// Ukazuje objektově orientovaný přístup k propojeným
// seznamům. Seznam deleguje činnost uzlu. Uzel je
// abstraktní datový typ. Používají se tři typy uzlů:
// uzly hlavy, uzly ocasu a vnitřní uzly. Data
// obsahují pouze vnitřní uzly.
//
// Třída Data je vytvořena, aby sloužila jako objekt
// k uchování v daném propojeném seznamu.
//
// ***********************************************
#include <iostream>
using namespace std;
enum { kJeMensi, kJeVetsi, kJeStejny};
// Třída Data pro vložení propojeného seznamu. Každá
// třída v propojeném seznamu musí podporovat dvě metody:
// Zobrazit (zobrazí hodnotu) a
// Porovnat (vrátí relativní pozici)
//30
class Data
{
public:
Data(int hodnota):mojeHodnota(hodnota){}
~Data(){}
int Porovnat(const Data &);
void Zobrazit() { cout << mojeHodnota << endl; }
private:
int mojeHodnota;
//40
};
// Porovnat se používá k určení, kam do seznamu
// určitý objekt patří.
int Data::Porovnat(const Data & jinaData)
{
if (mojeHodnota < jinaData.mojeHodnota)
return kJeMensi;
if (mojeHodnota > jinaData.mojeHodnota)
return kJeVetsi;
//50
else
return kJeStejny;
}
// Dopředné deklarace
class Uzel;
class UzelHlavy;
class UzelOcasu;
class VnitrniUzel;
//60
// ADT představující objekt uzlu v seznamu
// Každá odvozená třída musí překrýt Vlozit a Zobrazit
class Uzel
{
public:
Uzel(){}
virtual ~Uzel(){}
virtual Uzel * Vlozit(Data * taData)=0;
virtual void Zobrazit() = 0;
private:
//70
};
// Toto je uzel, který obsahuje vlastní objekt
// V tomto případě jde o objekt typu Data
// Uvidíme, jak to učinit obecněji, až si budeme
// povídat o šablonách
class VnitrniUzel: public Uzel
{
public:
VnitrniUzel(Data * taData, Uzel * dalsi);
//80
~VnitrniUzel(){ delete mujDalsi; delete mojeData; }
virtual Uzel * Vlozit(Data * taData);
// Delegovat!
virtual void Zobrazit() { mojeData->Zobrazit(); mujDalsi->Zobrazit();}
private:
Data * mojeData; // samotná Data
Uzel * mujDalsi; // ukazuje na další uzel v propojeném seznamu
};
//90
// Konstruktor jenom inicializuje
VnitrniUzel::VnitrniUzel(Data * taData, Uzel * dalsi):
mojeData(taData),mujDalsi(dalsi)
{
}
// Základ celého seznamu
// Když do seznamu vložíte nový objekt,
// předá se uzlu, který určí jeho pozici
// a vloží jej do seznamu
//100
Uzel * VnitrniUzel::Vlozit(Data * taData)
{
// Je ten nový hoch větší nebo menší než já?
int vysledek = mojeData->Porovnat(*taData);
switch(vysledek)
{
// Je li stejný jako já, pak podle konvence patří přede mě
//110
case kJeStejny: // projít dál
case kJeVetsi: // nová Data patří přede mě
{
VnitrniUzel * datovyUzel = new VnitrniUzel(taData, this);
return datovyUzel;
}
// Je větší než já, takže jej předáme dalšímu
// uzlu a ponecháme na NĚM, ať se stará.
case kJeMensi:
//120
mujDalsi = mujDalsi->Vlozit(taData);
return this;
}
return this; // naplnit MSC
}
// Uzel ocasu je jen hlídka
class UzelOcasu : public Uzel
//130
{
public:
UzelOcasu(){}
~UzelOcasu(){}
virtual Uzel * Vlozit(Data * taData);
virtual void Zobrazit() { }
private:
};
//140
// Pokud nějaká Data přijdou až ke mně, musí se vložit
// přede mě, protože já jsem ocas a za mnou už není NIC.
Uzel * UzelOcasu::Vlozit(Data * taData)
{
VnitrniUzel * datovyUzel = new VnitrniUzel(taData, this);
return datovyUzel;
}
// Uzel hlavy neobsahuje žádná Data, jenom
//150
// ukazuje na úplný začátek seznamu
class UzelHlavy : public Uzel
{
public:
UzelHlavy();
~UzelHlavy() { delete mujDalsi; }
virtual Uzel * Vlozit(Data * taData);
virtual void Zobrazit() { mujDalsi->Zobrazit(); }
private:
Uzel * mujDalsi;
//160
};
// Jakmile se vytvoří hlava, vytvoří se
// také ocas.
UzelHlavy::UzelHlavy()
{
mujDalsi = new UzelOcasu;
}
// Před hlavou nic není, takže Data
//170
// jen předáme dalšímu uzlu.
Uzel * UzelHlavy::Vlozit(Data * taData)
{
mujDalsi = mujDalsi->Vlozit(taData);
return this;
}
// Mám všechny zásluhy a přitom nic nedělám.
class PropojenySeznam
{
//180
public:
PropojenySeznam();
~PropojenySeznam() { delete mojeHlava; }
void Vlozit(Data * taData);
void ZobrazitVse() { mojeHlava->Zobrazit(); }
private:
UzelHlavy * mojeHlava;
};
// Při zrození vytvořím uzel hlavy.
//190
// Ten vytvoří uzel ocasu, takže
// prázdný seznam ukazuje na hlavu, která
// ukazuje na ocas a mezi nimi nic není.
PropojenySeznam::PropojenySeznam()
{
mojeHlava = new UzelHlavy;
}
// Deleguji, deleguješ, delegujeme
void PropojenySeznam::Vlozit(Data * pData)
//200
{
mojeHlava->Vlozit(pData);
}
// Testovací program
int main()
{
Data * pData;
int hodnota;
PropojenySeznam ps;
//210
// Požádat uživatele a zadání nějakých hodnot
// a vložit je do seznamu.
for (;;)
{
cout << "Jaka hodnota? (konec = 0): ";
cin >> hodnota;
if (!hodnota)
break;
pData = new Data(hodnota);
//220
ps.Vlozit(pData);
}
// Nyní projít seznamem a zobrazit Data
ps.ZobrazitVse();
return 0; // ps vypadne z oboru platnosti a je zrušen!
}
Pozn: číslo řádku v komentáři náleží řádku pod tímto číslem!
Jaka hodnota? (konec = 0): 5 Jaka hodnota? (konec = 0): 8 Jaka hodnota? (konec = 0): 3 Jaka hodnota? (konec = 0): 9 Jaka hodnota? (konec = 0): 2 Jaka hodnota? (konec = 0): 10 Jaka hodnota? (konec = 0): 0 2 3 5 8 9 10
Analýza: Nejprve deklarujeme výctovou konstantu, která poskytuje tri konstantní hodnoty:kJeMensi, kJeVetsi, kJeStejny. Každý objekt, který muže být obsažen v tomto propojeném seznamu, musí podporovat metodu Porovnat(). Tyto konstanty budou výslednou hodnotou vrácenou metodou Porovnat().
30-39 Vytvárí trídu Data
41-51 implementace metody Porovnat()
Objekt Data obsahuje nejakou hodnotu a dokáže se porovnat s jinými objekty Data. Rovnež podporuje metodu Zobrazit() sloužící k zobrazení hodnoty daného objektu Data.
Pro pochopení si projdeme príklad, který se seznamem pracuje.
203 - deklarace ovládacího programu
206 - deklarace ukazatele na objekt Data
208 - definice místního propojeného seznamu
Když se vytvorí tento seznam, zavolá se konstruktor na rádku 192. Jedinou prací konstruktoru je alokovat objekt UzelHlavy a priradit adresu tohoto objektu ukazateli obsaženému v seznamu na rádku 185.
Toto alokování UzelHlavy zavolá konstruktor UzelHlavy na rádcích 163-166. Tím se dále alokuje UzelOcasu a jeho adresa se priradí ukazateli mujDalsi uzlu hlavy. Vytvorení UzelOcasu volá konstruktor UzelOcasu na rádku 131, který nic nedelá. Proto prostým alokováním seznamu na zásobníku dojde k vytvorení daného seznamu, k vytvorení uzlu hlavy a ocasu a k jejich propojení:
Propojený seznam ---> Uzel hlavy ---> Uzel ocasu
212 - zacíná nekonecná smycka. Uživatel zadává hodnoty, které mají být pridány do seznamu. Zadávání se ukoncuje vložením 0.
Není-li vložená hodnota nulová, pak na řádku 218 je vytvoren nový objekt Data a řádku 219 je vložen do seznamu. Predpokládejme, že uživatel zadal 15. Tím dojde k zavolání metody Vlozit na rádku 198.
Propojený seznam okamžite deleguje zodpovednost za vložení daného objektu svému uzlu hlavy. Tím se zavolá metoda Vlozit na rádku 170. Uzel hlavy okamžite predá zodpovednost uzlu, na který ukazuje mujDalsi. V tomto prípade ukazuje na uzel ocasu. Proto dojde k vyvolání metody Vlozit na rádku 142. Metoda UzelOcasu:Vlozit ví, že objekt, který jí byl predán, musí vložit bezprostredne pred sebe. To znamená, že nový objekt se bude nacházet v seznamu bezprostredne pred uzlem ocasu. Proto na rádku 144 vytvorí nový objekt VnitrniUzel, kterému predá Data a ukazatel na sebe sama. Tím dojde k zavolání konstruktoru objektu VnitrniUzel, jenž je uvedený na rádku 90.
Konstruktor VnitrniUzel jenom inicializuje svuj další ukazatel Data, adresou jemu predaného objektu Data a inicializuje svuj ukazatel mujDalsi adresou uzlu, která mu byla predána. V tomto prípade bude odkazovaným uzlem uzel ocasu.(uzel ocasu predává svuj vlastní ukazatel this)
Protože byl nyní vytvoren VnitrniUzel, adresa tohoto vnitrního uzlu se priradí ukazateli datovyUzel na rádku 144 a tato adresa je dále vrácena z metody UzelOcasu::Vlozit(). To nás vrací do UzelHlavy::Vlozit(), kde adresa daného objektu VnitrniUzel priradá ukazateli propojeného seznamu, kde dojde na rádku 200 k jeho odhození (nic se nedelá, protože propojený seznam již zná adresu uzlu hlavy).
Proc se trápit s vracením adresy, která se nepoužije? Metoda Vlozit je deklarovaná v bázové tríde Uzel. Návratová hodnota je vyžadována dalšími implementacemi. Zmeníte-li návratovou hodnotu UzelHlavy::Vlozit(), obdržíte chyby kompilace; jednodušší je proste vrátit UzelHlavy a nechat propojený seznam, at tuto adresu odhodí.
Co se stalo? Data byla vložena do seznamu. Seznam je předal hlavě. Hlava je slepě předala tomu objektu, na který zrovna ukazovala. V tomto případě ukazovala hlava na ocas. Ocas okamažitě vytvořil nový vnitřní uzel a inicializoval jej tak, aby ukazoval na ocas. Ocas pak vrátil adresu tohoto nového uzlu hlavě, která upravila svůj ukazatel mujDalsi tak, aby se přesměroval na tento nový uzel.
Po vložení prvního prvku se obnoví řízení programu na řádku 214. Předpokládejme vložení hodnoty 3.
Dojde k vytvoření nového objektu Data na řádku 218 a vložení do seznamu na řádku 219.
Na řádku 200 znovu seznam předá Data svému UzelHlavy. Metoda UzelHlavy::Vlozit() zase předá novou hodnotu objektu, na který právě ukazuje mujDalsi. Nyní směřuje na objekt Data s hodnotou 15.
Dojde tedy k zavolání metody VnitrniUzel::Vlozit() na řádku 99.
Na řádku 103 použije VnitrniUzel svuj ukazatel mojeData a řekne svému objektu Data (s 15) aby zavolal svou metodu Porovnat(), které předá nový objekt Data (s 3). Tak dojde k zavolání metody Porovnat() na řádku 43.
Dojde k porovnání obou hodnot, a protože mojeHodnota bude 15 a jinaData.mojeHodnota bude 3 stane se vrácenou hodnotou kJeVetsi. To způsobí přeskok programu na řádek 1112.
Pro nový objekt Data se vytvoří nový VnitrniUzel. Tento nový uzel bude ukazovat na aktuální objekt VnitrniUzel a adresa nového objektu VnitrniUzel se vrátí z metody VnitrniUzel::Vlozit() do UzelHlavy. Proto se tento nový uzel, hodnota jehož objektu je menší než hodnota objektu aktuálního uzlu, vloží do seznamu před aktuální uzel.
Při třetím vkládání vloží uživatel 8.
Výsledkem porovnání s prvním uzlem (s 3) bude kJeMensi. To způsobí odskok VnitrniUzel::Vlozit() na řádek 119. Místo vytvoření nového uzlu a jeho vložení tak daný VnitrniUzel předá Data metodě Vlozit objektu, na který právě směřuje ukazatel mujDalsi. V tomto případě dojde k zavolání Vlozit objektu VnitrniUzel, jehož objekt má hodnotu 15.
Znovu dojde k porovnání a následně k vytvoření nového objektu VnitrniUzel. Tento nový VnitrniUzel bude ukazovat na VnitrniUzel, hodnotou jehož objektu Data je 15, a jeho adresa se předá zpět uzlu VnitrniUzel, jehož objekt Data má hodnotu 3, jak je patrné z řádku 119.
Cílovým efektem je vložení nového uzlu na správnou pozici v seznamu.
Při tomto OOP je každému jednotlivému objektu dána úzká a dobře definovaná sada zodpovědností.
Seznam odpovídá za správu uzlu hlavy.
Uzel hlavy předá nová data objektu, na který právě ukazuje, ať se jedná o cokoli.
Uzel ocasu vytváří nový uzel a vkládá do něj předaná data. Ví jen jedinou věc: Když se dostala až ke mně, musí se vložit přede mě.
Vnitřní uzly jsou složitější - požadují porovnání existujícího objektu s novým objektem. Podle výsledku buď objekt vloží nebo předají dál.