260 likes | 386 Views
ÚVOD DO C++ 4. Pole, ukazatele a odkazy. 4. Pole objektů 4.1.Ukazatelé na objekty, použití 4.2. Ukazatel this 4.3. Dynamická alokace paměti - new - delete 4.4. Inicializace dynamicky alokovaného objektu
E N D
ÚVOD DO C++ 4 Pole, ukazatele a odkazy
4. Pole objektů 4.1.Ukazatelé na objekty, použití 4.2. Ukazatel this 4.3. Dynamická alokace paměti - new - delete 4.4. Inicializace dynamicky alokovaného objektu 4.5. Dynamická alokace jednorozměrného pole 4.6. Odkazy v C++
Pole objektů Objekty jsou proměnné obdobných vlastností jako v jazyku C. Pole objektů je určeno - velikostí pole - bázovým typem pole ( typem je třída ) Syntaxe: Deklarace pole objektů : Class Trida { int a; public: void nastav_a ( int n) { …… .void predej_a ( ) { ……….. } ; Int main() { Tridapole_objektu[5]; // deklarave pole objektů o 5_ti prvcích ……. }
Do pole objektů je zapisována řídící proměnná cyklu pomocí fce nastav_a() a opět vypsána : */ #include<iostream> using namespace std; class Vzorek { // použit implicitní konstruktor a destruktor int a; public: void nastav_a( int n) { a=n;} int vypis_a() { return a;} }; int main() { int i; Vzorek pole_objektu[4]; //Deklarace pole objektů // Zápis do pole objektů: for( i=0;i<4; i++) pole_objektu [ i ].nastav_a( i ); /* Členská funkce nastav_a( i ); je volána pro každý prvek pole */ //Výpis pole objektů: for( i=0; i<4; i++){ cout << pole_objektu[i].vypis_a( ) << "\n"; } system(“pause”); return 0; }
Inicializace pole objektů. Podmínkou pro provedení inicializace je explicitní konstruktor deklarovaný v typové třídě. Příklad inicializace pole objektů: class Vzorek { int a; public: // explicitní konstruktor: Vzorek ( int n) { a= n; } //členská funkce: int predej_a() { return a; } }; int main() { //Deklarace jednorozměrného pole s inicializací: Vzorek pole_objektu[4] ={ -1, -2, -3, -4 } ; int i; cout<<"Vypis pole objektu :\n"; for( i=0; i<4; i++ ){ cout << pole_objektu[i].predej_a() << ' '; } cout << "\n"; systém(“pause“); return 0; }
Vícerozměrná pole objektu. Deklarace je stejná jako v C. Příklad dvojrozměrného pole a jeho inicializace : class Vzorek { int a; public: //konstruktor - podmínka pro provedení inicializace : Vzorek ( int n ) { a=n;} //členská funkce: int predej_a() { return a ;} }; int main() { //Deklarace dvojrozměrného pole s inicializací : Vzorek pole_objektu[4][2] = { 1, 2, 3, 4, 5, 6, 7, 8, }; int i; cout << "Vypis pole_objektu[4][2]:\n\n"; for( i=0; i<4; i++) { cout << pole_objektu[i][0].predej_a() << ' '; cout << pole_objektu[i][1].predej_a() << "\n"; } systém(“pause“); return 0; }
Inicializace pole v případě použití konstruktoru s více parametry. Přebírá-li konstruktor více než jeden argument,je nutné k inicializaci pole použít při inicializaci standardní dlouhou formu. Tento formát inicializace lze použít i když objekt přebírá pouze jediný argument. Zkrácená forma je však v tomto případu pohodlnější. #include<iostream> using namespace std; class Vzorek { int a, b; public: //konstruktor : Vzorek ( int n, int m ) { a=n; b=m;} //členské funkce : int predej_a() { return a;} int predej_b() { return b;} };
int main() { /* Inicializace je provedena přímým voláním konstruktoru Vzorek(n,m)*/ Vzorek pole_objektu[4][2] = { Vzorek(1, 2),Vzorek(3, 4), Vzorek(5, 6),Vzorek(7, 8), Vzorek(9,10),Vzorek(11,12), Vzorek(13,14),Vzorek(15,16) }; int i; cout << "Vypis pole_objektu[4][2]:\n\n"; for( i=0; i<4; i++){ cout << pole_objektu[i][0].predej_a() << ' '; cout << pole_objektu[i][0].predej_b() << "\n"; cout << pole_objektu[i][1].predej_a() << ' '; cout << pole_objektu[i][1].predej_b() << "\n"; } systém(“pause“); return 0; }
4.1. Ukazatelé objektu - použití Objekty mohou být dosažitelnépomocí ukazatele na objekt. Adresu objektu získáme použítím adresního operátoru & Použití ukazatele na objekt vyžaduje nahradit operátor tečka operátorem šipka V C++ platí stejně i aritmetika ukazatelů jako v C. ( inkrementace ukazatele způsobí přechod na nasledující prvek pole objektů ). Příklad : #include<iostream> using namespace std; class Vzorek { int a, b; public: /*konstruktormá dva parametry (n,m), proto bude inicializace provedena dlouhou formou */ Vzorek( int n, int m) { a = n; b=m; } // členské funkce: int predej_a() { return a;} int predej_b() { return b;} };
int main() { //Při inicializaci je nutné použít dlouhou formu: Vzorek pole_objektu[4]= { Vzorek(1,2), Vzorek(3,4), Vzorek(5,6), Vzorek(7,8) }; int i; Vzorek *p_pole_objektu; p_pole_objektu = pole_objektu; /* název pole objektů obsahuje adresu prvního prvku pole objektů Výpis obsahu pole_objektu[ ] pomoci aritmetiky ukazatelů: */ cout<<"Vypis pole objektu pomoci aritmetiky "; cout << " ukazatelu\n"; for( i=0; i< 4; i++){ cout << p_pole_objektu -> predej_a() << ' '; cout << p_pole_objektu -> predej_b() << "\n"; /* inkrementace ukazatele - postup k dalšímu objektu */ p_pole_objektu ++; } system("Pause"); return 0; }
4.2. Ukazatel this ( pseudoproměnná ). Metoda musí být informována, s jakou instancí má pracovat. Proto je nestatickým metodám předáván implicitní, skrytý parametr ukazatel na aktuální instanci. Předává se automaticky včetně konstruktorů a destruktorů. Název pseudoproměnná získal this proto, že na rozdíl od proměnných, které definuje programátor, definuje pseudoproměnnou this překladač. Častěji má však název ukazatel this. Ukazatel this - je typu ukazatel na třídu, které je objekt instancí - ukazuje na aktuální objekt, kterému je zasílána zpráva V každém objektu je k dispozici ukazatel this na tento objekt a tento fakt si lze představit tak, že v každé třídě (př. class T_třída) je implicitně deklarován atribut T_třída *const this jehož hodnotu nemůžeme měnit !!!
Příklad.: Objekt2 . f1_členská( ); f1_členská( ) předává automaticky ukazatel this na Objekt2, který aktivoval volání, protože f1() - je funkce členská, - není spřátelená - není označená static. . Příklad požití při odkazování na atribut n třídy T. Parametr metody nastav( int n) zakryje viditelnost atributu stejného jména: class T_trida{ int n; public: void nastav( int n); ..... } //end class void T_trida:: nastav( int n ) { this ->n = n; }
#include<iostream> // demonstrace this #include<cstring> using namespace std; class Inventarni_zaznam { char polozka[80]; double cena_polozky; int skladovano_pocet; public: // konstruktor : Inventarni_zaznam( char *p_zdroj, double cena, int skl) { strcpy (this ->polozka, p_zdroj); // strcpy(polozka,p_zdroj); this ->cena_polozky =cena; // cena_polozky=cena; this ->skladovano_pocet = skl; //skladovano_pocet = skl; } //členská funkce: void zobraz(); }; // end třídy
//Definice členské funkce: pokračování void Inventarni_zaznam::zobraz() { cout << "Nazev polozky: " << this ->polozka <<"\n"; //cout << "Nazev polozky: " << polozka <<"\n"; cout << "Cena :" << this ->cena_polozky << "Kc"<<"\n"; //cout << "Cena :" <<cena_polozky << "Kc"<<"\n"; cout << "Pocet kusu na sklade: "; cout << this ->skladovano_pocet<<"\n"; //cout << skladovano_pocet<<"\n"; } int main() { Inventarni_zaznam objekt("Budvar",25.70,54); objekt.zobraz(); system("Pause"); return 0;
4.3. Dynamická alokace - new a delete Funkce malloc( ) a free( ), známé z jazyka C pro alokaci a uvolnění paměti lze použít i v C++. Navíc lze požít v C++ nový způsob přidělování a uvolňování paměti pomocí funkcí new - protějšek malloc( ) delete - protějšek free( ) Uvedené funkce lze použít bez omezení, ( jsou to standardní funkce), ale použití new a delete v jazyce C++ je - bezpečnější - pohodlnější. Výhody používání new a delete: - new automaticky přiděluje dostatek paměti pro uložení objektu daného typu a proto není nutné používat fcisizeof(). - automaticky vrací ukazatel určeného typu, není nutné provádět přetypování - obě fce, delete i new mohou být přetěžovány - není nutné vkládat < cstdlib > - umožňují inicializovat dynamicky alokovaný objekt
Dynamické proměnné v C++. Dynamické proměnné - paměť je jim přidělena až za běhu programu. Příkazem za běhu programu je jim přidělená paměť i uvolněna. Přidělení paměti - syntaxe : new typ_proměnné; Typ_proměnné - označení typu proměnné, pro kterou provádíme alokaci. Průběh: Operátor new vyčlení ve volné paměti místo potřebné pro alokaci daného typu a vrátí ukazatel na alokovanou paměť. Příklad alokace: int *p_i = new int ; Není-li dostatek paměti k provedení alokačního příkazu, vrátí new prázdný ukazatel nebo vygeneruje výjimku. Není-li vyjímka programem obsloužena, program bude ukončen. (závisí to na překladači ). Před použitím paměti je nutné otestovat hodnotu ukazatele, vráceného operátorem new, zda není prázdný ( selhání alokace ). Dynamicky přidělenou paměť pro proměnnou lze uvolnit použitím operátoru delete s argumentem ukazatel na přidělenou paměť. Syntaxe: delete p ;
#include<iostream> using namespace std; int main( ) { int *p_int; p_int = new int; // alokace paměti pro integer //TEST PŘED POUŽITÍM ALOKOVANÉ PAMĚTI : if( !p_int ) { cout << "Chyba pri alokaci pameti\n"; return 1; } //Zapis do alokovane pameti: *p_int = 100; cout << "Vypis hodnoty v alokovane pameti "; cout << "*p_int :"<< *p_int <<"\n"; //Uvolneni pameti: delete p_int; system("Pause"); return 0; }
Inicializace dynamicky alokovaných proměnných a objektů pomocí operátoru new. Syntaxe inicializace proměnné : ukazatel = new jméno_typu( parametr_inicializace ) Operátor new 1)vyčlení z volné paměti prostor pro vytvoření instance odpovídající typu proměnné 2) uloží do něj honotou uvedenou jako parametr_inicializace 3) vrátí adresu alokované paměti - viz ukazatel. Příklad: /* Program přidělí dynamicky paměť pro proměnnou typu integer a zároveň provede její inicializaci na hodnotu 9.*/ #include<iostream> using namespace std; int main() { int *p_int; p_int new int(9(); ………………. …………….
Příklad inicializace proměnné, new mápouze jeden parametr: int main() { int *p_int; //Alokace paměti pro proměnnou integer - inicializace hodnotou 9: cout<<"Alokace pameti pro integer byla provedena "; cout<<"prikazem p_int = new int( 9 );\n"; p_int = new int ( 9 ); if(!p_int ) { cout << "Chyba alokace pameti\n"; return 1; } cout << "Vypis hodnoty dereferenci *p_int :"; cout << *p_int << "\n"; // Uvolnění paměti delete p_int; systém(“pause”); return 0; }
Dynamická alokace objektu, inicializace s předáním více parametrů. Syntaxe inicializace objektu : ukazatel = new jméno_objetového_typu( parametry_inicializace ) parametry_inicializace – jsou parametry konstruktoru Příklad inicializace dynamicky vytvořeného objektu, dva inicializační parametry: #include<iostream> using namespace std; class Vzorek { int i,j; public: //konstruktor s parametry - inicializace: Vzorek( int a, int b) { i=a; j= b;} //clenska funkce: int predej_soucin() { return i*j; } int vypis_i () { return i;}; int vypis_j () { return j;}; }; pokračování
pokračování int main() { Vzorek *p_objekt; /*Alokace objektu s inicializaci: automaticky je volán konstruktor a ten provede inicializaci hodnotou 6 a 5 */ p_objekt = new Vzorek(6,5); //Test úspěšnosti alokace: if(!p_objekt) { cout << "Chyba alokace pameti\n"; return 1; } cout << "Soucin je : " << p_objekt -> predej_soucin(); //Uvolněni paměti: delete p_objekt; systém(“pause”); return 0; }
Dynamicka alokace pole (s použitím operátoru new). Pole, které je dynamicky alokováno, nelze při vytvoření inicializovat !!!! Syntaxe: Pro vytvoření jednorozměrného pole bude mít operátor new formát : ukazatel = new typ_pole [ velikost_pole ] ; Pro uvolnění tohoto dynamicky alokovaného pole bude mít operátor delete formát : a) pro starší překladače: delete [ velikost_pole ] ukazatel; b) pro moderního překladače : delete [ ]ukazatel; Překladač zavolá destruktor pro každý prvek pole.
Příklad - vytvoření dynamického pole objektů: /* Vytvoření dynamického pole 8-mi objektů, atributy objektů zapsány pomocí členské fonkce nastav_ij( ) : */ class Vzorek { int i,j; public: void nastav_ij( int a, int b){ i=a; j=b; } int predej_soucin() { return i*j;} }; int main() { Vzorek *p_pole; int i; p_pole = new Vzorek[ 8 ]; // zde provédt test úspěšnosti alokace //Zapis do pole objektů, hodnotaj = i : for( i=0; i< 8; i++){ p_pole[i].nastav_ij(I,I); } delete[] p_pole; getchar(); return 0; }
Příklad - předchozí verze programu doplněná o destruktor.Ten je volán pro každý prvek pole, kterým je objekt, tedy volán 10-krát. /* Vytvoření dynamického pole 10-ti objektů : když je uvolňováno pole, je postupně volán destruktor každého objektu t.j.10-krat */ #include<iostream> using namespace std; class Vzorek { int i,j; public: //destruktor: ~ vzorek() { cout <<" Destrukce..... \n"; } //členské funkce: void nastav_ij( int a, int b){ i=a; j=b; } int predej_soucin() { return i*j;} }; int main() { Vzorek *p_pole; int i; //Alokace pole: p_pole = new vzorek[10]; pokračování
//Zapis do pole, j = i : ……. //Vypis pole:……… …………. delete[] p_pole; //volá pro každýprvek pole, kterým je objekt, destruktor return 0; } Výpis programu: Soucin [ 0 ] = 0 Soucin [ 1 ] = 1 Soucin [ 2 ] = 4 . Soucin [ 9 ] = 81 destruktor je volán 10 krát : Destrukce..... Destrukce..... Destrukce..... Destrukce..... Destrukce..... Destrukce..... Destrukce..... Destrukce..... Destrukce..... Destrukce.....