Download pdf - Klase u c++

Transcript
Page 1: Klase u c++
Page 2: Klase u c++
Page 3: Klase u c++

3

SADRŽAJ

Uvod u programski jezik C++ 1.

Programski jezik C++ ............................................................................................ 91. Turbo C++ 2006 ......................................................................................................92. Prvi C++ program ............................................................................................... 123. Stil i forma pisanja C++ programa ................................................................. 154. Komentari u programu ...................................................................................... 16 5.

Varijable i konstante2.

Uvod.......................................................................................................................... 191. Int (Cjelobrojni tip) ............................................................................................ 192. Float (Realni tip).................................................................................................... 203. Char (Znakovni tip)............................................................................................. 244. Imenovane konstante i typedef deklaracija .............................................. 245. Enum konstante, long i double tipovi podataka .................................... 256. Kvalifikatori short, signed i signed................................................................. 267. Cast i sizeof operatori ....................................................................................... 278. Aritmetički operatori ......................................................................................... 289. Dodjela vrijednosti izrazima............................................................................ 3010. Strukture i unije podataka................................................................................ 3211.

Naredbe za ispis i unos podataka3.

Naredbe cout i cin .............................................................................................. 371. Naredbe printf i scanf ...................................................................................... 422. Ispis i unos podataka - Dodatak..................................................................... 473. Pretvorbe tipova podataka ............................................................................. 504.

Naredbe za grananje4.

Uvod ........................................................................................................................ 531. Relacijski i logički operatori ............................................................................ 532. Naredba if ............................................................................................................... 553. Uvjetni operator ?................................................................................................. 594. Naredba switch .................................................................................................... 605.

Page 4: Klase u c++

4

Programske petlje5.

Uvod.......................................................................................................................... 641. Petlja for .................................................................................................................. 642. Petlja while ............................................................................................................. 693. Petlja do-while ...................................................................................................... 704. Naredbe break i continue ................................................................................. 725. Naredba goto ........................................................................................................786.

Polja i pokazivači6.

Jedno i višedimenzionalna polja ................................................................... 761. Rad sa znakovima i znakovnim poljima ......................................................822. Sortiranje polja ..................................................................................................... 853. Pokazivači i reference ......................................................................................... 884. Dinamička alokacija i realokacija memorije ............................................... 925. Pokazivači na pokazivače ................................................................................. 966.

Funkcije i pretprocesorske naredbe7.

Uvod.......................................................................................................................... 991. Funkcija kao blok naredbi ................................................................................ 992. Primjene funkcija ...............................................................................................1013. Funkcije i pokazivači ........................................................................................ 1054. Statičke varijable funkcije .............................................................................. 1105. Funkcija main( ) ................................................................................................. 1116. Rekurzije................................................................................................................ 1137. Lista argumenata funkcije ............................................................................. 1158. Podrazumijevani parametri funkcije .......................................................... 1179. Konstantni argumenti funkcije .................................................................... 11810. Pretprocesorske naredbe ............................................................................... 11811.

Rad sa datotekama 8.

Uvod ...........................................................................................................................1. Datoteke i C++ ........................................................................................................2. Naredbe fscanf, fprintf... ......................................................................................3. Neformatirane datoteke .......................................................................................4. Zaštita podataka .....................................................................................................5.

Strukture i liste9.

Uvod ...........................................................................................................................1.

Page 5: Klase u c++

5

2. STOG realiziran poljem ........................................................................................ 3. STOG realiziran listom ........................................................................................... 4. Red realiziran cikličkim poljem ......................................................................... 5. Red realiziran listom .............................................................................................. 6. Sortirane i višestruko povezane liste ............................................................... 7. Binarno pretraživanje ............................................................................................

10. Uvod u klase

Uvod ............................................................................................................................1. Konstrukcija klase ...................................................................................................2. Preopterećenje funkcije .......................................................................................3. Funkcije prijatelji .....................................................................................................4. Operatorske funkcije .............................................................................................5. Statički članovi klase ..............................................................................................6. Nasljeđivanje klasa .................................................................................................7. Virtualne funkcije ....................................................................................................8. Predlošci ....................................................................................................................9.

11. Sigurnosne pretvorbe i iznimke

Uvod ............................................................................................................................1. Pretvorba static_cast .............................................................................................2. Pretvorba dynamic_cast ......................................................................................3. Pretvorba reinterpret_cast ..................................................................................4. Pretvorba const_cast .............................................................................................5. Generiranje i obrada iznimki .............................................................................6. Standardne iznimke ...............................................................................................7. Neprihvaćene iznimke ..........................................................................................8. Funkcije i iznimke ..................................................................................................9.

12. Kontrolne klase

Uvod ...........................................................................................................................1. Klase TButton, TRadioButton i TGroupBox .....................................................2. Klase TCheckBox, TStatic i TGauge ....................................................................3. Klase TSlider i TScrollBar .......................................................................................4. Klase TListBox i TComboBox ...............................................................................5. Klase TEdit, TEditFile i TEditSearch ....................................................................6. Operatori new i delete ..........................................................................................7. Fontovi i objekti ......................................................................................................8. Rad sa porukama ...................................................................................................9. Nadogradnja kontrolnih klasa ..........................................................................10.

Page 6: Klase u c++

6

13. Dijalozi i prozori

Uvod ...........................................................................................................................1. Dijalozi Open i SaveAs ..........................................................................................2. Dijalog ChooseColor .............................................................................................3. Dijalog ChooseFont ...............................................................................................4. Karakteristike prozora ...........................................................................................5. Poruke prozora ........................................................................................................6. Rad sa više prozora ................................................................................................7.

14. Grafička obrada

Uvod ...........................................................................................................................1. Uređivanje prozora ................................................................................................2. Funkcije za crtanje ..................................................................................................3. Funkcija Paint ...........................................................................................................4. Ispis podataka ..........................................................................................................5.

15. Resource Workshop

Uvod ...........................................................................................................................1. Ikona i kursor ..........................................................................................................2. Izbornik ......................................................................................................................3. Dijalog .......................................................................................................................4. Bitmap .......................................................................................................................5. DLL resursi....................................................................................................................6.

16. Turbo C++ 2006

Uvod ...........................................................................................................................1. Standardne i dodatne komponente ................................................................2. Win32 i sistem komponente ...............................................................................3. Dijalozi i Win 3.1 komponente ...........................................................................4. Kreiranje i upotreba prozora ...............................................................................5. Dinamička alokacija VCL komponenti ............................................................6. Konfiguracijske datoteke i Windows registar ................................................7. Office integracija ....................................................................................................8. Dretve i procesi .......................................................................................................9.

17. Baze podataka

Uvod .........................................................................................................................1. Paradox i ODBC .......................................................................................................2.

Page 7: Klase u c++

7

3. ADO komponente .................................................................................................. 4. Rad sa zapisima ........................................................................................................ 5. Konekcije u vrijeme zahtjeva ............................................................................. 6. Klijentski skup podataka ...................................................................................... 7. Rave reports ................................................................................................................

18. Mrežno programiranje

1. Uvod .............................................................................................................................. 2. Internet Socket komponente ............................................................................... 3. Indy TCP klijent-server ............................................................................................ 4. Indy UDP klijent-server ........................................................................................... 5. Indy ICMP .................................................................................................................... 6. Indy SMTP .................................................................................................................... 7. Indy FTP klijent .......................................................................................................... 8. Indy Telnet klijent ..................................................................................................... 9. Indy konekcije ............................................................................................................ 10. Windows servisi ........................................................................................................

19. Biblioteke i komponente

Uvod .........................................................................................................................1. Statičke biblioteke .................................................................................................2. Dinamičke biblioteke ............................................................................................3. Borland komponente ............................................................................................4. COM komponente ..................................................................................................5. Active Form ...............................................................................................................6.

20. Linux aplikacije

Uvod ..........................................................................................................................1. Kylix i C++ ................................................................................................................2. CLX biblioteka ..........................................................................................................3. Životni ciklus i komunikacija ..............................................................................4. Prijenos aplikacija .....................................................................................................5.

Page 8: Klase u c++

10. UVOD U KLASE

1. Uvod .............................................................................................................................2. Konstrukcija klase ...........................................................................................................3. Preopterećenjefunkcije.................................................................................................4. Deklaracijafriend..........................................................................................................5. Operatorskefunkcije......................................................................................................6. Statičkičlanoviklase.......................................................................................................7. Nasljeđivanjeklasa........................................................................................................8. Virtualnefunkcije..........................................................................................................9. Predlošci .........................................................................................................................10 UVOD U KLASE

