Objektno programiranje c
This presentation is the property of its rightful owner.
Sponsored Links
1 / 71

Objektno programiranje (C++) PowerPoint PPT Presentation


  • 82 Views
  • Uploaded on
  • Presentation posted in: General

Objektno programiranje (C++). Pravila ocjenjivanja. Održat će se dva kolokvija. Svaki nosi po 30 bodova. Za prolaz treba imati 25 bodova. Treba predati rješenja dviju domaćih zadaća. Svaka zadaća nosi 20 bodova. Minimum za prolaz je 15 bodova.

Download Presentation

Objektno programiranje (C++)

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Objektno programiranje c

Objektno programiranje (C++)


Pravila ocjenjivanja

Pravila ocjenjivanja

Održat će se dva kolokvija. Svaki nosi po 30 bodova. Za prolaz treba imati 25 bodova.

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

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


Gradivo

Gradivo

Ocjene:

45-59 bodova: dovoljan (2)

60-74 boda: dobar (3)

75-85 bodova: vrlo dobar (4)

86-100 bodova: izvrstan (5)


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


Gradivo1

Gradivo

Klase

Kontrola kopiranja

Operatori

Spremnici

Iznimke

Imenici

Nasljeđivanje

Polimorfizam

RTTI

Predlošci


Nastavni materijali

Nastavni 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ć).


Literatura

Literatura

Osnovna:

Stanley B. Lippman, JoséeLajoie, Barbara E. Moo: C++ Primer, FourthEdition, AddisonWesley Professional, 2005.

Julijan Šribar, Boris Motik: Demistificirani C++, 2. izdanje, Element, Zagreb, 2006.

BruceEckel: Thinkingin C++, 1. i 2. dio (besplatna e-knjiga) :http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html


Literatura1

Literatura

Napredna:

BjarneStroustrup: The C++ ProgrammingLanguage, AddisonWesley, 2000.

Scott Meyers: Effective C++, Third Edition, Addison-Wesley, 2006.

Scott Meyers: More Effective C++, Addison-Wesley, 1996.

HerbSutter: Exceptional C++, AddisonWesley, 2000.

Stephen C. Dewhurst: C++ CommonKnowledge, AddisonWesley, 2005.

ErichGamma, et. all: DesignPatterns: ElementsofReusableObject-OrientedSoftware (Addison-Wesley Professional ComputingSeries).


Povijest

Povijest

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.


Objektno orijentirano programiranje

Objektno orijentirano programiranje

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.


Tehnike programiranja

Tehnike 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.


Tehnike programiranja1

Tehnike 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.


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.


Generi ko programiranje

Generič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.


Reference

Reference

Referenca 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. compoundtype), 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


Reference1

Reference

Na 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


Reference2

Reference

Referenca 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.

constchar &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.


Reference3

Reference

Koriš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;

constint &rx = x;


Reference4

Reference

Kada 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;

inttmp = x;

constint &rx = tmp;

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


Reference5

Reference

Referencu 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.


Reference6

Reference

voidf(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;


Reference7

Reference

U 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.

voidswap(int &x, int &y) {     

inttmp = x;     

x = y;     

y = tmp;

}

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


Reference8

Reference

U 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).


Reference9

Reference

voidprint(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;

}


Reference10

Reference

Ako 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.


Reference11

Reference

Kako 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*.

voidprint( int * ){ …..}

voidprint( int[ ] ){ …. }

voidprint( int[100] ){ …… }


Reference12

Reference

Funkcija 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:

intcount(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.


Reference13

Reference

Ako 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';


Reference14

Reference

Moramo 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(conststd::string& s1, conststd::string& s2){

std::stringtmp = s1+s2;     

returntmp;// greška

}

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


Pokaziva i na funkcije

Pokazivači na funkcije

Kao 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.


Pokaziva i na funkcije1

Pokazivači na funkcije

Zbog kompliciranosti sintakse, preporučljivo je uvesti novo ime za pokazivač na funkciju:

typedef int (*fptrType)(conststring &, 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.


Pokaziva i na funkcije2

Pokazivači na funkcije

Neka 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;


Pokaziva i na funkcije3

Pokazivači na funkcije

Možemo uvesti novo ime i za sam tip funkcije.

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

typedefintfType(const string &, int );

int f(const string &, int );

fptrType fptr1=f;

fType *fptr2=fptr1;


Pokaziva i na funkcije4

Pokazivač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(conststring &s, int a){

cout << s;

return ++a;

}

fptrTypefptr=&f;

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

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


Pokaziva i na funkcije5

Pokazivači na funkcije

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

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

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

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

void Test( int , fptrType );


Pokaziva i na funkcije6

Pokazivač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

fTypeff( int );


Pokaziva i na funkcije7

Pokazivač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);


Pokaziva i na funkcije8

Pokazivači na funkcije

Zadatak:

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.


Konverzije

Konverzije

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.


Konverzije1

Konverzije

Implicitne 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.


Konverzije2

Konverzije

Najč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, signedchar, unsignedchar, short, unsignedshort) 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.


