Transcript
Page 1: Objektno programiranje (C++)

Objektno programiranje Objektno programiranje (C++)(C++)

Page 2: Objektno programiranje (C++)

Pravila ocjenjivanjaPravila ocjenjivanja1. Održat će se dva kolokvija. Svaki nosi po 30

bodova. Za prolaz treba imati 25 bodova.

2. Treba predati rješenja dviju domaćih zadaća. Svaka zadaća nosi 20 bodova. Minimum za prolaz je 15 bodova.

3. Popravni kolokvij (maksimum je 45, treba skupiti 20 bodova).

Page 3: Objektno programiranje (C++)

GradivoGradivoOcjene:

• 45-59 bodova: dovoljan (2)• 60-74 boda: dobar (3)• 75-85 bodova: vrlo dobar (4)• 86-100 bodova: izvrstan (5)

Page 4: Objektno programiranje (C++)

Ciljevi kolegija:Ciljevi kolegija: •Uvod u objektno orijentirano i generičko programiranje kroz programski jezik C++• Detaljna prezentacija C++-a• Pripadne standardne biblioteke: STL, Boost•Napredne tehnike programiranja, softverski predlošci

Page 5: Objektno programiranje (C++)

GradivoGradivo• Klase• Kontrola kopiranja• Operatori• Spremnici• Iznimke• Imenici• Nasljeđivanje• Polimorfizam• RTTI• Predlošci

Page 6: Objektno programiranje (C++)

Nastavni materijaliNastavni materijali• Stranica kolegija: http://web.math.hr/nastava/opepp• Vježbe: http://web.math.hr/~vpetrice/opepp

Preporučuju se i slideovi kolegija Računarski praktikum 4 (Botinčan, Petričević, Puljić).

Page 7: Objektno programiranje (C++)

LiteraturaLiteraturaOsnovna: • Stanley B. Lippman, Josée Lajoie, Barbara E. Moo: C++ Primer, Fourth Edition, Addison Wesley Professional, 2005. •Julijan Šribar, Boris Motik: Demistificirani C++, 2. izdanje, Element, Zagreb, 2006. • Bruce Eckel: Thinking in C++, 1. i 2. dio (besplatna e-knjiga) : http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html

Page 8: Objektno programiranje (C++)

LiteraturaLiteraturaNapredna: •Bjarne Stroustrup: The C++ Programming Language, Addison Wesley, 2000. •Scott Meyers: Effective C++, Third Edition, Addison-Wesley, 2006. •Scott Meyers: More Effective C++, Addison-Wesley, 1996. • Herb Sutter: Exceptional C++, Addison Wesley, 2000.• Stephen C. Dewhurst: C++ Common Knowledge, Addison Wesley, 2005. •Erich Gamma, et. all: Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional Computing Series).

Page 9: Objektno programiranje (C++)