1. Uvod ....................................................................................................................................

2. Konstrukcija klase ...........................................................................................................

3. Preopterećenje funkcije ...............................................................................................

4. Deklaracija friend ...........................................................................................................

5. Operatorske funkcije .....................................................................................................

6. Statički članovi klase .....................................................................................................

7. Nasljeđivanje klasa .........................................................................................................

8. Virtualne funkcije ............................................................................................................

9. Predlošci .............................................................................................................................

Page 9: Klase u c++

9

10. Uvod u klase

10 UVOD U KLASE

1. Uvod ....................................................................................................................................

2. Konstrukcija klase ...........................................................................................................

3. Preopterećenje funkcije ...............................................................................................

4. Deklaracija friend ...........................................................................................................

5. Operatorske funkcije .....................................................................................................

6. Statički članovi klase .....................................................................................................

7. Nasljeđivanje klasa .........................................................................................................

8. Virtualne funkcije ............................................................................................................

9. Predlošci .............................................................................................................................

10.1. Uvod

Programski jezik C++ je karakterističan po tome što programeru dopušta da kre-ira svoj tip podatka. Tako na osnovu tipova podataka koji su već definirani možete kreirati i vlastiti tip podatka. U tu svrhu se koriste klase. Klase su prilično slične strukturama i uni-jama jer se i pomoću njih definira nekakav tip podatka.

Opći oblik klase:

class <ime> {

// Deklaracija članova klase (varijable i funkcije)

}<varijable>;

Opći oblik prikazuje sličnost klasa sa strukturama i unijama podataka. U klasi ili strukturi se pojedini članovi mogu zaštititi ili ograničiti im se pristup. Ukoliko je to potrebno onda se taj tip podatka uglavnom predstavlja kao klasa, a u protivnom kao struktura. Obično, strukture se koriste kada se definira podatak koji ima sve javne članove, i ne sadrži funkci-je. U protivnom je riječ o klasi.

U većini slučajeva funkcije članice koje se koriste za obradu novonastalog tipa podatka (klase) se postavljaju kao javne (public), tj. mogu se koristiti prilikom obrade bilo koje vari-jable (instance) novonastalog tipa. Te javne funkcije mogu koristiti i neke druge pomoćne funkcije koje ne moraju nužno biti dostupne svima, pa se uglavnom postavljaju kao pri-vatne ili zaštićene (private ili protected).

Pravo pristupa Značenje

Public Članovi su dostupni svima (unutar i izvan klase).

Private Članovi su dostupni samo unutar te klase. Niti potomci te klase ne-maju pravo pristupa privatnim članovima.

Protected Članovi su dostupni samo toj klasi i njenim potomcima.

Tablica 10.1.1. Prava pristupa članovima klase

Sve do pojma nasljeđivanja klasa koristiti ćemo samo prva dva pristupa (public i private). Treći pristup (protected) možemo shvatit kao proširenje pristupa private. Koristi se ako je riječ o nasljeđivanju klasa kada je potrebno definirati kojim podacima mogu pristupati potomci neke klase.

Page 10: Klase u c++

10. Uvod u klase

10

10.2. Konstrukcija klase

Osim običnih varijabli i funkcija, klasa može imate konstruktor i destruktor. Njih možemo shvatiti kao dvije karakteristične funkcije klase koje se izvršavaju prilikom krei-ranja njene instance tj. prilikom njenog uništenja iz memorije. Time se programeru daje mogućnost da definira što se treba dogoditi prilikom deklaracije neke varijable (objekta) tog tipa, ili što se treba napraviti prilikom njenog uništenja (brisanja iz memorije).

Konstruktor može imati argumente, a njima se služimo kada želimo odmah pri kreiranju objekta inicijalizirati neke njegove članove, dok kod destruktora argumenata nema. Kon-struktor i destruktor klase ćemo detaljnije obraditi u nastavku.

Primjer 10.2.1.

#include <iostream.h>

class Objekt

{

private: // privatni članovi...

char znak;

int broj;

public: // Javni članovi...

void f();

};

void Objekt::f(){

cout << "Funkcija Objekt::f()";

}

int main()

{

Objekt Instanca;

Instanca.znak = 'A'; /* greška! privatni članovi nisu

dostupni 7*/

Instanca.f(); // ok! "f" je javna funkcija

return 0;

}

Kreirali smo klasu Objekt koja sada predstavlja novi tip podatka. Ova klasa ima dvije po-moćne varijable i jednu funkciju kao svoje članove.

Primijetite na koji način je napisano tijelo funkcije f :

Page 11: Klase u c++

11

10. Uvod u klase

void Objekt::f()...

Ova funkcija ima prototip u klasi Objekt, te se zbog toga mora navesti da je ona vlasništvo te klase. To se radi na način da se, nakon što se navede tip funkcije, navede ime pripadne klase te znakovi “::" (operator dosega). Poslije toga se navede ime funkcije i njeni parame-tri (ako postoje).

Ukoliko funkcije nisu velikog sadržaja njihova tijela moguće je napisati i u samoj klasi. Tada se umjesto prototipa navedene funkcije odmah piše njeno tijelo. Tako smo klasu u primjeru 10.2.1. mogli napisati i ovako:

class Objekt

{

private: // privatni članovi...

char znak;

int broj;

public: // Javni članovi...

void f()

{

cout << "Funkcija Objekt::f()"; }″

};

Primijetimo da je ova klasa preglednija od prethodne jer tijelo funkcije f se nalazi u samoj klasi, a ne izvan. Međutim, to ne bi bio slučaj da neka od funkcija sadrži mnogo naredbi. Tada bi se radi preglednosti u klasi naveo prototip te funkcije, a njeno tijelo bi napisali izvan klase. Općenito, programeri i koriste tu praksu da zasebno napišu definiciju klase sa svim prototipima funkcija te to spreme u header datoteku, dok sama tijela funkcija se spremaju u cpp datoteku.

U glavnom programu smo deklarirali Instanca kao varijablu tipa Objekt. Ta varijabla pred-stavlja jednu kopiju navedene klase, te sada zato možemo koristiti sve njene dostupne članove. Njima pristupamo na isti način kao da pristupamo nekom članu strukture. Prvo navedemo ime strukture, pa onda točku (.), a nakon toga ime člana. Kod struktura, unija i klasa točka se koristi kao operator za pristup funkciji ili varijabli koja je njen sastavni dio. Na taj način smo pozvali i funkciju f.

Sve ovo može djelovati jako zbunjujuće jer u C++u i strukture mogu sadržavati funkcije kao svoje članove, pa je teško uvidjeti samu razliku između strukture i klase (osim u ime-nu). Međutim, razlika je u podrazumijevanom pravu pristupa. Članovi klase su automatski privatni (ako se ne navede drukčije), dok su članovi strukture javni.

Članovi klase mogu biti i funkcije tipa inline. Takva funkcija je ona čije se tijelo kopira na mjesto poziva. Time se ubrzava njeno izvršavanje, no izvršni program se poveća. Nije preporučljivo koristiti inline funkcije pri radu sa programskim petljama, niti ukoliko se u

Page 12: Klase u c++

10. Uvod u klase

12

takvoj funkciji deklariraju polja većih dimenzija. Razlog? Veličina izlaznog koda tj. izvršnog programa.

inline void f();

Sve funkcije, članice neke klase, čija su tijela napisana u samoj definiciji te klase su auto-matski inline funkcije. Ukoliko želite da to budu i ostale funkcije koje imaju samo prototip u definiciji klase, morate ispred prototipa te funkcije napisati ključnu riječ inline.

Primjer 10.2.2.

#include <iostream.h>

#include <math.h>

class Tocka

{

private:

float x, y;

public:

Tocka(float a, float b); // konstruktor

float X() {return x;} // vraca x koordinatu tocke

float Y() {return y;} // vraca y koordinatu tocke

};

Tocka::Tocka(float a, float b){ // tijelo konstruktora klase

x = a;

y = b;

}

float UdaljenostTocaka(Tocka A, Tocka B)

{

return pow(pow(A.X()-B.X(), 2) + pow(A.Y()-B.Y(), 2), 0.5);

}

int main()

{

Tocka A(1, 1), B(2, 2);

cout << UdaljenostTocaka(A, B) << endl;

return 0;

}

Za razliku od prethodne, ova klasa ima konstruktor. Spomenuli smo da konstruktor mo-žemo shvatiti kao funkciju. Međutim, samo kao funkciju koja NEMA povratnu vrijednost.

Page 13: Klase u c++

13

10. Uvod u klase

