You are on page 1of 28

Objektno orijentisano

programiranje 1

Preklapanje operatora
Pojam preklapanja operatora
z Ako su u programu potrebni kompleksni brojevi i operacije nad njima
– pogodno je da se operacije mogu predstaviti standardnim operatorima
– na primer: Complex c1(1,2),c2(3,4),c3; c3=c1+c2;
z C++ dozvoljava preklapanje operatora (operator overloading)
– definišu se nova značenja operatora za korisničke tipove (klase)
– princip je sličan kao kod preklapanja imena funkcija
z Preklopljeni operatori za klasne tipove su specijalne operatorske funkcije
z Operatorske funkcije nose ime operator@
– simbol @ predstavlja neki operator ugrađen u jezik
z Operatorske funkcije preklapaju standaradne operatore (+, -, *, /, ...)
z Pozivanje operatorskih funkcija u izrazima
– može biti notaciono isto kao i korišćenje operatora nad ugrađenim tipovima
– izraz t1@t2 se tumači kao:
z operator@(t1,t2) // za operatorsku prijateljsku funkciju klase
z t1.operator@(t2) // za operatorsku metodu klase

2 Preklapanje operatora 30.10.2005.


Primer operatorskih funkcija
class Complex {
public:
Complex(double,double); /* konstruktor */
friend Complex operator+(Complex,Complex); /* oparator + */
friend Complex operator-(Complex,Complex); /* operator - */
private:
double real, imag;
};
Complex::Complex (double r, double i) : real(r), imag(i) {}
Complex operator+ (Complex c1, Complex c2) {
Complex c(0,0);
c.real=c1.real+c2.real;
c.imag=c1.imag+c2.imag;
return c;
}
Complex operator- (Complex c1, Complex c2) {
return Complex(c1.real-c2.real,c1.imag-c2.imag);
}

Complex c1(1.0,1.0),c2(2.0,2.0),c3(0,0);
c3=c1+c2; /* poziva se operator+(c1,c2) */
c1=c2-c3; /* poziva se operator-(c2,c3) */

3 Preklapanje operatora 30.10.2005.


Organičenja preklapanja operatora
z Postoje neka ograničenja u preklapanju operatora:
– ne mogu da se preklope operatori:
., .*, ::, ?:, sizeof i throw dok svi ostali mogu
– ne mogu da se redefinišu značenja operatora
za primitivne (standardne) tipove podataka
– ne mogu da se uvode novi simboli za operatore
– ne mogu da se menjaju osobine operatora:
n-arnost, prioritet i asocijativnost
– neki operatori imaju posebna ograničenja za preklapanje:
new, delete, i++, i--, =, (), [], ->, (tip)

4 Preklapanje operatora 30.10.2005.


Pravila o preklapanju operatora
z Operatorske funkcije mogu biti:
– metode
z kod kojih je skrivreni argument levi (za binarne) ili jedini (za unarne) operand
z po prirodi stvari, levi operand mora biti tipa klase čija je metoda članica
– globalne prijateljske funkcije
z kod kojih je bar jedan argument tipa date klase
z Za korisničke tipove su unapred definisani sledeći operatori:
– = (dodela vrednosti), & (uzimanje adrese), .(pristup članu), , (lančanje)
– sve dok ih korisnik ne redefiniše (osim .), oni imaju podrazumevano značenje
z Za izvedene (pokazivačke) tipove iz korisničkih tipova definisani su:
– * (indirektno adresiranje), -> (posredan pristup članu), [] (indeksiranje)
– sve dok ih korisnik ne redefiniše, i oni imaju podrazumevano značenje
z Vrednosti operatorskih funkcija mogu da budu bilo kog tipa, pa i void
z Ako se simbol operatora sastoji od slova (npr. new),
mora se pisati odvojeno od ključne reči operator
z Operatorske f-je ne mogu da imaju podrazumevane vrednosti argumenata
5 Preklapanje operatora 30.10.2005.
Bočni efekti i veze između operatora
z Bočni efekti koji postoje kod operatora za primitivne tipove
ne podrazumevaju se za preklopljene operatore
– bočni efekti postoje kod:
z operatora ++ i –- (prefiksnih i postfiksnih)
z svih operatora dodele (=, +=, -=, *=, ...)
z Veze koje postoje između operatora za primitivne tipove
ne podrazumevaju se za preklopljene operatore
– na primer, ako je definisan operator+, a+=b ne znači automatski a=a+b
– ako je potreban, operator += mora posebno da se preklopi
z Preporuke:
– preklopljeni operatori treba da imaju očekivano značenje (zbog čitljivosti)
z na primer, ako su definisani i operator+= i operator+,
dobro je da a+=b ima isti efekat kao i a=a+b
z operatori dodele treba da menjaju stanje levog operanda
– kada se definišu operatori za klasu, treba težiti da njihov skup bude kompletan
z na primer, ako su definisani operator= i operator+, treba definisati i operator+=
z za definisan operator== treba definisati i operator!=