PovijestPovijest• Programski jezik C++ nastao je razvojem jezika C i zadržava visoku kompatibilnost s njime.• Kreator jezika je Bjarne Stroustrup (http://www.research.att.com/~bs/). Razvoj je započeo 1979. g.; ime C++ skovano je 1983. godine, a prva komercijalna implementacija pojavila se 1985. • Između 1985. i 1989. jezik je doživio veće inovacije: zaštićeni članovi, parametrizirane klase, višestruko nasljeđivanje itd.• Jezik je 1997. godine definiran standardnom koji nosi ime ISO/IEC 14882:2003. • Planira se novi standard C++0x.

Page 10: Objektno programiranje (C++)

Objektno orijentirano Objektno orijentirano programiranjeprogramiranje

U centru interesa softverskog inženjerstva su složene aplikacije.

Problemi: • Održivost -- mogućnost lakog održavanja koda.•Proširivost -- mogućnost lakog dodavanja nove funkcionalnosti.

Page 11: Objektno programiranje (C++)

Tehnike programiranjaTehnike programiranja

Proceduralna:• Razlaganje programa na manje cjeline -- implementacija pomoću funkcija procedura.• Nemogućnost definiranja apstrakcije koncepata iz aplikacijske domene. • Ne nudi podršku za postizanje održivosti i proširivosti.• "Svemoguća" main funkcija.

Page 12: Objektno programiranje (C++)

Tehnike programiranjaTehnike programiranja

Objektno orijentirana:• Klase predstavljaju koncepte iz aplikacijske domene.• Program se sastoji od objekta (instance klasa) i njihove komunikacije.• Objekti imaju punu odgovornost za svoje ponašanje.

Page 13: Objektno programiranje (C++)

Osnovni elementi OO tehnike:Osnovni elementi OO tehnike:

Apstrakcija -- Koncepti se reprezentiraju neposredno u programu, a izvedbeni detalji su skriveni iza sučelja (eng. interface) koje reprezentira koncept. Enkapsulacija -- Sposobnost osiguravanja da se apstrakcija koristi prema svojim specifikacijama. Enkapsulacijom se sprečava narušavanje apstrakcije, odnosno prodiranje implementacijskih odluka izvan granica apstrakcije. Polimorfizam -- Skrivanje različitih implementacija iza istog sučelja. Osigurava široku primjenjivost koda i reducira zavisnost o implementaciji.Nasljeđivanje -- Konstrukcija novih apstrakcija polazeći od već postojećih.

Page 14: Objektno programiranje (C++)

Generičko programiranjeGeneričko programiranje

• Pojam generičkog programiranja odnosi se na generalizaciju softverskih komponenti kako bi se lako mogle koristiti u različitim situacijama. • Osnovni elementi generičkog programiranja u C++-u su parametrizirane klase i funkcije.

Page 15: Objektno programiranje (C++)

ReferenceReferenceReferenca na neki objekt je novo ime za taj objekt. Osnovna uloga reference je omogućiti prijenos parametara po referenci, dakle prijenos u kojem nema kopiranja parametra, već funkcija dobiva referencu na objekt.

Referenca spada u tzv. složeni tip (engl. compound type), tip koji se gradi pomoću drugih tipova. Tu spadaju još pokazivači (na neki tip) i polja (nekog tipa).

Budući da referenca uvijek mora referirati na neki objekt, slijedi pravilo:

Prilikom deklaracije referenca mora biti inicijalizirana.

int n=100;

int &rn = n;

float ℞ // Greška pri kompilaciji. Neinicijalizirana referenca

Page 16: Objektno programiranje (C++)

ReferenceReferenceNa jedan objekt možemo imati više referenci, a kako je svaka referenca samo novo ime za objekt, svaka promjena objekta putem jedne reference vidljiva je i kroz sve druge.

int n = 100;

int &rn1 = n;

int &rn2 = n;

std::cout << “n= "<< n << std::endl; //100

std::cout << “rn1= "<< rn1 <<“, rn2=“<<rn2<< std::endl; //100,100

rn1++;

std::cout << “n= "<< n << std::endl; //101

std::cout << “rn1= "<< rn1 <<“, rn2=“<<rn2<< std::endl; //101, 101

Page 17: Objektno programiranje (C++)

ReferenceReferenceReferenca može biti konstantna i tada može referirati na konstantan objekt. Obična referenca ne može referirati na konstantu:

char &ra = 'a'; // greška pri kompilaciji.

// Nekonstantna referenca, konstantan objekt.

const char &rb = 'b'; // o.k. Konstantna referenca nam garantira da kroz nju ne možemo promijeniti objekt na koji referira.

Referenca je dakle isto što i pokazivač koji se automatski dereferencira. Za razliku od pokazivača, referenca koja referira na jedan objekt nikad ne može referirati na neki drugi objekt.

Page 18: Objektno programiranje (C++)

ReferenceReferenceKorištenjem referenci donekle ograničavamo prirodan način korištenja implicitnih konverzija. Na primjer, sljedeći kod javlja grešku pri kompilaciji.

double x = 2.71;

int &rx = x;

S druge strane, sljedeći javlja samo upozorenje o konverziji double u int (jer je naravno moguć gubitak podataka):

double x = 2.71;

const int &rx = x;

Page 19: Objektno programiranje (C++)

ReferenceReferenceKada prevoditelj treba referencu na jedan tip inicijalizirati objektom nekog drugog, kompatibilnog, tipa, on kreira privremeni objekt istog tipa kao i referenca, vrši konverziju i inicijalizira referencu tim privremenim objektom.

Kod koji prevoditelj generira izgleda, dakle, ovako:

double x = 2.71;

int tmp = x;

const int &rx = tmp;

Nekonstantna referenca nekog tipa može biti inicijalizirana jedino objektom egzaktno tog istog tipa.

Page 20: Objektno programiranje (C++)

ReferenceReferenceReferencu možemo definirati i na pokazivač.

int n = 100;

int *pn = &n;

int *&rpn = pn; // Referenca na pokazivač

std::cout << "*rpn = "<< *rpn << std::endl;

Nije dozvoljeno deklarirati pokazivač na referencu, a isto tako ni referencu na referencu.

Polje referenci ne postoji.

double &x[8];  // Polje referenci nije dozvoljeno – neispravno.

Razlog je taj što svaka referenca mora biti inicijalizirana nekim objektom, što pri definiciji polja nije moguće.

Page 21: Objektno programiranje (C++)

ReferenceReferencevoid f(int *p)

{

std::cout<<*p<<std::endl;

p++;

}

void g(int * & p)

{

std::cout<<*p<<std::endl;

p++;

}

int a=3;

int *ptr=&a;

std::cout<<ptr<<std::endl;

f(ptr);

std::cout<<ptr<<std::endl;

g(ptr);

std::cout<<ptr<<std::endl;

Page 22: Objektno programiranje (C++)

ReferenceReferenceU C++ u koristimo reference kad ne želimo prijenos parametara po vrijednosti. Ako je formalni argument funkcije deklariran kao referenca nekog tipa, onda prilikom poziva funkcije neće doći do kopiranja stvarnog argumenta u formalni, već će formalni argument (koji je referenca) biti inicijaliziran stvarnim. Formalni argument tako postaje alias za stvarni argument i kroz njega možemo dohvatiti stvarni argument. Na taj se način postiže prijenos parametara po referenci.

void swap(int &x, int &y) {     

int tmp = x;     

x = y;     

y = tmp;

}

Prijenos po referenci vršimo kad želimo mijenjati stvarni argument ili kad je argument suviše velik za kopiranje.

Page 23: Objektno programiranje (C++)

ReferenceReferenceU drugom slučaju, kad samo želimo izbjeći kopiranje stvarnog argumenta, formalni argument treba deklarirati kao konstantnu referencu.

S druge strane, kako je moguće konstantnu referencu inicijalizirati nekonstantnim objektom (const je samo obećanje da referenca neće služiti za mijenjanje objekta), funkcija koja deklarira konstantnu referencu može uvijek uzeti nekonstantan argument (koji, naravno, ne može u svom tijelu promijeniti).

Page 24: Objektno programiranje (C++)

ReferenceReferencevoid print(std::string& text) {     

std::cout << text << std::endl;

}

    std::string a("...");     print(a);       // o.k.     

print("...");   // greška

Bolje je dakle pisati:

void print(const std::string& text) {     

std::cout << text << std::endl;

}

Page 25: Objektno programiranje (C++)

ReferenceReferenceAko je argument funkcije deklariran kao nekonstantna referenca, onda pri pozivu funkcije nije dozvoljena konverzija tipova za taj argument. Formalni i stvarni argument moraju biti istog tipa.

Kad je referenca konstantna, onda je, kao što smo vidjeli, konverzija dozvoljena. Treba imati pri tome na umu da će prevoditelj generirati privremeni objekt i da će formalni argument referirati na njega.

Page 26: Objektno programiranje (C++)

ReferenceReferenceKako se polja ne mogu kopirati, ne možemo napisati funkciju koja ima parametar tipa polje. Kad koristimo polje u izrazima, ono se automatski konvertira u pokazivač na prvi član polja.

Sljedeće deklaracije su ekvivalentne. Interpretiraju se kao funkcija koja kao parametar prima pokazivač tipa int*.

void print( int * ){ …..}

void print( int[ ] ){ …. }

void print( int[100] ){ …… }

Page 27: Objektno programiranje (C++)

ReferenceReferenceFunkcija koja uzima polje kao argument dobiva pokazivač na prvi element polja. Takva funkcija može uzeti polje bilo koje dimenzije. S druge strane, moguće je deklarirati funkciju koja uzima referencu na polje:

int count(int (&arr)[4]) {     

int x = 0;     

for(int i=0; i< 4; ++i) x += arr[i];     

return x;

}

Funkcija count će uzimati samo polja dimenzije 4, jer nema implicitnih konverzija između polja različite veličine. Referenca na polje je dakle manje fleksibilna od pokazivača na polje, pa se stoga rijetko koristi kao parametar funkcije.

Page 28: Objektno programiranje (C++)

ReferenceReferenceAko funkcija vraća referencu, tada ne dolazi do kopiranja vrijednosti, već samo do kopiranja reference. Za velike objekte to može biti velika ušteda.

Referenca kao povratna vrijednost ima još i tu prednost da predstavlja vrijednost koja se može naći na lijevoj strani znaka jednakosti (lvalue).

char& get(std::string& s, unsigned i) {    

  return s[i];

}

    std::string s1("abc");     

get(s1,2)='z';

Page 29: Objektno programiranje (C++)

ReferenceReferenceMoramo paziti da nikad ne vratimo referencu na lokalnu varijablu jer će ona nakon vraćanja reference na nju biti uništena. Isto naravno vrijedi i za pokazivač na lokalnu varijablu.

  // Neispravan kod

std::string&  ccn(const std::string& s1, const std::string& s2){

    std::string tmp = s1+s2;     

return tmp; // greška

}

Funkcija ne smije nikada vratiti referencu ili pokazivač na lokalnu varijablu.

Page 30: Objektno programiranje (C++)

Pokazivači na funkcijePokazivači na funkcijeKao i ostali pokazivači, i pokazivač na funkciju pokazuje na točno određeni tip funkcije. Pritom se uzima u obzir i povratni tip i lista parametara.

Primjer: Pokazivač na funkciju koja prima const string referencu i int, a vraća int, deklariramo na sljedeći način:

int (*fptr)(const string &, int );

Napomena: zagrade oko *fptr su nužne jer je

int *fptr(const string &, int );

deklaracija funkcije koja ima jednaku listu parametara i vraća pokazivač na int.

Page 31: Objektno programiranje (C++)

Pokazivači na funkcijePokazivači na funkcijeZbog kompliciranosti sintakse, preporučljivo je uvesti novo ime za pokazivač na funkciju:

typedef int (*fptrType)(const string &, int );

Ukoliko koristimo ime funkcije za poziv funkcije, ona se i tretira kao funkcija. U ostalim slučajevima se automatski tretira kao pokazivač na funkciju pripadnog tipa.

Page 32: Objektno programiranje (C++)

Pokazivači na funkcijePokazivači na funkcijeNeka je deklarirana odgovarajuća funkcija:

int f(const string &, int );

Pokazivač na funkciju može se inicijalizirati samo s funkcijom ili pokazivačem na funkciju jednakog tipa ili s konstantnim izrazom jednakim nula.

Ne postoji konverzija između pokazivača na funkcije različitih tipova (moraju se slagati i lista parametara i povratni tip).

fptrType ptr1=f;

ptr1=&f;

fptrType ptr2=0;

ptr2=ptr1;

Page 33: Objektno programiranje (C++)

Pokazivači na funkcijePokazivači na funkcijeMožemo uvesti novo ime i za sam tip funkcije.

typedef int (*fptrType)(const string &, int );

typedef int fType(const string &, int );

int f(const string &, int );

fptrType fptr1=f;

fType *fptr2=fptr1;

Page 34: Objektno programiranje (C++)

Pokazivači na funkcijePokazivači na funkcije Pokazivač na funkciju koji nije inicijaliziran ili ima vrijednost nula ne može se koristiti za poziv funkcije. Pri pozivu funkcije možemo koristiti i pokazivač na funkciju i dereferencirani pokazivač.

int f(const string &s, int a){

cout << s;

return ++a;

}

fptrType fptr=&f;

int a=(*fptr)("Hello",1);

int b=fptr("Hello",1);

Page 35: Objektno programiranje (C++)

Pokazivači na funkcijePokazivači na funkcijePokazivač na funkciju može biti i parametar neke funkcije. Pritom su ekvivalentne sljedeće deklaracije:

typedef int (*fptrType)(const string &, int );

void Test( int , int(const string &, int ) );

void Test( int , int (*) (const string &, int ) );

void Test( int , fptrType );

Page 36: Objektno programiranje (C++)

Pokazivači na funkcijePokazivači na funkcije

Funkcija može i vratiti pokazivač na funkciju. Pritom povratna vrijednost mora biti baš pokazivač, ne može biti sama funkcija.

Preporučljivo je koristiti typedef za tip pokazivača. Ekvivalentno je:

int (*f( int ))(const string &, int );

fptrType f( int );

Nije dozvoljeno deklarirati funkciju tipa

fType ff( int );

Page 37: Objektno programiranje (C++)

Pokazivači na funkcijePokazivači na funkcije¸Moguće je definirati i polje pokazivača na funkcije.

void f1( int i) { cout<<"Funkciji f1 proslijedili ste broj "<<i; }

void f2( int i ) { cout<<"Funkciji f2 proslijedili ste broj "<<i; }

void f3( int i ){ cout<<"Funkciji f3 proslijedili ste broj "<<i; }

void (*fp[3])( int )={ f1,f2,f3 };

fp[1](13);

Page 38: Objektno programiranje (C++)

Pokazivači na funkcijePokazivači na funkcijeZadatak:

Definirane su funkcije

bool ascending ( int a, int b ) { return a<b ; }

bool descending ( int a, int b ) { return a>b ; }

Napišite definiciju funkcije deklariranu s

void Sort ( int [ ] , const int , bool(*) (int, int));

koja sortira polje int-ova u rastućem ili padajućem poretku.

Napišite main koji testira funkciju.

Page 39: Objektno programiranje (C++)

KonverzijeKonverzije Izrazi mogu biti sastavljeni od operanada različitih tipova ukoliko se svi mogu konvertirati u odgovarajući zajednički tip.

Prevoditelj će prije izvršenja operacije izvršiti konverziju operanada u taj zajednički tip.

Budući da se radi o konverzijama koje se rade bez eksplicitnog zahtjeva od programera govorimo o implicitnim konverzijama.

Page 40: Objektno programiranje (C++)

KonverzijeKonverzijeImplicitne konverzije se dešavaju u ovim situacijama: • Kod aritmetičkih, relacijskih i logičkih izraza.• Kod testiranja u if, while, for i do while naredbama dolazi do konverzije u tip bool.• Kod izraza pridruživanja (=) dolazi do konverzije u tip varijable na lijevoj strani. Ako pri tome dolazi do gubitka preciznosti, konverzija je svejedno legalna, jedino što će prevoditelj dati upozorenje.• Kod poziva funkcije, ako stvarni i formalni argumenti nisu istog tipa.

Page 41: Objektno programiranje (C++)

KonverzijeKonverzijeNajčešće su aritmetičke konverzije. Osnovno pravilo je da dolazi do konverzije u najširi tip u izrazu s ciljem da se sačuva preciznost rezultata.

Integralna promocija: svi se integralni tipovi manji od int (char, signed char, unsigned char, short, unsigned short) pretvaraju u int, ako je to moguće, a ako ne, onda u unsigned int.

Kada se tip bool pretvara u int, onda se true pretvara u 1, a false u nulu.

Page 42: Objektno programiranje (C++)

KonverzijeKonverzijeOstale konverzije: • U većini izraza polje se konvertira u pokazivač na prvi član polja. To se ne dešava kod primjene adresnog operatora i sizeof operatora te kad se poljem inicijalizira referenca na polje.• U izrazima testiranja pokazivač se pretvara u bool tip: null-pokazivač se konvertira u false, svaki drugi u true. • Svaki pokazivač se može konvertirati u void *.• Nula (0) se može konvertirati u pokazivački tip.• Enumeracija se konvertira u integralni tip koji je strojno zavisan.•Nekonstantan objekt se može konvertirati u konstantan. Pokazivač na konstantan tip može se inicijalizirati adresom nekonstantnog objekta.

Napomena: klase definiraju svoje vlastite konverzije.

Page 43: Objektno programiranje (C++)

KonverzijeKonverzijeOd prevoditelja možemo eksplicitno zahtijevati da napravi konverziju tipova, ukoliko je takva konverzija dozvoljena. U C-u bismo to učinili izrazom

(T) izraz;

gdje je T tip u koji konvertiramo izraz.

Jednako je dozvoljen izraz oblika T(izraz).

Primjer: izbjegavanje cjelobrojnog dijeljenja.

    int x = 3;     

int y =4;     

double z=3.24;     

z = x/y; // cjelobrojno dijeljenje     

z = double(x)/y; // realno dijeljenje ili

     z = (double) x/y; // realno dijeljenje

Page 44: Objektno programiranje (C++)

KonverzijeKonverzijeIsta je sintaksa dozvoljena i C++-u, no ovdje se umjesto jednoga uvodi četiri specijalizirana operatora konverzije:

static_cast<T>(izraz);

const_cast<T>(izraz);

dynamic_cast<T>(izraz);

reinterpret_cast<T>(izraz);

Prednost specijaliziranih operatora je bolja dijagnostika grešaka, a ekspresivnija sintaksa omogućava lakše uočavanje eksplicitnih konverzija u kodu.

Page 45: Objektno programiranje (C++)

KonverzijeKonverzijestatic_cast<T> služi za sve one konverzije koje prevoditelj radi implicitno. Većinu tih konverzija on može učiniti i u suprotnom smjeru. Na primjer, svaki se pokazivač implicitno može konvertirati u pokazivač na void, ali obratna konverzija se ne dešava automatski. Moguće ju je tražiti eksplicitno:

    void *pv = &x;     

int *pi;       

pi = pv;                     // Greška pri kompilaciji     

pi = static_cast<int *>(pv); // o.k.

Ovaj je kod ispravan samo ako je varijabla x kojom smo incijalizirali pokazivač pi tipa int. Prevoditelj, općenito, nije u stanju detektirati stvarni tip varijable čija je adresa uzeta. Stoga se greške u uporabi eksplicitnih konverzija pokazuju za vrijeme izvršavanja programa.

Page 46: Objektno programiranje (C++)

KonverzijeKonverzijePomoću static_cast<T> operatora ne možemo pretvoriti konstantan objekt u nekonstantan. U tu svhu služi const_cast<T>.

const_cast<T>(izraz) uklanja konstantnost izraza. Pretpostavimo, na primjer, da imamo funkciju koja uzima nekonstantnu referencu na tip, ali ne mijenja stvarni argument. Tu funkciju ne možemo pozvati s konstantnim stvarnim argumentom.

void f(int& i) {     // ... } // ....     

const int x = 3;     

f(x);                     // Greška pri kompilaciji

f(const_cast<int &>(x)); // o.k

const_cast<T> se može primijeniti samo na pokazivačima i referencama.

Page 47: Objektno programiranje (C++)

KonverzijeKonverzijedynamic_cast<T>(izraz) se koristi za konverziju pokazivača ili reference na baznu klasu u pokazivač ili referencu na izvedenu klasu.

reinterpret_cast<T>(izraz) vrši konverzije zavisne o implementaciji kao što je konverzija pokazivača u int. Radi se o reinterpretaciji niza bitova koja ovisi o sustavu na kojem se vrši i stoga nije prenosiva s računala na računalo. Rijetko se koristi, a ima svoje mjesto u sistemskom programiranju.

Eksplicitne konverzije su opasne jer dovode do grešaka za vrijeme izvršavanja koje nije moguće otkriti za vrijeme kompilacije. One često indiciraju grešku u dizajnu programa i najčašće se mogu izbjeći. Stoga ih treba koristiti u najmanjoj mogućoj mjeri.

Page 48: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaDvije funkcije u istom dosegu su preopterećene ako imaju isto ime, ali različitu listu parametara.

U jeziku C funkcija je na jedinstven način identificirana svojim imenom pa stoga različite funkcije moraju imati različita imena.

Primjer: double sin(double) i float sinf(float).

U C++ jeziku funkciju identificira njena signatura (potpis) koja se sastoji od imena funkcije te liste njezinih parametara.

Nije moguće preopteretiti dvije funkcije samo na osnovu različitog povratnog tipa, odnosno ne mogu postojati dvije funkcije istog imena, broja i tipa parametara, koje bi se razlikovale samo po tipu povratne vrijednosti.

Page 49: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaU nekim se situacijama parametri, koji se čine različitim, ne tretiraju kao različiti i prevoditelj javlja grešku redefiniranja funkcije. To su sljedeće situacije:

Page 50: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaTypedef ne uvodi novi tip već samo predstavlja novo ime za stari tip i stoga ne može biti osnova za razlikovanje:

void f(double y) {

cout << "f(double)"<<endl;

}

typedef double R;

void f(R y) {

cout << "f(R)"<<endl;

} // Greška, redefinicija

Page 51: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaDefaultni argument ne smanjuje broj argumenata funkcije pa ne može biti osnova za razlikovanje:

void f(int x, int y) {

cout << "f(int,int)"<<endl;

}

void f(int x, int y=0) {

cout << "f(int,int=0)"<<endl;

} // Greška, redefinicija

Page 52: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaKada je const irelevantan, ne može služiti za razlikovanje tipova. U ovom slučaju const je irelevantan jer funkcija dobiva kopiju argumenta i nikako ne može promijeniti original.

void f(int x) {

cout << "f(int)"<<endl;

}

void f(const int x) {

cout << "f(const int)"<<endl;

} // Greška, redefinicija

Konstantni i nekonstantni argument mogu služiti za razlikovanje samo kod referenci i pokazivača.

Page 53: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaPrvi korak: nalaženje kandidata. Prevoditelj nalazi sve funkcije danog imena koje su vidljive na mjestu poziva.

Drugi korak: selektiranje među kandidatima onih funkcija koje imaju korektan broj parametara i svi parametri se mogu konvertirati u odgovarajući tip. Time dolazimo do skupa dobrih kandidata (engl. viable functions), tj. onih koji mogu biti pozvani sa zadanim parametrima. Prilikom uspoređivanja broja argumenata uzimaju se u obzir i eventualni defaultni argumenti. Ako je skup dobrih kandidata prazan imamo grešku pri kompilaciji.

Page 54: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaTreći korak: određivanje najboljeg kandidata. Princip nalaženja je sljedeći: kandidat kod kojeg imamo egzaktno podudaranje argumenta je bolji od kandidata kod kojeg moramo vršiti konverziju argumenta. Kako ima više vrsta konverzija one se rangiraju prema kvaliteti u svrhu definiranja uređaja među kandidatima.

Za funkcije s više argumenata najbolji kandidat je onaj koji nije lošiji od drugih niti po jednom argumentu, a u jednom je bolji od svih. Ako na kraju postupka ima više najboljih kandidata, poziv je dvosmislen (engl. ambiguous) i prevoditelj javlja grešku.

Page 55: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaRang lista konverzija prema kvaliteti je sljedeća:

• Egzaktno podudaranje• Integralna promocija• Standardna konverzija• Konverzija definirana u klasi

Page 56: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaPrimjer:

void f(int x, int y) {

cout << "f(int,int)"<<endl;

}

void f(double x, double y) {

cout << "f(double, double)"<<endl;

}

f(1.2, 2);

Page 57: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaPrimjer:

void f(int x, int y) {

cout << "f(int,int)"<<endl;

}

void f(double x, double y) {

cout << "f(double, double)"<<endl;

}

f(1.2, 2);

Poziv je dvosmislen. Obje funkcije su dobri kandidati.

Page 58: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaPrimjer:

void f() { cout << "f()"<<endl; }

void f(int x) { cout << "f(int)"<<endl; }

void f(int x, int y) { cout << "f(int,int)"<<endl; }

void f(double x, double y=0.0) {cout << "f(double, double=0)"<<endl;}

f(1.2);

Page 59: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaPrimjer:

void f() { cout << "f()"<<endl; }

void f(int x) { cout << "f(int)"<<endl; }

void f(int x, int y) { cout << "f(int,int)"<<endl; }

void f(double x, double y=0.0) {cout << "f(double, double=0)"<<endl;}

f(1.2);

Bit će pozvana funkcija f(double, double) jer ne traži niti jednu konverziju.

Page 60: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaČesto se funkcija preopterećuje na osnovu toga što jedna verzija uzima konstantnu referencu, a druga nekonstantnu. To je legalno jer prevoditelj uvijek može odrediti koju funkciju pozvati.

void f(int & x) {

cout << "f(int &)"<<endl;

}

void f(const int & x) {

cout << "f(const int &)"<<endl;

}

Page 61: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcija Ako funkcija dobiva referencu na const objekt, onda je poziv korektan jedino ako funkcija definira argument kao konstantnu referencu; verzija funkcije koja deklarira argument kao nekonstantnu referencu ne garantira da neće promijeniti objekt.

Ako pak imamo referencu na nekonstantan objekt, onda su obje funkcije dobri kandidati i obje mogu biti pozvane. Ali, funkcija s nekonstantnim argumentom ne traži konverziju argumenta, dok kod funkcije s konstantnim parametrom treba prvo konvertirati referencu na nekonstantan objekt u referencu na konstantan objekt. Prema tome, verzija s nekonstantnom referencom je bolja te se poziva.

Page 62: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaPosve je analogna situacija s pokazivačima na konstantan i nekonstantan objekt.

void f(int * x) {

cout << "f(int *)"<<endl;

}

void f(const int * x) {

cout << "f(const int *)"<<endl;

}

Page 63: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaNapomena: Kada funkcija uzima referencu na neki tip, a dobije referencu na neki drugi tip koji je s njim vezan, onda prevoditelj radi konverziju tako što kreira privremeni objekt i predaje funkciji konstantnu referencu na taj objekt. U tom se dakle slučaju poziva verzija funkcije s konstantnom referencom i ako takva nije definirana dolazi do greške pri kompilaciji.

void f(int &a) {std::cout<<"f(int &)";}

void f(const int &a){std::cout<<"f(const int &)";}

….

double d=0.0

f(d);

Page 64: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaNe možemo preopteretiti funkciju obzirom na to uzimaju li pokazivač ili konstantan pokazivač (ne pokazivač na const), jer funkcija ionako dobiva kopiju pokazivača.

void f(int * x) {

cout << "f(int *)"<<endl;

}

void f(int * const x) {

cout << "f(int * const)"<<endl;

} // Greška, redefinicija

Page 65: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaclass Klasa{

int i;

public:

Klasa (int a):i(a){ };

};

//void f(int i) { std::cout<<“ f( int ) ”;}

void f(double i) { std::cout<<“ f( double ) ";}

void f(Klasa i) { std::cout<<“ f( Klasa )";}

int main() {

Klasa k(2);

f(2);

f(1.2);

f(k);

return 0;

}

Page 66: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaclass Klasa{

int i;

public:

Klasa (int a):i(a){ };

};

//void f(int i) { std::cout<<“ f( int ) ”;}

//void f(double i) { std::cout<<“ f( double ) ";}

void f(Klasa i) { std::cout<<“ f( Klasa )";}

int main() {

Klasa k(2);

f(2);

f(1.2);

f(k);

return 0;

}

Page 67: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijaclass Klasa{

int i;

public:

Klasa (int a):i(a){ };

};

void f(int i) { std::cout<<“ f( int ) ”;}

void f(double i) { std::cout<<“ f( double ) ";}

//void f(Klasa i) { std::cout<<“ f( Klasa )";}

int main() {

Klasa k(2);

f(2);

f(1.2);

f(k);

return 0;

}

Page 68: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijavoid g( int i ) { cout<<"int"; }

void g( long i ) { cout<<"long"; }

void g( float i ) { cout<<"float"; }

void g( double i ){ cout<<"double"; }

int main()

{

short a=1;

g(a);

return 0;

}

Page 69: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcijavoid g( int i ) { cout<<"int"; }

void g( long i ) { cout<<"long"; }

void g( float i ) { cout<<"float"; }

void g( double i ){ cout<<"double"; }

int main()

{

short a=1;

g(a);

return 0;

}

Poziva se g(int ) jer integralna promocija ima prednost.

Page 70: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcija

void g( long i ) { cout<<"long"; }

void g( float i ) { cout<<"float"; }

void g( double i ){ cout<<"double"; }

int main()

{

short a=1;

g(a);

return 0;

}

Page 71: Objektno programiranje (C++)

Preopterećenje funkcijaPreopterećenje funkcija

void g( long i ) { cout<<"long"; }

void g( float i ) { cout<<"float"; }

void g( double i ){ cout<<"double"; }

int main()

{

short a=1;

g(a);

return 0;

}

Poziv funkcije je dvosmislen.


Recommended