Ne možete je deklarirati niti kao tipa void. Konstruktor klase uvijek ima isto ime kao i sama klasa. Npr. za klasu Tocka deklaracija konstruktora može biti

Tocka(float a, float b); // konstruktor klase Tocka

Jedino je važno da se funkcija zove isto kao i klasa, dok argumenti unutar nje nisu uopće bitni. Nasuprot toga, destruktor, također ne može imati specifikaciju o povratnoj vrijedno-sti. I on ima gotovo isto ime kao i sama klasa, no nikada nema argumente. Npr.:

~Tocka(); // destruktor klase Tocka

Razlika u imenu konstruktora i destruktora je samo u prvom znaku imena. Destruktor kao prvi znak ima “tildu” tj. znak ‘~’. U našim primjerima nećemo se baviti destruktorom jer nam on nije toliko važan kao npr. konstruktor klase.

Ukoliko klasa ima konstruktor tada se prilikom deklaracije neke varijable tog tipa moraju navesti vrijednosti argumenata koje traži konstruktor. Tako npr. za navedenu klasu Tocka konstruktor glasi

Tocka(float a, float b);

što znači da svaku varijablu tipa Tocka moramo deklarirati tako da unutar zagrada te nove varijable navedemo dvije vrijednosti tipa float. Npr.:

Tocka A(1.5, 1), B(2, 2.7);

Da u klasi nismo naveli postojanje konstruktora varijable A i B smo mogli deklarirati kao i svake druge varijable (bez korištenja zagrada). Zašto? Ako programer ne navede niti jedan konstruktor onda se generira onaj podrazumijevani. U ovom slučaju to bi bio:

Tocka(){}

Međutim, ako je programer definirao jedan ili više drugih konstruktora onda podrazumi-jevani konstruktor više ne postoji. Tada ga je potrebno dodatno navesti u definiciji klase ukoliko želite imati i tu mogućnost da instance te klase kreirate poput običnih varijabli bez ikakvih argumenata.

U našem primjeru smo definirali samo jedan konstruktor i on prima dva argumenta koji su realni brojevi. Drugim riječima, podrazumijevani konstruktor sada ne postoji i moramo pri deklaraciji svake varijable tipa Tocka unutar zagrada predati i dva realna broja.

Primjer 10.2.2. prikazuje kada je to poželjan slučaj. Klasa Tocka ima konstruktor čija dva argumenta zapravo predstavljaju koordinate nove točke, tj. nove varijable tipa Tocka. Kon-struktorom smo skratili posao jer smo odmah inicijalizirali koordinate nove točke.

Unutar klase Tocka smo deklarirali i dvije funkcije. Funkcije X i Y vraćaju x tj. y koordinatu točke, dok globalna funkcija UdaljenostTocaka vraća udaljenost dviju točaka u koordinat-nom sustavu. Ova funkcija kao argumente ima podatke tipa Tocka, što je sada dopušteno

Page 14: Klase u c++

10. Uvod u klase

14

jer je Tocka novodefinirani tip podatka čija se definicija nalazi prije tijela te funkcije.

Primjer 10.2.3.

#include <iostream.h>

class Jednadzba

{

private:

float X, Y;

public:

Jednadzba(float a1, float b1, float c1,

float a2, float b2, float c2);

float RjX() {return X;}

float RjY() {return Y;}

};

Jednadzba::Jednadzba(float a1, float b1, float c1,

float a2, float b2, float c2)

{

if((-a1 / b1) == (-a2 / b2))

{

cout << "NEMA RJEŠENJA JEDNADŽBE!";

return;

}

X = (c1 - b1 * ((a1 * c2 - a2 * c1) / (a1 * b2 - a2 * b1))) / a1;

Y = (a1 * c2 - a2 * c1) / (a1 * b2 - a2 * b1);

}

int main()

{

Jednadzba J(1, -1, 0, 1, 3, 2); // X – Y = 0; X + 3Y = 2

cout << J.RjX() << endl; // 0.5

cout << J.RjY() << endl; // 0.5

return 0;

}

Navedena klasa je tip podatka koji u sebi sadrži koeficijente dviju jednadžbi sa dvije ne-poznanice.

Prilikom deklaracije jednadžbe tj. varijable tipa Jednadzba ti se koeficijenti predaju preko

Page 15: Klase u c++

15

10. Uvod u klase

konstruktora. Unutar njega se izračunaju rješenja jednadžbe (ukoliko ih je moguće naći), te se funkcijama RjX i RjY ta rješenja “vrate” preko povratnih vrijednosti tih funkcija.

Također, spomenimo da postoji poseban oblik konstruktora koji se naziva konstruktor kopije (copy constructor). On se koristi kada vršimo inicijalizaciju novog objekta pomoću nekog već postojećeg objekta tog tipa. Tada se vrši doslovno kopiranje sadržaja iz jednog objekta u drugi. Pripadni konstruktor kopije za klasu X bi izgledao ovako:

X(X const&);

Konstruktor kopije kao argument sadrži referencu na konstantan objekt. Konstanta se po-stavlja kako se slučajno ne bi promijenio predani objekt, a referenca zbog ubrzanja poziva. Zbog reference neće se gubiti vrijeme na kopiranje podataka i zauzimanje dodatne me-morije zbog samog argumenta konstruktora. Ovo je osnovni oblik konstruktora kopije, no on se može proširiti i dodatnim argumentima.

Tocka A(0, 0);

Tocka B = A;

Tocka C(B);

Ovo su najčešći slučajevi korištenja konstruktora kopije. U prvoj naredbi smo kreirali in-stancu klase Tocka. Već u drugoj naredbi koristimo konstruktor kopije. Naime,

Tocka B = A; // deklaracija i inicijalizacija (konstruktor kopije)

Ova naredba predstavlja deklaraciju (kreiranje) i inicijalizaciju objekta. Pošto je riječ o krei-ranju nužno se poziva konstruktor, i to u ovom slučaju konstruktor kopije čiji argument će biti objekt A. Da smo imali samo

B = A; // inicijalizacija (operator pridruživanja =)

onda je riječ o pridruživanju, te bi se koristio operator =. Međutim, objekt B prethodno nije niti postojao da bi se ovaj operator mogao direktno primijeniti. Zadnja naredba također prikazuje upotrebu konstruktora kopije, i to direktno uzimajući postojeći objekt kao argu-ment konstruktora klase.

10.3. Preopterećenje funkcije

Prilikom rada sa funkcijama moguće je koristiti više funkcija sa istim imenom. One se tada trebaju razlikovati po drugim karakteristikama (broju i tipovima argumenata). Tada se za takvu funkciju kaže da je preopterećena (overloaded).

Page 16: Klase u c++

10. Uvod u klase

16

Primjer 10.3.1.

#include <iostream.h>

#include <string.h>

class Osoba

{

private:

char ime[20];

char prezime[20];

public:

Osoba(char* ime, char* prezime){

strcpy(this->ime, ime);

strcpy(this->prezime, prezime);

}

void UzmiPodatke(char* ime){

strcpy(ime, this->ime);

}

void UzmiPodatke(char* ime, char* prezime){

strcpy(ime, this->ime);

strcpy(prezime, this->prezime);

}

};

int main()

{

char ime[20], prezime[20];

Osoba A("Ivan", "Ivic");

A.UzmiPodatke(ime);

cout << ime << endl; //Ivan

A.UzmiPodatke(ime, prezime);

cout << ime << prezime; //IvanIvic

return 0;

}

Navedeni primjer prikazuje preopterećenje funkcije UzmiPodatke. Prva deklaracije ove funkcije ima samo jedan argument kojim se dohvaća ime osobe, dok preopterećenje tj. drugi oblik te funkcije može pomoću pokazivača vratiti i prezime osobe.

U prvom pozivu funkcije naveo se samo jedan parametar. Po tome je program znao da

Page 17: Klase u c++

17

10. Uvod u klase

treba pozvati prvi oblik funkcije UzmiPodatke. Stoga, glavnom programu se vratilo samo ime osobe. Pri drugom pozivu te funkcije su se navela dva parametra. Program je našao i taj oblik te funkcije, te glavnom programu ovaj put vratio i ime i prezime osobe. Drugim riječima, program je bez obzira na isto ime funkcija izvršavao baš onu gdje su se predani parametri podudarali sa traženim argumentima funkcije.

Osim preopterećenja funkcije UzmiPodatke možemo primijetiti i ključnu riječ this. To je ništa drugo već pokazivač na klasu u kojoj se nalazi. Uzmimo za primjer prvi oblik funkcije UzmiPodatke.

void UzmiPodatke(char* ime)