6 Preklapanje operatora 30.10.2005.


Operatorske metode/glob. funkcije
z Ako je @ neki binarni operator (na primer +), on može da se realizuje:
– kao metoda klase X: <tip> operator@(X)
z poziv a@b se tumači kao: a.operator@(b)
– kao prijateljska globalna funkcija: <tip> operator@(X,X)
z poziv a@b se tumači kao: operator@(a,b)
z Nije dozvoljeno da se u programu nalaze obe ove funkcije
z Kod operatorske metode levi operand je skriveni argument
– ako levi operand treba da bude standardnog tipa
mora se deklarisati globalna prijateljska funkcija u klasi drugog argumenta
– primer: Complex operator-(double d, Complex c) mora biti prijateljska
z Operatorska metoda ne dozvoljava konverziju levog operanda

7 Preklapanje operatora 30.10.2005.


Primer metode/globalne funkcije
class Complex {
double real,imag;
public:
Complex (double r=0, double i=0) : real(r), imag(i) {}
Complex operator+(Complex c)
{ return Complex(real+c.real,imag+c.imag; }
};
class Complex { // alternativno
double real,imag;
public:
Complex (double r=0, double i=0) : real(r), imag(i) {}
friend Complex operator+(Complex,Complex);
};
Complex operator+ (Complex c1, Complex c2) {
return Complex(c1.real+c2.real,c1.imag+c2.imag);
}
void main () {
Complex c1(2,3),c2(3.4);
Complex c3=c1+c2; // c1.operator+(c2) ili operator+(c1,c2)
}

8 Preklapanje operatora 30.10.2005.


Unarni i binarni operatori
z Unarni operator ima samo jedan operand, pa se može realizovati:
– kao metoda bez argumenata:
tip operator@ ()
– kao globalna funkcija sa jednim argumentom:
tip operator@ (X x)
z Binarni operator ima dva argumenta, pa se može realizovati
– kao metoda sa jednim argumentom:
tip operator@ (X xdesni)
– kao globalna funkcija sa dva argumenta:
tip operator@ (X xlevi, X xdesni)

9 Preklapanje operatora 30.10.2005.


Primer unarnih i binarnih operatora
class Complex {
//...
public:
// metoda unarni operator!
Complex operator!();
// globalna f-ja, unarni operator~
friend Complex operator~(Complex);
// metoda binarni operator-
Complex operator-(Complex);
// globalna f-ja, binarni operator+
friend Complex operator+(Complex,Complex);
};

10 Preklapanje operatora 30.10.2005.


Preklapanje new i delete (1)
z Može se preuzeti kontrola nad alokacijom memorije od ugrađenog alokatora
– na primer, kada su objekti klase mali, može se precizno vršiti njihova alokacija,
tako da se smanji režija alokacije
z Za ovakve potrebe mogu se preklopiti operatori new i delete za neku klasu
z Operatorske funkcije new i delete su statičke (static) metode
– čak i ako nisu tako deklarisane, one su statičke
– razlog: one se pozivaju pre nego što je objekat stvarno kreiran, odnosno pošto je uništen
z Unutar tela ovih operatorskih funkcija:
– ne treba eksplicitno pozivati konstruktor, odnosno destruktor
– konstruktor se implicitno poziva posle operatorske funkcije new
– destruktor se implicitno poziva pre operatorske funkcije delete
z Ove operatorske funkcije služe samo da:
– obezbede prostor za smeštanje dinamičkog objekta (new)
– oslobode prostor koji je bio alociran za dinamički objekat (delete)
z Operator new treba da vrati pokazivač na alocirani prostor

11 Preklapanje operatora 30.10.2005.


Preklapanje new i delete (2)
z Ove operatorske funkcije deklarišu se na sledeći način:
– void* operator new (size_t velicina)
– void operator delete (void* pokazivac)
z Tip size_t je celobrojni tip definisan u <stddef.h>
– služi za izražavanje veličina objekata u bajtovima
z Argument velicina daje veličinu prostora koji treba alocirati za objekat
z Stvarni argument za velicina je sizeof(T),
gde je T klasa za koju je preklopljen operator new
z Stvarni argument se formira na osnovu tipa T u operaciji new T
z Argument pokazivac je pokazivač na prostor koji treba osloboditi
z Ako su u klasi T preklopljeni operatori new i delete,
ugrađeni operatori new i delete mogu da se pozivaju:
– eksplicitno, preko operatora :: (::operator new T i ::operator delete pt), ili
– implicitno, kada se dinamički kreiraju objekti koji nisu tipa T
z U slučaju dinamičkih nizova objekata uvek se pozivaju globalni new i delete
z Metode new i delete ne mogu biti virtuelne, ali se nasleđuju

12 Preklapanje operatora 30.10.2005.


Primer preklapanja new i delete
#include <stddef.h>
class XX {
public:
void* operator new (size_t sz)
{ return new char[sz]; }
// koristi se ugrađeni new
void operator delete (void *p)
{ delete [] p; }
// koristi se ugrađeni delete
};

13 Preklapanje operatora 30.10.2005.


Inicijalizacija i dodela vrednosti
z Inicijalizacija objekta pri kreiranju i dodela vrednosti su različite operacije
– inicijalizacija podrazumeva da objekat još ne postoji
– dodela podrazumeva da objekat sa leve strane operatora već postoji
z Inicijalizacija se vrši uvek kada se kreira objekat:
– statički, automatski, klasni član, privremeni i dinamički
z Inicijalizacija poziva konstruktor, a ne operator dodele
– konstruktor se poziva čak iako je notacija za inicijalizaciju simbol =
– ako je izraz sa desne strane = istog tipa kao i objekat koji se kreira,
poziva se konstruktor kopije
z ovaj konstruktor najčešće kopira ceo složeni objekat, a ne samo članove
z Dodelom se naziva izvršavanje izraza sa operatorom dodele =
– operator dodele se može preklopiti pisanjem operatorske funkcije operator=
z Podrazumevano značenje operatora = je kopiranje objekta član po član
– pri kopiranju članova tipa klase
z pozivaju se operatori = klasa kojima članovi pripadaju
– ako je član klase tipa pokazivača
z kopiraće se samo taj pokazivač, a ne i pokazivana vrednost
z kada treba kopirati i pokazani objekat treba da se preklopi operator=

14 Preklapanje operatora 30.10.2005.


Preklapanje operatora dodele
z Operatorska funkcija operator= mora biti nestatička metoda
z Operatorska funkcija = se najčešće realizuje tako da:
– prvo uništava prethodno formirane delove objekta,
– zatim formira nove, uz kopiranje delova objekta sa desne strane =
z Problem se pojavljuje kod izraza a=a
– rešenje je sledeće:
X& X::operator=(const X &x){
if (&x != this) {
/* uništava se sadržaj delova starog *this,
formira novi i kopira iz x */}
return *this;
}
z Ako neka klasa sadrži destruktor, konstruktor kopije ili operator=
– sva je prilika da treba da sadrži sva tri

15 Preklapanje operatora 30.10.2005.


Primer preklapanja operatora =
class String {
public:
String(const char*); // konstruktor
String(const String&); // konstruktor kopije
~String(); // destruktor
String& operator=(const String&); // operator dodele
private:
char *tekst;
};
String::String(const String &s) {
if (tekst=new char [strlen(s.tekst)+1]) strcpy(tekst,s.tekst);
}
String::~String() {
delete [] tekst;
}
String& String:operator=(const String &s) {
if (&s!=this) { // provera na s=s
if (tekst) delete [] tekst; // prvo oslobodi staro,
if (tekst=new char [strlen(s.tekst)+1]) strcpy(tekst,s.tekst);
// pa onda zauzmi novo
}
return *this;
}
void main () {
String a("Hello world!"), b=a; // String(const String&);
a=b; // operator=
}

16 Preklapanje operatora 30.10.2005.


Preklapanje operatora ++ i --
z Problem: postoje prefiksne i postfiksne varijante operatora ++ i --
z Za preklapanje prefiksnih oblika operatora ++ i --:
– koriste se uobičajene operatorske funkcije:
z u obliku metode klase T bez argumenata: T operator@@()
z u obliku funkcije prijatelja klase T sa jednim argumentom: T operator@@(T)
z Za preklapanje postfiksnih oblika operatora ++ i --:
– operatorska funkcija sadrži i jedan dodatni arument tipa int i to:
z u obliku metode klase T sa jednim argumentom: T operator@@(int)
z u obliku funkcije prijatelja klase T sa dva argumenta: T operator@@(T, int)
z Ako se postfiksna operatorska funkcija poziva korišćenjem operatora @@
argument tipa int ima vrednost 0
z Ako se za postfiksnu funkciju koristi notacija t.operator@@(k) ili
operator@@(t,k) može biti k!=0

17 Preklapanje operatora 30.10.2005.


Preklapanje operatora ()
z Operator () je binarni operator kojem odgovara funkcija operator()()
z Operatorska funkcija operator()() mora da bude nestatička metoda
– funkcija operator()() ne može da bude globalna prijateljska funkcija
z Argumenti:
– proizvoljan broj proizvoljnog tipa
z Pozivanje:
– f(a1,...,aN) je ekvivalent izrazu f.operator()(a1,...,aN)
z Preklapanje operatora() u nekoj klasi
omogućava izraze sa o(a1,...,aN), gde je o objekat date klase
z Primer:
P p; float x;
– ako je P klasa polinoma,
– može se pisati p(x) za vrednost polinoma u x,
ako se preklopi funkcija operator()(float)

18 Preklapanje operatora 30.10.2005.


Preklapanje operatora [] (1)
z Operator [] je binarni operator kojem odgovara funkcija operator[]()
z Operatorska funkcija operator[]() mora da bude nestatička metoda
– funkcija operator[]() ne može da bude globalna prijateljska funkcija
z Argument:
– kod standardnog indeksiranja indeksni izraz mora biti celobrojnog tipa
– kod preklopljenog operatora [] indeksni izraz može biti proizvoljnog tipa
z Pozivanje:
– niz[ind] je ekvivalent izrazu niz.operator[](ind) za objekat niz
z Preklapanje operatora [] u nekoj klasi
omogućava izraze sa o[i], gde je o objekat date klase
z Moguće primene:
– klasa čiji su objekti nizovi sa zadatim granicama indeksa:
funkcija indeksiranja može da proverava granice
– asocijativni pristup komponentama niza

19 Preklapanje operatora 30.10.2005.


Preklapanje operatora [] (2)
z Ako izraz sa operatorom [] može da bude prvi operand operacije =
– na primer: o[i]=izraz;
– tip funkcije operator[]() treba da bude referenca na objekat
z Izraz sa preklopljenim operatorom [] nije indeksiranje
već samo notacijski isto izgleda
– operatorska funkcija operator[]() dejstvuje na objekat svoje klase,
a ne na niz objekata, kao standardni operator []
z Prirodno je da struktura objekta bude kolekcija elemenata,
a da se operatorom [] odabira neka komponenta

20 Preklapanje operatora 30.10.2005.


Preklapanje operatora ->
z Operator -> je unarni operator kojem odgovara funkcija operator->()
z Operatorska funkcija operator->() mora da bude nestatička metoda
– funkcija operator->() ne može da bude globalna prijateljska funkcija
z Argumenti:
– funkcija operator->() mora biti bez argumenata
z Pozivanje:
– o->clan je ekvivalent izrazu (o.operator->())->clan
z Rezultat:
– treba da bude tipa pokazivača na klasu koja sadrži clan
– bude objekat (ili referenca) klase za koju je takođe definisan operator->
z Primena:
– pristup članovima objekata preko "pametnih pokazivača"

21 Preklapanje operatora 30.10.2005.


Primer preklapanja operatora ->
z Odbrojavaju se indirektni pristupi objektu:
struct X{int m};
class Xptr {
X *p; int bp;
public:
Xptr(X *px):p(px),bp(0){} // konstruktor
X& operator*() {bp++; return *p;}
X* operator->(){bp++; return p;}
};
void main(){
X x; Xptr p=&x; // poziva se konstruktor
(*p).m=1; // poziva se (p.operator*()).m;
int i=p->m; // poziva se (p.operator->())->m;
}

22 Preklapanje operatora 30.10.2005.


Preklapanje operatora (tip) (1)
z Preklapanje cast operatora je drugi način za konverziju klasnih tipova
– prvi način konverzije korisničkih tipova je pomoću konstruktora
z Operator (T) je unarni operator kojem odgovara funkcija operator T()
– funkcija treba da izvrši konverziju objekta klase čiji je član u tip T
– T može da bude standardni, izvedeni (npr. pokazivač) ili klasni tip
z Operatorska funkcija operator T() mora da bude nestatička metoda
– funkcija operator T() ne može da bude globalna prijateljska funkcija
z Argumenti:
– funkcija nema argumente (unarni operator, član klase)
z Pozivanje:
– (U)t ili U(t) je ekvivalent izrazu t.operator U()
– drugi oblik je notacijski isti kao da je u pitanju konstruktor U
– moguć oblik je i statički kast: static_cast<U>(t)
z Rezultat:
– tip rezultata funkcije ne sme da bude naveden u deklaraciji/definiciji
– podrazumeva se na osnovu imena funkcije

23 Preklapanje operatora 30.10.2005.


Preklapanje operatora (tip) (2)
z Za razliku od konstruktora U(t) preklopljeni operator U(t)
– može da se koristi za U koje je standardni tip
– argument T t mora biti objekat klase, odnosno T ne može biti primitivan tip
z Primer:
int(x) - konvertuje x tipa X u tip int
z Oblik notacije U(t) ne može da se koristi za tipove sa većim brojem reči
z Primer:
(unsigned long) x nije isto što i unsigned long(x)
z Konverzija se primenjuje automatski, ako je jednoznačan izbor konverzije
– ako je definisan konstruktor kopije U(T) i operatorska funkcija T::operator U(),
u=t je dvoznačno
– ako su definisane obe konverzije U(t) i T(u), i operator + za tipove U i T
prevodilac ne može automatski da odredi konverziju za u+t
z Problem sa konverzijom tipa pri prenosu parametara po referenci
– rezultat konverzije stvarnog argumenta je privremeni objekat,
pa se u funkciju prenosi njegova adresa
– izmene u funkciji se odnose na taj privremeni objekat

24 Preklapanje operatora 30.10.2005.


Standardni U/I tokovi
z Kao ni jezik C, ni C++ ne sadrži ugrađene U/I naredbe
– one se realizuju standardnim bibliotekama
z Za C++ postoje standardne U/I biblioteke realizovane u duhu OOP-a
z Na raspolaganju su i stare C biblioteke sa funkcijama scanf i printf
– njihovo korišćenje nije u duhu C++ i treba izbegavati
z Deklaracije C++ biblioteke za U/I nalaze u zaglavlju <iostream.h>
z Biblioteka iostream sadrži dve osnovne klase za U/I:
– istream (apstrakcija ulaznog toka)
– ostream (apstrakcija izlaznog toka)
z Iz navedenih klasa su izvedene klase ifstream i ofstream
– objektu klase ifstream/ofstream može da se pridruži jedna datoteka za U/I
z Datotekama se pristupa isključivo preko ovakvih objekata
– odnosno funkcija članica ili prijatelja ovih klasa

25 Preklapanje operatora 30.10.2005.


Standardni objekti i operacije za U/I
z U biblioteci iostream definisana su i dva globalna statička objekta:
– objekat cin klase istream
z koji je pridružen standardnom ulaznom uređaju (obično tastatura)
– objekat cout klase ostream
z koji je pridružen standardnom izlaznom uređaju (obično ekran)
z Klasa istream je preklopila operator>> za sve ugrađene tipove,
koji služi za ulaz podataka:
– istream& operator>>(istream &is, T &t);
– gde je T neki ugrađeni tip objekta koji se čita
z Klasa ostream je preklopila operator<< za sve ugrađene tipove,
koji služi za izlaz podataka:
– ostream& operator<<(ostream &os, const T& x);
– gde je T neki ugrađeni tip objekta koji se ispisuje

26 Preklapanje operatora 30.10.2005.


Korišćenje operatora >> i <<
z Operatorske funkcije operator>> i operator<<
– vraćaju referencu na levi operand
z posledica: može se vršiti višestruki U/I u istoj naredbi
– operatori su asocijativni sleva
z posledica: podaci se ispisuju/učitavaju u prirodnom redosledu
z Operatore >> i << treba koristiti za jednostavne U/I operacije
z Primer:
#include <iostream.h>
void main () {
int i;
cin>>i;
cout<<"i="<<i<<endl;
}

27 Preklapanje operatora 30.10.2005.


Preklapanje operatora >> i <<
z Korisnik može da definiše značenja operatora >> i << za svoje tipove
– to se postiže definisanjem odgovarajućih globalnih funkcija prijatelja date klase
z Razlog zbog kojeg preklopljen operator ne može biti metoda:
– prvi operand je tipa istream& odnosno ostream&
z Primer za klasu Complex:
#include <iostream.h>
class Complex {
double real,imag;
friend ostream& operator<< (ostream&,const Complex&);
public:
//... kao i ranije
};
ostream& operator<< (ostream &os, const Complex &c) {
return os<<"("<<c.real<<","<<c.imag<<")";
}
void main () {
Complex c(0.5,0.1);
cout<<"c="<<c<<endl; // ispisuje se: c=(0.5,0.1)
}

28 Preklapanje operatora 30.10.2005.

You might also like