Konverzije3

Konverzije

Ostale konverzije:

U većini izraza polje se konvertira u pokazivač na prvi član polja. To se ne dešava kod primjene adresnog operatorai sizeofoperatora 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.


Konverzije4

Konverzije

Od 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


Konverzije5

Konverzije

Ista 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.


Konverzije6

Konverzije

static_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.


Konverzije7

Konverzije

Pomoć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) {     // ... } // ....     

constint 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.


Konverzije8

Konverzije

dynamic_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.


Preoptere enje funkcija

Preopterećenje funkcija

Dvije 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 floatsinf(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.


Preoptere enje funkcija1

Preopterećenje funkcija

U 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:


Preoptere enje funkcija2

Preopterećenje funkcija

Typedef 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;

}

typedefdouble R;

void f(R y) {

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

} // Greška, redefinicija


Preoptere enje funkcija3

Preopterećenje funkcija

Defaultni 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


Preoptere enje funkcija4

Preopterećenje funkcija

Kada 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(constint x) {

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

} // Greška, redefinicija

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


Preoptere enje funkcija5

Preopterećenje funkcija

Prvi 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.


Preoptere enje funkcija6

Preopterećenje funkcija

Treć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.


Preoptere enje funkcija7

Preopterećenje funkcija

Rang lista konverzija prema kvaliteti je sljedeća:

Egzaktno podudaranje

Integralna promocija

Standardna konverzija

Konverzija definirana u klasi


Preoptere enje funkcija8

Preopterećenje funkcija

Primjer:

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);


Preoptere enje funkcija9

Preopterećenje funkcija

Primjer:

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.


Preoptere enje funkcija10

Preopterećenje funkcija

Primjer:

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);


Preoptere enje funkcija11

Preopterećenje funkcija

Primjer:

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.


Preoptere enje funkcija12

Preoptereć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(constint & x) {

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

}


Preoptere enje funkcija13

Preopterećenje funkcija

Ako funkcija dobiva referencu na const objekt, onda je poziv korektanjedino 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.


Preoptere enje funkcija14

Preopterećenje funkcija

Posve je analogna situacija s pokazivačima na konstantan i nekonstantan objekt.

void f(int * x) {

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

}

void f(constint * x) {

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

}


Preoptere enje funkcija15

Preopterećenje funkcija

Napomena: 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);


Preoptere enje funkcija16

Preopterećenje funkcija

Ne 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


Preoptere enje funkcija17

Preopterećenje funkcija

class Klasa{

int i;

public:

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

};

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

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

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

intmain() {

Klasa k(2);

f(2);

f(1.2);

f(k);

return 0;

}


Preoptere enje funkcija18

Preopterećenje funkcija

class Klasa{

int i;

public:

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

};

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

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

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

intmain() {

Klasa k(2);

f(2);

f(1.2);

f(k);

return 0;

}


Preoptere enje funkcija19

Preopterećenje funkcija

class Klasa{

int i;

public:

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

};

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

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

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

intmain() {

Klasa k(2);

f(2);

f(1.2);

f(k);

return 0;

}


Preoptere enje funkcija20

Preopterećenje funkcija

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

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

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

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

int main()

{

shorta=1;

g(a);

return 0;

}


Preoptere enje funkcija21

Preopterećenje funkcija

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

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

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

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

int main()

{

shorta=1;

g(a);

return 0;

}

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


Preoptere enje funkcija22

Preopterećenje funkcija

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

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

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

intmain()

{

short a=1;

g(a);

return 0;

}


Preoptere enje funkcija23

Preopterećenje funkcija

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

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

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

intmain()

{

short a=1;

g(a);

return 0;

}

Poziv funkcije je dvosmislen.


  • Login