{

strcpy(ime, this->ime);

}

Ova funkcija se nalazi u klasi Osoba. Ta klasa kao privatni član ima varijablu ime, no njena funkcija članica UzmiPodatke ima argument koji se isto tako zove. Stoga, da se prevoditelja ne bi zbunilo uvodimo ključni riječ this i njome u ovom slučaju strogo kažemo da se refe-riramo na član klase Osoba koji se zove ime, a ne na argument funkcije koji se tako zove, tj.:

ime – odnosi se na argument funkcije

this->ime - odnosi se na član klase Osoba koji se naziva ime

Primjer 10.3.2.

#include <iostream.h>

class Tocka

{

private:

float x, y;

public:

Tocka(float a, float b) {x = a; y = b;}

float X() {return x;}

float Y() {return y;}

};

class Pravac

{

private:

float k, l;

public:

Page 18: Klase u c++

10. Uvod u klase

18

Pravac(float koeficijent, float odsjecak);

Pravac(Tocka A, Tocka B);

void Jednadzba();

};

Pravac::Pravac(float koeficijent, float odsjecak){

k = koeficijent;

l = odsjecak;

}

Pravac::Pravac(Tocka A, Tocka B){

k = (B.Y() - A.Y()) / (B.X() - A.X());

l = -k * A.X() + A.Y();

}

void Pravac::Jednadzba(){

cout << "Y = " << k << "x + " << l << endl;

}

int main()

{

Tocka A(1, 1), B(2, 8);

Pravac PrviPravac(1, 4); /* koeficijent smjera i odsječak na

osi x */

Pravac DrugiPravac(A, B); /* pravac definiran dvjema točkama

u ravnini*/

PrviPravac.Jednadzba(); // y = 1x + 4

DrugiPravac.Jednadzba(); // y = 7x - 6

return 0;

}

Ovo je primjer u kojem vidimo preopterećenje konstruktora. Navedeni program može de-klarirati varijable tipa Pravac u dva slučaja:

a) Ako je poznat koeficijent smjera pravca i odsječak na koordinatnoj osi x (prvi oblik konstruktora klase Pravac).

b) Ako su poznate dvije točke kojima prolazi pravac (drugi oblik konstruktora klase Pravac).

Zbog drugog slučaja smo i kreirali klasu Tocka da bi mogli deklarirati dvije varijable koje predstavljaju dvije točke u koordinatnom sustavu. Njene funkcije X i Y smo u drugom obli-ku konstruktora klase Pravac upotrijebili kako bi izračunali koeficijent smjera pravca i od-sječak na koordinatnoj osi x.

Page 19: Klase u c++

19

10. Uvod u klase

10.4. Deklaracija friend

Pojam prijatelj (friend), osim u svakodnevnom životu moguće je koristiti čak i u C++u. Riječ je o odnosu klase i funkcije, te klase i klase. Primjerice, moguće je deklarirati “prijateljsku” funkciju unutar neke klase. Takva funkcija je zapravo obična globalna ili ne-članska funkcija, ali svojstvo friend joj omogućava da koristi sve članove klase u kojoj ima to svojstvo. To uključuje i privatne i zaštićene članove te klase.

Primjer 10.4.1.

#include <iostream.h>

class Tocka

{

private:

int x, y;

friend int GetX(Tocka A);

friend int GetY(Tocka A);

public:

Tocka(int x, int y){

this->x = x;

this->y = y;

}

};

int GetX(Tocka A){

return A.x;

}

int GetY(Tocka A){

return A.y;

}

int main()

{

Tocka A(1, 10);

cout << "X = " << GetX(A) << endl; // 1

cout << "Y = " << GetY(A) << endl; // 10

return 0;

}

U privatnom dijelu klase Tocka nalaze se dvije varijable i dvije funkcije. Deklarirane varija-

Page 20: Klase u c++

10. Uvod u klase

20

ble predstavljaju koordinate točke, dok se sa naredne dvije funkcije vraćaju te koordinate. Zamislimo da su funkcije GetX i GetY deklarirane bez svojstva friend i da se njihovi proto-tipovi ne nalaze u definiciji klase Tocka.

U tom slučaju one bi bile obične globalne funkcije i ne bi mogle pristupiti članovima x i y koji se nalaze u privatnom dijelu klase Tocka. Međutim, pošto se njihovi prototipovi sa svojstvom friend nalaze u definiciji klase, one će bez obzira što nisu njene članice imati pristup svim njenim članovima.

U našem primjeru prototipovi funkcija GetX i GetY su navedeni u privatnom dijelu klase Tocka, no deklaracija friend može se nalaziti bilo gdje u klasi. Također, mogli smo i tijela tih funkcija napisati unutar klase, no svejedno treba imati na umu da one ne mijenjanju svoju izvornu definiciju tj. da i dalje ostaju globalne ili funkcije članice neke druge klase.

Primjer 10.4.2.

class Tocka{

friend class Pravac;

int x, y;

public:

Tocka(int a, int b) : x(a), y(b){}

};

class Pravac{

public:

Tocka A1, B1;

Pravac(Tocka A, Tocka B) : A1(A), B1(B){}

int Kvadrant(Tocka A){

if(A.x > 0 & A.y > 0) return 1;

if(A.x < 0 & A.y > 0) return 2;

if(A.x < 0 & A.y < 0) return 3;

if(A.x > 0 & A.y < 0) return 4;

}

};

Deklaracija friend se može odnositi i na klasu. Sada vidimo kako klasa Pravac ima pristup privatnim članovima klase Tocka. Svejedno, preporučljivo je ne koristiti deklaraciju friend jer se njome omogućuje lagani uvid u strukture podataka te time ugrožava jedno od te-meljnih načela rada s klasama – skrivanje podataka.

Page 21: Klase u c++

21

10. Uvod u klase

10.5. Operatorske funkcije

Kada se radi sa klasama tj. kada definirate svoj korisnički tip podatka moguće je za njega osim funkcija i varijabli definirati i operatore. Njima omogućavate i definirate neke osnovne aritmetičke ili druge operacije sa tim podatkom. Pomoću operatora mo-žemo definirati komunikaciju između vaše klase i ostalih tipova podataka, a operatore uvodimo i definiramo pomoću operatorskih funkcija.

Primjer 10.5.1.

#include <iostream.h>

class Kompleksni

{

public:

double re, im;

Kompleksni(){} // podrazumijevani konstruktor

Kompleksni(double re, double im);

Kompleksni operator +(double re); // zbrajanje

Kompleksni operator -(double re); // oduzimanje

Kompleksni operator =(double re); // pridruživanje

};

Kompleksni::Kompleksni(double re, double im)

{

this->re = re;

this->im = im;

}

Kompleksni Kompleksni::operator +(double re)

{

this->re += re;

return *this;

}

Kompleksni Kompleksni::operator -(double re)

{

this->re -= re;

return *this;

}

Kompleksni Kompleksni::operator =(double re)

{

this->re = re;

Page 22: Klase u c++

10. Uvod u klase

22

this->im = 0;

return *this;

}

int main()

{

Kompleksni A(2.5, 6), B(4, 1.3), C;

A = A + 4.5; // A = A.operator +(4.5);

B = B - 2.4; // B = B.operator -(2.4);

C = 10.23; // C.operator(10.23);

cout << "A.re = " << A.re << "\tA.im = " << A.im << endl;

cout << "B.re = " << B.re << "\tB.im = " << B.im << endl;

cout << "C.re = " << C.re << "\tC.im = " << C.im << endl;

return 0;

}

Najlakše je definirati operatore poput operatora pridruživanja (=), no i binarni operatori poput + (plus) i – (minus) mogu se definirati vrlo jednostavno. U konkretnom slučaju, defi-nirali smo spomenute operatore da bi mogli kompleksnom broju zbrojiti ili oduzeti realni dio. Npr.:

Kompleksni Kompleksni::operator +(double re)

{

this->re += re;

return *this;

}

U ovoj operatorskoj funkciji vidimo kako je definirano zbrajanje sa realnim brojem. Zbroj realnog broja i kompleksnog je kompleksni broj, te je stoga povratna vrijednost operator-ske funkcije podatak tipa Kompleksni. Nakon ključne riječi operator, naveli smo zagrade u kojima definiramo tip podatka i varijablu koju želimo dodati kompleksnom broju, a u tijelu funkcije smo definirali to zbrajanje.

Komentirajmo zadnju naredbu u ovoj operatorskoj funkciji:

return *this;

Prethodno smo već objasnili što predstavlja ključna riječ this. To je pokazivač na klasu u kojoj se nalazi, no kako mi moramo vratiti konkretnu vrijednost koja se nalazi na toj adresi (neki kompleksni broj) koristimo *this. Sada će funkcija gornjom naredbom vratiti baš neki kompleksni broj, a ne adresu na kojoj se on nalazi.

Page 23: Klase u c++

23

10. Uvod u klase

Zato sada naredbom

A = A + 4.5; // A = A.operator +(4.5);

program zna da to zapravo znači povećanje realnog dijela kompleksnog broja za vrijed-nost 4.5. Međutim, gornje dvije operatorske funkcije rade sa jednom pretpostavkom, a to je da se pridružena vrijednost nalazi sa desne strane operatora +, dok se instanca treba nalaziti na lijevoj strani. Naime,

A = A + 4.5; // ok

i

A = 4.5 + A; // greška!

nisu uopće iste stvari. U C++u ova dva zbrajanja se mogu definirati kao sasvim različita. Stoga, bolje je operatorske funkcije pisati tako da se odmah pomoću argumenata definira i mjesto za pojedini tip podatka. Točnije, da se definira koji tip podatka treba ići prije na-vođenja operatora, a koji poslije.

Primjer 10.5.2.

#include <iostream.h>

class Kompleksni

{

public:

double re, im;

Kompleksni(){} // podrazumijevani konstruktor

Kompleksni(double re, double im);

};

Kompleksni::Kompleksni(double re, double im)

{

this->re = re;

this->im = im;

}

//Kompleksni + Kompleksni

Kompleksni operator +(Kompleksni A, Kompleksni B){

return Kompleksni(A.re + B.re, A.im + B.im);

}

//Kompleksni + double

Kompleksni operator +(Kompleksni Z, double re){

return Kompleksni(Z.re + re, Z.im);

}

Page 24: Klase u c++

10. Uvod u klase

24

//double + Kompleksni

Kompleksni operator +(double re, Kompleksni Z){

return Z + re; // operator +(Kompleksni, double)...

}

int main()

{

Kompleksni A(2, 6), B(1.5, 2.5), C;

A = A + 1.5; // Kompleksni + double

C = A + 2.5 + B; // Kompleksni + double + Kompleksni

cout << "A.re = " << A.re << "\tA.im = " << A.im << endl;

cout << "B.re = " << B.re << "\tB.im = " << B.im << endl;

cout << "C.re = "<< C.re << "\tC.im = " << C.im << endl;

return 0;

}

Ispis programa:

A.re = 3.5 A.im = 6

B.re = 1.5 B.im = 2.5

C.re = 7.5 C.im = 8.5

Kada želimo definirati koji tip podatka treba biti prije i koji poslije navođenja operatora moramo koristiti globalne operatorske funkcije. One moraju biti globalne jer operatorske funkcije članice neke klase imaju samo jedan argument, dok se za drugi podrazumijeva da je instanca klase u kojoj se nalazi.

Već smo prikazali zašto je to mana, pa smo zato u ovom slučaju koristili globalne operator-ske funkcije. Pogledajmo za primjer jednu od njih:

//Kompleksni + double

Kompleksni operator +(Kompleksni Z, double re)

{

return Kompleksni(Z.re + re, Z.im);

}

Ova operatorska funkcija ima dva argumenta. Točnije ona definira zbrajanje u slučaju kada se sa lijeve strane operatora + nalazi podatak tipa Kompleksni, a sa desne strane podatak tipa double. Isto smo napravili i u sljedećoj funkciji prototipa

Page 25: Klase u c++

25

10. Uvod u klase

Kompleksni operator +(double re, Kompleksni Z);

gdje smo definirali zbrajanje u slučaju kada se sa lijeve strane operatora + nalazi realan broj, a sa desne strane podatak tipa Kompleksni. Ovim dvjema funkcijama smo i omogućili operacije koje smo koristili u programu:

A = A + 1; // Kompleksni + realni

C = A + 1 + B; // Kompleksni + realni + Kompleksni

Za zadnju operaciju smo koristili i operatorsku funkciju koja definira zbrajanje dvaju kom-pleksnih brojeva jer ono što je sa lijeve strane jednakosti (podatak tipa Kompleksni) mora biti isto što i ono sa desne strane jednakost (podatak tipa Kompleksni).

return Kompleksni(Z.re + re, Z.im);

Za povratnu vrijednost smo u jednoj od operatorskih funkcija koristili privremeni objekt. To je objekt koji postoji samo za vrijeme izvršavanja određenog programskog koda, a na-kon toga se uništava. U ovom slučaju on samo postoji u trenutku kada operatorska funk-cija treba vratiti povratnu vrijednost.

Također, osim binarnih aritmetičkih operatora možemo definirati i one unarne, operatore pretvorbe i operatore za definiranje ulaznog i izlaznog toka podataka.

Primjer 10.5.3.

#include <iostream.h>

#include <math.h>

class Kompleksni

{

public:

double re, im;

Kompleksni(){} // podrazumijevani konstruktor

Kompleksni(double re, double im);

Kompleksni& operator ++(); // prefiks ++

Kompleksni operator ++(int); // postiks ++

operator double(); // operator pretvorbe u double

};

Kompleksni::Kompleksni(double re, double im)

{

this->re = re;

this->im = im;

}

Page 26: Klase u c++

10. Uvod u klase

26

// prefiks operator ++

Kompleksni& Kompleksni::operator ++()

{

++this->re;

++this->im;

return *this;

}

// postfiks operator ++

Kompleksni Kompleksni::operator ++(int)

{

Kompleksni Pom = *this;

++(*this);

return Pom;

}// operator pretvorbe u double

Kompleksni::operator double()

{

// vraća modul kompleksnog broja

return pow(pow(this->re, 2) + pow(this->im, 2), 0.5);

}

// operator za izlazni tok <<

ostream& operator <<(ostream& izlaz, Kompleksni Z)

{

izlaz << Z.re << " + " << Z.im << "j";

return izlaz;

}

int main()

{

Kompleksni A(1, 1);

cout << (double)A << endl; // 1.41421

cout << A++ << endl; // 1 + 1j

cout << ++A << endl; // 3 + 3j

return 0;

}

Programski jezik C++ dozvoljava da se posebno definiraju postfiks i prefiks operatori ++, a razlika između prototipa ovih operatorskih funkcija je samo u tome što postfiksni operator ++ ima dodatni argument. Također, prefiks operator vraća referencu.

Kompleksni& operator ++(); // prefiks ++

Page 27: Klase u c++

27

10. Uvod u klase

Kompleksni operator ++(int); // postiks ++

Uveli smo i operator pretvorbe double. Točnije, njime smo omogućili upotrebu cast opera-tora double nad podatkom tipa Kompleksni, a kao rezultat te pretvorbe će se vratiti modul kompleksnog broja.

Koristili smo i operator <<. Ovo je operator izlaznog toka koji se koristi kada želite ispisati neke podatke. Pošto je Kompleksni novi tip podatka dodatno smo preopteretili opera-torsku funkciju << te omogućili i definirali ispis za podatak tipa Kompleksni. Osim za ispis, mogli smo zasebno definirati i operatorsku funkciju >> za učitavanje novog podatka tipa Kompleksni, a ona bi izgledala ovako:

// operator za ulazni tok >>

istream& operator >>(istream& ulaz, Kompleksni& Z)

{

ulaz >> Z.re >> Z.im;

return ulaz;

}

Ova operatorska funkcija bi omogućilo učitavanje kompleksnog broja sa tipkovnice naredbama:

Kompleksni A;

cin >> A;

Jedan operator se može koristiti u neograničenom broju slučajeva. Zato je svako definira-nje operatora ništa drugo već preopterećenje operatorske funkcije. Ukoliko se operator služi i privatnim članovima klase onda se vrlo često takve operatorske funkcije deklariraju i kao tipa friend unutar te klase.

10.6. Statički članovi klase

Kreiranjem klase definirate novi tip podatka, a članovi klase definiraju od čega se taj tip podatka sastoji i što on koristi. Svi objekti tog tipa (instance) imaju svoju kopiju tih podataka i spremaju ih u svoj zasebni memorijski prostor. Međutim, moguće je u klasi definirati i podatke koji se međusobno dijele između svih instanci. To su statički članovi klase.

Page 28: Klase u c++

10. Uvod u klase

28

Primjer 10.6.1.

#include <iostream.h>

class A

{

public:

static int n;

};

int A::n = 0; // inicijalizacija statičkog člana

int main()

{

A obj1, obj2;

cout << obj1.n << “ “ << obj2.n << endl; // 0 0 obj1.n = 1;

cout << obj1.n << “ “ << obj2.n << endl; // 1 1 obj1.n = 2;

cout << obj1.n << “ “ << obj2.n << endl; // 2 2 return 0;

}

Kada se koriste statički članovi u klasi potrebno ih je prije početka programa obavezno inicijalizirati. Nadasve, nećete moći ni pokrenuti program ukoliko to niste napravili.

Promotrimo glavni program. Prvo smo ispisali

cout << obj1.n << “ “ << obj2.n << endl; // 0 0

Pošto je riječ o statičkom članu klase koji je u početku inicijaliziran na vrijednost 0, sve in-stance klase A će vrijednost tog člana pročitati kao 0. U drugoj naredbi smo preko instance obj1 promijenili vrijednost statičkog člana u vrijednost 1, ali se pri ispisu ispisuje 1 1, što znači da je i druga instanca obj2 uvidjela promjenu jer koriste dijeljeni član. Isti slučaj se događa i u zadnjem ispisu gdje smo ovaj put preko instance obj2 promijenili vrijednost statičkog člana, pa se ispisuje 2 2.

Statički članovi klase mogu poslužiti i u slučaju kada želite brojati ili numerirati instance, što pokazuje i sljedeći primjer.

Page 29: Klase u c++

29

10. Uvod u klase

Primjer 10.6.2.

#include <iostream.h>

class A

{

public:

static int kol;

int rb;

A(){ rb = ++kol; }

};

int A::kol = 0;

int main()

{

A obj1, obj2, objX[5];

cout << "Kreirano je " << A::kol << " instanci tipa A\n";

// ispis rednih brojeva instanci

cout << obj1.rb << obj2.rb;

for(int i = 0; i < 5; i++)

cout << objX[i].rb;

return 0;

}

Ispis programa:

Kreirano je 7 instanci tipa A

1234567

Osim statičkih varijabli klase, možemo koristiti i statičke funkcije. To su funkcije koje rade samo sa statičkim članovima. Pomoću njih se može čitati i mijenjati vrijednost statičkog člana neke klase bez potrebe kreiranja njene instance.

Page 30: Klase u c++

10. Uvod u klase

30

Primjer 10.6.3.

#include <iostream.h>

class A

{

private:

static int N;

public:

static int VratiN(){

return N;

}

static void PostaviN(int x){

N = x;

}

};

int A::N = 0;

int main()

{

cout << A::VratiN(); // 0

A::PostaviN(5);

cout << A::VratiN(); // 5

return 0;

}

Statička varijabla N je sada postavljena kao privatna. Da je postavljena kao javna mogli bi joj pristupiti naredbom

A::N

te ju pročitati i izmijeniti po volji. Međutim, pošto ona zbog prava pristupa nije dostupna upotrijebili smo statičke funkcije kojima možemo dobiti identičan rezultat. Naime, statič-ka funkcija VratiN vraća vrijednost statičkog člana N, dok statička funkcija PostaviN mijenja vrijednost tog statičkog člana.

Ono što je ovdje prednost pri korištenju statičkih funkcija jest da nam uopće nije potrebna niti jedna instanca klase A da bi pročitali i izmijenili statički član.

Page 31: Klase u c++

31

10. Uvod u klase

10.7. Nasljeđivanje klasa

Jedno od najvažnijih svojstava jezika C++ je nasljeđivanje. Na osnovu tog svoj-stva je jednostavno moći pisati čak i složene GUI aplikacije. Nasljeđivanjem se smanjuje količina programskog koda, pojednostavljuje se definiranje složenih objekata i onih koji imaju neka zajednička svojstva. Vrlo korisni primjeri se mogu naći baš u pisanju Windows aplikacija korištenjem Borlandove OWL ili Microsoft MFC biblioteke gdje se prozori pišu nasljeđivanjem od klase praznog prozora itd..

Nasljeđivanje je postupak kada se kreira zasebna klasa koja od jedne ili više drugih klasa nasljeđuje članove. Istovremeno, ta nova klasa može imati i neke svoje vlastite članove, dok one naslijeđene može i preopteretiti (ako je riječ o funkcijama). Klasa od koje se vrši nasljeđivanje se uglavnom naziva klasa roditelj, dok klase koje nastaju nasljeđivanjem se nazivaju djeca, izvedenice ili derivacije.

Primjer 10.7.1.

#include <iostream.h>

class A

{

private:

int privatnaA;

public:

int javnaA;

protected:

int zasticenaA;

};

class B : public A

{

public:

int javnaB;

void ProvjeraPristupa()

{

privatnaA = javnaB; // privatnaA nije dostupna!

javnaA = javnaB; // ok!

zasticenaA = javnaB; // ok!

}

};

int main()

Page 32: Klase u c++

10. Uvod u klase

32

{

B obj;

// provjera pristupa

obj.javnaB; // ok! javnaB je član klase B

// pristup naslijeđenim članovima

obj.privatnaA; // nije dostupno!

obj.javnaA; // ok!

obj.zasticenaA; // nije dostupno van klase B!

return 0;

}

U ovisnosti o pravima pristupa, nije moguće naslijediti sve članove klase roditelja. Točnije, nije moguće naslijediti samo privatne članove. Međutim, moguće je da će derivacija klase roditelja također postati klasa od koje se nasljeđuje (klasa roditelj), te se zbog toga nivoi nasljeđivanja mogu detaljno definirati:

class B : public A

Klasa B sada koristi javno nasljeđivanje. To je najčešći oblik koji se koristi i njime definiramo da će klasa B naslijediti članove klase A i to na način da će naslijeđeni članovi imati ista prava pristupa kao i u klasi A. Osim javnog, moguće je izvršiti privatno i zaštićeno naslje-đivanje.

Nasljeđivanje Značenje

PublicJavni članovi klase roditelja postaju javni članovi izvedene klase. Za-štićeni članovi klase roditelja postaju zaštićeni članovi izvedene klase. Privatni članovi klase roditelja nisu dostupni izvedenoj klasi.

Private Javni i zaštićeni članovi klase roditelja postaju privatni članovi izvedene klase. Privatni članovi klase roditelja nisu dostupni izvedenoj klasi.

ProtectedJavni članovi klase roditelja postaju zaštićeni članovi izvedene klase. Zaštićeni članovi klase roditelja postaju privatni članovi izvedene klase. Privatni članovi klase roditelja nisu dostupni izvedenoj klasi.

Tablica 10.7.1. Metode nasljeđivanja

Pogledajmo funkciju ProvjeraPristupa koja se nalazi unutar klase B. Prvom naredbom smo

Page 33: Klase u c++

33

10. Uvod u klase

pokušali pristupiti privatnom članu klase A, no to će biti greška jer privatni članovi klase roditelja nisu dostupni u izvedenoj klasi. Drugom naredbom smo uspješno pristupili jav-nom članu klase A jer se može on može naslijediti. Također i treća naredba

zasticenaA = javnaB;

će biti izvršena jer zaštićeni članovi klase roditelja su dostupni izvedenoj klasi. Međutim, zaštićeni članovi klase roditelja nisu dostupni van te klase, što se vidi u glavnoj funkciji main gdje preko instance klase B nismo uspjeli pristupiti članu zasticenaA. Ovo je i smisao zaštićenog člana.

Nasljeđivanje od više klasa je također vrlo jednostavno za izvesti:

Primjer 10.7.2.

#include <iostream.h>

class A

{

public:

A(){ cout << "A "; }

};

class B

{

public:

B(){ cout << "B "; }

};

class C: public A, public B

{

public:

C() : A(), B(){ cout << "C "; }

};

int main()

{

C obj;

return 0;

}

Ispis programa: A B C

Page 34: Klase u c++

10. Uvod u klase

34

Osim primjera višestrukog nasljeđivanja, ovim primjerom smo prikazali slučaj kada se pri tome koriste i konstruktori klasa roditelja. Prvo se izvršavaju konstruktori naslijeđenih kla-sa, i to redom od lijeva na desno, a tek nakon toga konstruktor izvedene klase. Ukoliko izvedena klasa ima podrazumijevani konstruktor onda nije nužno potrebno koristiti kon-struktore izvedenih klasa.

Bez svojstva nasljeđivanja bilo bi gotovo nezamislivo pisati Windows aplikacije. Za svaki program bi nam bilo potrebno desetak datoteka programskog koda, dok se na ovaj način jednostavno nadogradi postojeća klasa u kojoj se nalaze osnovni dijelovi koji su potrebni za aplikaciju.

10.8. Virtualne funkcije

Objekti koji su nastali nasljeđivanjem uvijek se mogu predstaviti i klasom rodite-lja tj. pretvorbom na više. Primjerice, recimo da imamo klase Pas i Mačka. One bi se mogle predstaviti jednom klasom, a nju bi mogli nazvati Zivotinja, što naravno podrazumijeva i da su klase Pas i Mačka derivacije te klase. Ovo je korisna stvar ukoliko pišete funkcije koje kao argument trebaju imati derivaciju neke klase, ali niste u potpunosti sigurni o kojoj je derivaciji riječ.

Virtualne funkcije ćete upotrebljavati u slučajevima kada pokazivač klase roditelja adre-sirate na njen potomak. Tada, u normalnom slučaju pristup funkcijskim članovima bi se odnosio na članove klase roditelja. No, ukoliko je u njemu neki od funkcijskih članova de-klariran kao virtualan onda će se pristup odnositi na taj isti funkcijski član koji se nalazi u derivaciji klase na koju je adresiran roditelj. Npr.:

Primjer 10.8.1.

#include <iostream.h>

class Zivotinja

{

public:

virtual void Vrsta(){}

};

class Pas : public Zivotinja

{

Page 35: Klase u c++

35

10. Uvod u klase

public:

void Vrsta(){

cout << "Pas\n";

}

};

class Macka : public Zivotinja

{

public:

void Vrsta(){

cout << "Macka\n";

}

};

int main()

{

Pas Rex;

Macka Mac;

Zivotinja *Ziv;

Ziv = &Rex;

Ziv->Vrsta(); // Pas

Ziv = &Mac;

Ziv->Vrsta(); // Macka

return 0;

}

Ključna operacija je adresiranje pokazivača Ziv. Time se zapravo stvara veza između klase roditelja i potomka. Kako u sve tri klase postoji ista funkcija (Vrsta) pitanje je koja će se izvršiti. Ključnom riječi virtual smo funkciju Zivotinja :: Vrsta definirali kao virtualnu. Zbog toga će se program pokušati adresirati na tu istu funkciju koja se nalazi u derivacijama tj. u klasi Pas ili Macka, a neće koristiti onu iz klase Zivotinja.

Adresiranjem navedenog pokazivača zapravo smo odredili tip podatka (potomak) koji sadrži svoju inačicu funkcije Vrsta. Kada je poznat potomak automatski se zna koja će se funkcija Vrsta izvršiti. Npr., Rex je varijabla tipa Pas. Kako je pokazivač Ziv adresiran na vari-jablu Rex to znači da će se izvršiti tijelo funkcije Vrsta koje se nalazi unutar klase Pas, jer Rex je varijabla tipa Pas. Ukoliko ključna riječ virtual ne bi bila navedena program ne bi ništa ispisao jer bi se pozvala funkcija Vrsta iz klase Zivotinja, a njeno tijelo je prazno.

Kako ova virtualna funkcija ima tijelo (iako je prazno) moguće je kreirati zaseban objekt (varijablu) tipa Zivotinja. Međutim, tijelo virtualne funkcije ne mora nužno postojati. U tom slučaju ona može biti čista virtualna funkcija.

Page 36: Klase u c++

10. Uvod u klase

36

virtual void ispis() = 0;

Ovo je primjer deklaracije čiste virtualne funkcije. Klasa u kojoj se nalazi ovakva funkcija se smatra apstraktnom (zamišljenom), te nije moguće izravno kreirati objekt takve zamišlje-ne klase, već samo pokazivač na njega.

Potrebno je spomenuti da u klasi jedino konstruktor ne može biti virtualan, dok destruktor to može biti. Nadasve, nekada je to i nužno. Npr.:

Primjer 10.8.2.

class Bazna

{

public:

virtual ~Bazna(){

cout << "Destruktor bazne klase...\n";

}

};

class Derivacija : public Bazna

{

private:

int* polje;

public:

Derivacija(int n){

polje = new int[n];

}

~Derivacija(){

delete[] polje;

cout << "Polje je dealocirano! (destruktor derivacije...)\n";

}

};

Derivacija nasljeđuje baznu klasu. Međutim, derivacija klase pri svom uništenju mora dea-locirati zauzetu memoriju i zato je nužno da se destruktor derivacije izvrši. No, zbog even-tualne pretvorbe na niže moguća je ovakva situacija:

Bazna* X = new Derivacija(10);

delete X;

Page 37: Klase u c++

37

10. Uvod u klase

U ovom slučaju po definiciji (deklaraciji) X je pokazivač koji pokazuje na objekt bazne kla-se. No, on po inicijalizaciji (pretvorbi na niže) zapravo pokazuje na objekt derivacije. Me-đutim, zbog svoje deklaracije, prilikom oslobađanja memorije poziva se samo destruktor bazne klase.

Kada bi se to sada dogodilo imali bi memory leak tj. zauzeta memorija u derivaciji klase ne bi bila dealocirana. Zbog toga, destruktor bazne klase moram deklarirati kao virtualan. Ako je destruktor bazne klase virtualan prevoditelj će shvatiti da je X zapravo derivacija i prvo će pokrenuti destruktor derivirane klase, pa tek onda destruktor bazne klase.

10.9. Predlošci

Kada se deklarira funkcija uvijek je potrebno navesti sve tipove podataka i argu-mente koje ona koristi. Takva funkcija se može koristiti samo ako prima argumente pret-hodno deklariranog tipa. Tako npr. ukoliko deklarirate funkciju int zbroj(int a, int b) znate da ona može poslužiti samo ukoliko su njeni argumenti cijeli brojevi. Ukoliko biste htjeli da funkcija vraća zbroj dva realna broja morali biste napisati novu funkciju koja za argu-mente ima realne brojeve.

Međutim, kada bi to radili za svaki postojeći tip podatka onda bi to bio naporan posao. Umjesto toga, moguće je deklarirati familiju srodnih funkcija koje rade isti posao neovisno o tipovima podataka koje koriste. Kada deklariramo familiju takvih funkcija onda koristi-mo deklaraciju template.

Sintaksa:

template <template-argument-list> Deklaracija;

Template-argument-list je dio u kojemu se navodi koliko različitih tipova podataka (klasa) ćete koristiti. Ukoliko će vaša funkcija koristiti samo jedan tip podatka onda se deklarira samo jedna klasa, dok se za svaki drugi tip podatka deklarira po još jedna klasa. Tako npr. ukoliko će vaša funkcija zbrojiti i vratiti sumu realnih brojeva onda ćete deklarirati samo jednu klasu jer se koristi samo jedan tip podatka (realni brojevi).

Deklaracija je standardni dio u kojemu se deklarira funkcija (povratni tip, ime i argumenti). Osim kod funkcija, deklaraciju template je moguće koristiti i kod klasa. U tom slučaju se u dijelu Deklaracija navodi deklaracija klase, a ne funkcije.

Page 38: Klase u c++

10. Uvod u klase

38

Primjer 10.9.1.

#include <iostream.h>

template <class Tip1>

Tip1 zbroj(Tip1 a, Tip1 b)

{

return (a + b);

}

int main ()

{

cout << zbroj(2, 4) << endl; // ... int zbroj(int a, int b)

cout << zbroj(3.14, 6.33) << endl;

// ... float zbroj(float a, float b)

cout << zbroj('A', char(3));

// ... char zbroj(char a, char b)

return 0;

}

Ispis programa:

6

9.47

D

U glavnom programu smo tri puta pozvali funkciju zbroj. Prvi put njeni argumenti su bili cijeli brojevi, drugi put su to bili realni brojevi, a potom znakovi. Karakteristika ovih tipova podataka jest da je za njih definirana operacija zbrajanja (+). Da su kao argumenti funkcije postavljeni tipovi podataka za koje nije definiran operator + funkcija zbroj ne bi vratila točan rezultat, ili se na nekim prevoditeljima program uopće ne bi pokrenuo.

template <classTip1> Tip1 zbroj (Tip1 a, Tip1 b

Deklaracija funkcije zbroj koja kao rezultat vraća podatak tipa Tip1, dok su joj argumenti dva podatka tipa Tip1.

Funkcija zbroj koristi samo jedan promjenjivi tip podatka (Tip1). On se koristi za deklaraciju argumenata i kao povratna vrijednost funkcije.

Page 39: Klase u c++

39

10. Uvod u klase

Iz gore navedenog se vidi da funkcija zbroj se može koristiti samo kada se zbrajaju podaci istog tipa (Tip1). Tip1 može biti svaki tip podataka za koji postoji definiran operator +. U prvom slučaju Tip1 je postao int, u drugom slučaju float, a potom char.

Primjer 10.9.2.

#include <iostream.h>

class Kompleksni{

public:

double re, im;

Kompleksni(){}

Kompleksni(double re){

this->re = re;

im = 0;

}

Kompleksni(double re, double im){

this->re = re;

this->im = im;

}

void operator =(double r){

re = r;

im = 0;

}

};

Kompleksni operator +(Kompleksni A, Kompleksni B){

return Kompleksni(A.re + B.re, A.im + B.im);

}

ostream& operator <<(ostream& izlaz, Kompleksni Z){

cout << Z.re << " + " << Z.im << "j";

return izlaz;

}

template <class T1>

T1 Suma(T1 *polje, int n)

{

T1 s;

s = 0;

if(n <= 0) return 0;

Page 40: Klase u c++

10. Uvod u klase

40

for(int i = 0; i < n; i++)

s = s + polje[i];

return s;

}

int main()

{

int polje1[3] = {1, 2, 4};

float polje2[3] = {1.5, 2.5, 3.5};

Kompleksni polje3[3] = {

Kompleksni(1, 1),

Kompleksni(4.2, 5),

Kompleksni(3, 4.2)

};

cout << Suma(&polje1[0], 3) << endl; // 7

cout << Suma(&polje2[0], 3) << endl; // 7.5

cout << Suma(&polje3[0], 3) << endl; // 8.2 + 10.2j

return 0;

}

Napisani predložak funkcije Suma predstavlja funkciju koja kao argument prima određe-no polje podataka i njihov broj elemenata, a vraća sumu svih elemenata tog polja. U glav-nom programu smo pri pozovu te funkcije prvo predali cjelobrojno, pa zatim realno polje podataka. To su već definirani tipovi podataka i funkcija je bez problema uspjela izračunati i vratiti sumu tih polja.

No, u zadnjem pozivu te funkcije predano je korisnički definirano polje podataka tipa Kompleksni. Pošto je riječ o korisnički definiranom tipu podatka sa kojim radi predložak funkcije treba paziti da ta klasa zadovoljava sve što predložak funkcije treba da bi uspješ-no obavio posao. Predložak funkcije treba sljedeće:

a) Pomoćnu varijablu u koju će spremiti sumu elemenata polja.

Zbog ove potrebe morali smo u klasi Kompleksni deklarirati podrazumijevajući konstruk-tor. Inače bi naredba T1 s bila prijavljena kao greška.

b) Inicijalizirati sumu na vrijednost 0.

Da bi se ovo pridruživanje uspješno obavilo u klasi Kompleksni smo morali deklarirati ope-rator pridruživanja = .

c) Znati kako se zbrajaju predani tipovi podataka.

Predložak funkcije u ovom slučaju treba zbrajati kompleksne brojeve, a da bi to bilo mo-guće u klasi Kompleksni smo morali izvršiti preopterećenje operatorske funkcije +. Da ovaj

Page 41: Klase u c++

41

10. Uvod u klase

operator nije definiran za slučaj zbrajanja kompleksnih brojeva predložak funkcije bi javio grešku da ne zna kako zbrojiti kompleksne brojeve.

Primjer 10.9.3.

#include <iostream.h>

template <class T1, class T2>

double Suma(T1 a, T2 b){

return a + b;

}

double Suma(double a, double b){

cout << "Preopterećenje predloška! ";

return a + b;

}

int main()

{

cout << Suma(2.5, 4.3); // Preopterećenje predloška! 6.8

return 0;

}

Predloške funkcija je moguće i preopteretiti kao što je prikazano u ovom primjeru. Bez obzira na to što će tokom izvođenja sam predložak definirati oblik funkcije za zbrajanje dvaju podataka tipa double, ukoliko postoji preopterećenje koje definira točno taj slučaj onda će se izvršiti ta preopterećena funkcija.

Predlošci funkcija će tek u vrijeme izvođenja doznati tipove podataka sa kojima rade, a za to se brine prevoditelj. Na programeru je samo da pazi kakve tipove podataka koristi u predlošcima funkcija, i da bude siguran da ti tipovi podataka zadovoljavaju sve što je potrebno da se funkcija uspješno izvrši, kao što je prikazano i u gornjem primjeru.

Osim predložaka funkcija mogu se kreirati i predlošci klasa. Njih koristimo kada želimo kreirati klasu koja kao svoje članove može imati tipove podataka koji su poznati tek u vrijeme izvođenja.

Page 42: Klase u c++

10. Uvod u klase

42

Primjer 10.9.4.

template <class T>

class STOG

{

public:

T* vrh;

int DodajElement(T element);

int SkiniElement(T &element);

};

template <class T> int STOG<T>::DodajElement(T element){

// ...

}

template <class T> int STOG<T>::SkiniElement(T &element){

// ...

}

Primjerice, ovaj predložak klase predstavlja strukturu podataka STOG. Da je ovo obična klasa onda bi se odmah znalo koji tip podatka se nalazi na STOG-u, no to će ovako biti samo poznato u vrijeme izvođenja. Npr.:

Stog <int> MojStog; // stog s cijelim brojevima

Stog <double> MojStog; // stog s realnim brojevima

Stog <Kompleksni> MojStog; // stog s kompleksnim brojevima

Kreiranje instance ovakve klase se vrši tako da se nakon imena predloška navedu znakovi < (manje) i > (veće) unutar kojih se navede tip podataka koji će se koristiti u generiranoj klasi. Tek nakon toga se navodi ime instance.

Zadatak 1: Napiši predložak klase koja predstavlja polje elemenata proizvoljnog tipa. Broj elemenata se određuje konstruktorom klase, a klasa za svaku instancu (polje) mora omo-gućiti informaciju o broju elemenata, direktan pristup svakom elementu polja preko ope-ratora [], te pretragu pojedine vrijednosti u polju.

Page 43: Klase u c++

43

10. Uvod u klase

Primjer 10.9.5. (Rješenje zadatka 1)

template <class T>

class Polje

{

public:

T* polje;

int BrojElemenata;

Polje(int n);

int Sadrzi(T vrijednost);

~Polje() {delete[] polje;}

T& operator [](int indeks) {return polje[indeks];}

};

template <class T> Polje<T>::Polje(int n){

BrojElemenata = n;

polje = new T[n];

}

template <class T> int Polje<T>::Sadrzi(T Vrijednost){

int pom = 0;

for(int i = 0; i < BrojElemenata; i++)

if(polje[i] == Vrijednost)

pom = 1;

return pom;

}

Prikazani predložak klase će u konstruktoru dinamički alocirati polje tipa T. Polje se dealo-cira u destruktoru, a sama klasa nudi direktan pristup tom polju preko operatora []. Tako-đer, funkcijskom članicom Sadrzi vršimo pretragu polja, a članica BrojElemenata sadrži broj elemenata polja. Na programeru je sada da samo odluči kakvo polje želi kreirati, a za svaku instancu tog polja imati će na raspolaganju sve mogućnosti ove klase. Primjerice;

Polje <int> A(100);

Odlučili smo kreirati polje cijelih brojeva, a ono u ovom slučaju ima 100 elemenata. Polje je predstavljeno varijablom (objektom) A, i sada tu varijablu zbog implementacije operatora [] možemo koristiti kao polje:

srand((unsigned)time(NULL));

for(int i = 0; i < 100; i++)

A[i] = rand() % 100 + 1; // A.polje[i] ...

Page 44: Klase u c++

10. Uvod u klase

44

Primijetite upotrebu a zatim i implementaciju operatora []. Njegova povratna vrijednost mora biti referenca na objekt tipa T. Kada to ne bi bila referenca onda bi operator [] mogli koristiti samo za čitanje vrijednosti nekog elementa polja, no ne i za njegovu inicijaliza-ciju. Inicijalizacija se striktno odnosi na objekte (varijable) jer se oni nalaze s lijeve strane jednakosti, a ne na konstante.

Prednost korištenja predloška u ovom slučaju jest i u tome da sada direktno preko imena instance klase doznajemo tražene informacije o polju.

cout << A.Sadrzi(58); // da li se u polju nalazi broj 58?

cout << A.BrojElemenata; // koliki je broj elemenata?

Štoviše, možete dodati i mnoštvo drugih mogućnosti. Primjerice, malom promjenom pri-stupa možete omogućiti direktno dinamičko proširivanje/suženje polja, implementirati operatore za razne druge operacije s poljem, pa čak i proširiti klasu tako da može raditi s više-dimenzionalnim poljima. Mogućnosti su mnogobrojne, a na vama je da ih implemen-tirate po potrebi.


Recommended