51
1 Lekcija 4 – Preklapanje operatora Pregled 1.1 Pojam preklapanje operatora 1.2 Operatorske funkcije 1.3 Bočni efekti i veze 1.4 Preklapanje ++ i -- 1.5 Preklapanje () 1.6 Preklapanje [] 1.7 Preklapanje -> 1.8 Preklapanje new i delete 1.9 Preklapanje = 1.10 U/I tokovi 1.11 Preklapanje >> i << 1.12 Inicijalizacija i dodjela 1.13 Konverzije tipova

04 - Preklapanje operatora

Embed Size (px)

DESCRIPTION

Prezentacija o preklapanju operatora u C++.

Citation preview

  • Lekcija 4 Preklapanje operatora Pregled1.1Pojam preklapanje operatora1.2Operatorske funkcije1.3Boni efekti i veze1.4Preklapanje ++ i --1.5Preklapanje ()1.6Preklapanje []1.7Preklapanje ->1.8Preklapanje new i delete1.9Preklapanje =1.10U/I tokovi1.11Preklapanje >> i
  • Ciljevi lekcijeU ovoj lekciji:Upoznavanje sa osnovim pojmovima vezanim za preklapanje operatoraDefinisanje operatorskih funkcija Predefinisanje operatora ++, --, (), [], ->, new i delete Predefinisanje operatora dodjele i razlike u odnosu na inicijalizacijuOsnovne ulazno/izlaznih tokova i operatori >> i
  • 1.1 Pojam preklapanja operatora Znaenje operatora ugraenih u jezik mogue je definisati za korisnike tipove (klase) Preklapanje operatora (engl. operator overloading)Slian princip kao kod preklapanja funkcija Ako je za operator definisano novo znaenje onda se kae da je on preklopljen Poveavanje itljivosti koda Primjer: Klasa koja predstavlja kompleksne brojeve i operacija sabiranja Bilo bi pogodno da moemo koristiti operator + nad objektima ove klase

  • 1.1 Pojam preklapanja operatoraclass Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i){}; Complex add(Complex c1) { Complex rez; rez.re = this->re + c1.re; rez.im = this->im + c1.im; return rez; }};

    int main(){ Complex c1(1.0,2.0), c2(4.5,5.6), c3; c3 = c1.add(c2); return 0;}

  • 1.2 Operatorske funkcijeZnaenje operatora za korisniki tip definie se putem operatorskih funkcija Imaju posebna imena operator@Simbol @ oznaava neki operator ugraen u jezik Npr. operator+Ove funkcije preklapaju standardne operatore (+,-, , /, * itd.)Osim eksplicitnog poziva preko imena mogu se pozivati koristei notaciju koja se koristi za operatore nad ugraenim tipovimaIzraz t1@t2 se tumai kao:operator@(t1,t2) // za operatorsku prijateljsku funkciju klaset1.operator@(t2) // za operatorsku metodu klase

  • 1.2 Operatorske funkcijeclass Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i){}; friend Complex operator+(Complex c1, Complex c2); void Print(){cout
  • 1.2 Operatorske funkcijeclass Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i){}; Complex operator-(Complex c1); Complex operator+(float f){return Complex(this->re + f, this->im);} void Print(){cout
  • 1.2 Operatorske funkcijeNije mogue Promijeniti prioritet, asocijativnost i broj operanda operatora u odnosu na svojstva koja su ugraena u jezik Npr. nije mogue definisati da prekolopljeni operator + ima vei prioritet u odnosu na preklopljeni operator *Predefinisati operatore za ugraene tipove Npr. nije dozvoljeno Complex operator+(float, float)Uvoditi nove operatore u jezikPreklopiti operatore ., .*, ::, ?:, sizeof i throw dok svi ostali moguNeki operatori imaju posebna ogranienja za preklapanje: new, delete, i++, i--, =, (), [], ->, (tip)

  • 1.2 Operatorske funkcijeOperatorska funkcija moe biti Funkcija lanica klase Neka je @ binarni opererator, tada operatorska funkcije koja je funkcija lanica treba da se realizuje kao T operator@(Y)Prvi operand mora biti objekat klase kojoj operatorska funkcija pripada Drugi operator mora biti tipa argumenta Npr. ako u klasi Complex postoji definisana operatorska funkcija Complex operator+(float f), onda prvi argument mora biti objekat klase Complex. Drugi argument mora biti tipa float. Globalna funkcija (najee prijateljska)Neka je @ binarni opererator, tada operatorska funkcije koja je globalna treba da se realizuje kao T operator@(X,Y)

  • 1.2 Operatorske funkcijeUnarni operator ima samo jedan operand, pa se moe realizovati: kao metoda bez argumenata: tip operator@ ()kao globalna funkcija sa jednim argumentom: tip operator@ (X x)Binarni operator ima dva argumenta, pa se moe realizovati kao metoda sa jednim argumentom: tip operator@ (X xdesni)kao globalna funkcija sa dva argumenta: tip operator@ (X xlevi, X xdesni)

  • 1.2 Operatorske funkcijeclass Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i){}; void Print(){cout
  • 1.3 Sporedni efekti i vezeBoni efekti koji postoje kod operatora za primitivne tipove ne podrazumijevaju se za preklopljene operatoreBoni efekti postoje kod:Operatora ++ i - (prefiksnih i postfiksnih) Svih operatora dodjele (=, +=, -=, *=, ...)Veze koje postoje izmeu operatora za primitivne tipove ne podrazumijevaju se za preklopljene operatoreNpr., ako je definisan operator+, a+=b ne znai automatski a=a+bAko je potreban, operator += mora posebno da se preklopi

  • 1.3 Sporedni efekti i vezePreporuke:Preklopljeni operatori treba da imaju oekivano znaenje (zbog itljivosti)Npr., ako su definisani i operator+= i operator+, dobro je da a+=b ima isti efekat kao i a=a+b Operatori dodjele treba da mijenjaju stanje lijevog operandaKada se definiu operatori za klasu, treba teiti da njihov skup bude kompletanNpr., ako su definisani operator= i operator+, treba definisati i operator+=Za definisan operator== treba definisati i operator!=

  • 1.3 Sporedni efekti i vezeU nekim sluajevima bitno je da li je operatorska funkcija definisana kao globalna funkcija, ili kao funkcija lanica. Ako je operatorska funkcija definisana kao funkcija lanica, bie onemogueno vrenje implicitne konverzije Za globalne funkcije to je dozvoljenoAko operatorske funkcije mijenjaju stanje (+=) objekta poeljno je da budu funkcije laniceMogu i globalne iji je odgovarajui operator referenca

  • 1.3 Sporedni efekti i vezeclass Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i){} friend Complex operator+(Complex c1, Complex c2);};

    Complex operator+(Complex c1, Complex c2){ return Complex(c1.re + c2.re, c1.im + c2.im);}

    int main(){ Complex c1(1,2); Complex c2(1,2); Complex c3; c3 = 1.0 + c2;//dozvoljeno, postoji odgovarajui konstruktor koji se moze pozvati}

  • 1.3 Sporedni efekti i vezeclass Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i){}Complex operator+(Complex c1);};

    Complex Complex::operator+(Complex c1){ return Complex(this->re + c1.re, this->im + c1.im);}

    int main(){ Complex c1(1,2); Complex c2(1,2); Complex c3; c3 = 1.0 + c2;//Greska}

  • 1.3 Sporedni efekti i vezeRezultat je lvrijednost ako i samo ako funkcija vraa referencu Ovo vai za sve operatorske funkcije Termin lvrijednost oznaava izraz koji se odnosi na neki objekat ili funkcijuNajee, u pitanju je izraz koji se moe nai sa lijeve strane znaka jedankosti U C++ neki operatori (=, +=) vraaju lvrijednost, tj. mogu se nai sa lijeve strane znaka dodjeleNpr. izraz (a+=4) = 5; je dozvoljen u C++Bez obrzira na prethodno stanje varijabla a dobija vrijednost 5Ako neki operator vraa lvrijednost, onda je preporuljivo da preklopljeni operator takoe vraa lvrijednost

  • 1.3 Sporedni efekti i vezeclass Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i){}friend Complex& operator+=(Complex& c1, Complex c2);};

    Complex& operator+=(Complex& c1, Complex c2){ c1.im = c1.im + c2.im; c1.re = c1.re + c2.re; return c1;}int main(){ Complex c1(1,2); Complex c2(5,6); Complex c3(3,4); (c2 += c1) = c3; //c2 dobija vrijednost c3 return 0;}

  • 1.4 Preklapanje ++ i --Komplikovaniji je postoji i prefiksna i postfiksna varijanta Preklapanje prefiksnog operatora ++ vri se putem uobiajenih operatorskih funkcija Kao funkcija lanica - T operator++()Kao globalna funkcija - T operator++(T)Analogno vai i za --Preklapanje postfiksnog operatora ++ vri se Kao funkcija lanica - T operator++(int)Kao globalna funkcija - T operator++(T, int)Ako se drugi stvarni argument ne navede bie 0Ne moe se navesti kada se funkcija poziva kao operatorMoe se navesti kada se funkcija poziva direktno t.operator++(k) Analogno vai i za --

  • 1.4 Preklapanje ++ i --class Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i){}; void Print(){cout
  • 1.4 Preklapanje ++ i --int main(){ Complex c1(1.0,2.0), c2; cout
  • 1.5 Preklapanje ()Odgovara mu funkcija operator()()Mora da bude nestatika funkcija Ne moe da bude globalna funkcijaIma proizvoljan broj argumenataSvaki argument moe da bude proizvoljnog tipa Poziva se f(a1,...,aN) To je ekvivalent f.operator()(a1,...,aN)Rezultat je lvrijednost ako i samo ako funkcija vraa referencu Ovo vai za sve operatorske funkcije Termin lvrijednost oznaava izraz koji se odnosi na neki objekat ili funkcijuNajee, u pitanju je izraz koji se moe nai sa lijeve strane znaka jedankosti

  • 1.5 Preklapanje ()class Matrix{ private: int** mat; int r; int c; public: Matrix(int r, int c); ~Matrix(); int& operator()(int i, int j);};

    Matrix::Matrix(int r, int c) :r(r), c(c){ mat = new int*[r]; for(int i = 0; i < r; i++) {mat[i] = new int[c];}}

    Matrix::~Matrix(){ for(int i = 0; i < r; i++) {delete new int[c];} delete mat;}

    int& Matrix::operator()(int i, int j){ return mat[i][j];}

  • 1.5 Preklapanje ()int main(){ Matrix m(3,3); m(0,0) = 1;//lvrijednost, moze se naci sa //lijeve strane znaka jednakosti cout
  • 1.6 Preklapanje []Odgovara mu funkcija operator[]()Mora da bude nestatika funkcija Ne moe da bude globalna funkcijaIma tano jedan argumentMoe da bude proizvoljnog tipa Poziva se niz[ind] To je ekvivalent niz.operator[](ind)Najea upotreba Kod objekata koji predstavljaju neke kolekcije

  • 1.6 Preklapanje []class Array{ private: int* a; int num; public: Array(int num); ~Array(); int& operator[](int i);};

    Array::Array(int num) : num(num){ a = new int[num];}

    Array::~Array(){delete a;}

    int& Array::operator[](int i){ return a[i];}

    int main(){ Array a(3); a[0] = 1; cout

  • 1.7 Preklapanje ->Unarni operator kojem odgovara funkcija operator->()Mora da bude nestatika funkcija Ne moe da bude globalna funkcijaMora da bude bez argumenataMoe da bude proizvoljnog tipa Poziva se o->clan To je ekvivalent (o.operator->()(ind))->clanNajea upotreba Pristup lanovima preko pametnih pokazivaa Broji pristupe

  • 1.7 Preklapanje ->class X{ public: int data;};

    class Y{ private: X* xPtr; int num; public: Y(X* xPtr) : xPtr(xPtr), num(0){}; X* operator->(){num++; return xPtr;}; int getNum(){return num;}};

    int main(){ X x; Y y(&x); y->data = 5; //(poziva se y->operator->)->data cout

  • 1.8 Preklapanje new i deletePredefinisanjem operatora new vri se kontrola nad alokacijom memorijeZa male objekte moe se vriti precizno alokacija i optimizovati taj postupak Operatorske funkcije new i delete su uvijek statikeKada su pozvane objekat jo uvijek ne postojiUnutar tijela nije potrebno pozivati konstruktor, tj. destruktorOni su implicitno pozvani Operator new treba da vrati pokaziva na alocirani prostor

  • 1.8 Preklapanje new i deleteOperatorska funkcija new void* operator new (size_t sz)Argument sz je cjelobrojni i prestavlja broj bajta koje treba alocirati Vraa generiki pokaziva void*, tj. pokaziva na zauzetu memoriju Operatorska funkcija new definie se void operator delete (void* ptr)Ima jedan argument ptr koji je pokaziva na memoriju koju treba osloboditi

  • 1.8 Preklapanje new i deleteclass X{ private: static int num; public: void* operator new (size_t sz); void operator delete (void* ptr);};int X::num = 0;

    void* X::operator new(size_t sz){ if (num == 10) {cout

  • 1.9 Preklapanje =Binarni operator kojem odgovara funkcija operator= Mora da bude nestatika funkcija Ne moe da bude globalna funkcijaMora da ima jedan argument Moe da bude proizvoljnog tipa Poziva se o=izraz To je ekvivalent o.operator=(izraz)Uvijek je treba definisati kada prosto dodjeljivanje lan po lan nije loginoSlian problem kod konstruktora kopije

  • 1.9 Preklapanje =class Array{ private: int* a; int num; public: Array(int num): num(num){a = new int[num];}; ~Array(){delete a;}; int& operator[](int i) {return a[i];};};

    int main(){ Array a1(3), a2(2); a1[0] = 1; a2 = a1; a2[0] = 5; cout

  • 1.9 Preklapanje =

  • 1.9 Preklapanje =class Array{ //isto ka raniije Array& operator=(Array& arr);};

    Array& Array::operator=(Array& arr){ //izbjegavanje a=a problema if (this == &arr){return *this;}

    delete a; num = arr.num; a = new int[num]; for(int i = 0; i < num; i++) a[i] = arr.a[i];

    return *this;}

    int main(){ Array a1(3), a2(2); a1[0] = 1; a2 = a1; a2[0] = 5; cout

  • 1.9 Preklapanje =

  • 1.10 U/I tokoviU C++ ne postoje naredbe ugraene u jezik koje su namijenjene ulazno/izlaznim operacijama U tu svrhu se koriste standardne bibliotekeIsto vai i za programski jezik CStadardne biblioteke za U/I realizovane su u duhu OOP-aDeklaracije biblioteka nalaze u zaglavlju Definisani su pojmovi ulaznog i izlaznog toka Logiki pojmovi koji se odnose na ulazi i izlaz niza znaka na ureaj ili datotekuBiblioteka iostream sadriKlasu istream koja realizuje ulazni tok Klasu ostream koja realizuje izlazni tok

  • 1.10 U/I tokoviIz navedenih klasa izvedene su klase ifstream i ofstreamJednom objektu klase ifstream/ofstream moe da se pridrui jedna datoteka ili ureaj za U/IU biblioteci iostream definisana su i dva globalna statika objekta:Objekat cin klase istream koji je pridruen standardnom ulaznom ureaju (obino tastatura)Objekat cout klase ostream koji je pridruen standardnom izlaznom ureaju (obino ekran)Klasa istream sadri po jednu operatorsku funkciju operator>> za svaki ugraeni tip podatkaistream& operator>>(istream &is, Tip &t);Gdje Tip oznaava neki ugraeni tip

  • 1.10 U/I tokoviKlasa ostream sadri po jednu operatorsku funkciju operator
  • 1.11 Preklapanje >> i
  • 1.11 Preklapanje >> i
  • 1.12 Inicijalizacija i dodjelaPostoji razlika izmeu pojmova inicijalizacije i dodjele Inicijalizacija se vri nad objektom u fazi kreriranjaVri se samo jednomDefinie poetno stanje objekta Dodjela se vri nad postojeim objektom Moe se vriti proizvoljan broj puta Mijenja postojee stanje objekta Kada se objekat inicijalizuje objektom iste klase poziva se konstruktor, a ne operator dodjeleKonstruktor 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

  • 1.12 Inicijalizacija i dodjelaOperacija dodjele vri se u okviru naredbe dodjele (operator =)Operator dodjele se moe preklopiti pisanjem operatorske funkcije operator=Podrazumijevano ponaanje je kopiranje objekta lan po lan Pri kopiranju lanova klase pozivaju se operatori = za lanove klase Problem:Ako je lan klase pokazi izvrie se tzv. plitko dodjeljivanje, tj. kopiranje pokazivaa, ali ne i sadrajaPraktino pravilo Ako klasa ima konstruktor kopije, operator dodjelje ili destruktor, onda najvjerovatnije treba da ima sva tri

  • 1.12 Inicijalizacija i dodjelaclass Array{ private: int* a; int num; public: Array(int num); Array(Array& arr); ~Array(){delete a;}; int& operator[](int i) {return a[i];}; Array& operator=(Array& arr); friend bool operator==(Array& arr1, Array& arr2); friend ostream& operator
  • 1.12 Inicijalizacija i dodjelaArray::Array(Array& arr): num(arr.num){ cout
  • 1.12 Inicijalizacija i dodjelabool operator==(Array& arr1, Array& arr2){ cout
  • 1.12 Inicijalizacija i dodjelaint main(){ Array a1(2); a1[0] = 1; a1[1] = 2; cout
  • 1.12 Inicijalizacija i dodjelaclass Point{ private: float x; float y; public: Point(float x = 0.0, float y = 0.0) : x(x), y(y) {cout
  • 1.13 Konverzije tipovaKonverzija tipova moe se vriti putem konstr.

    class Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i) {cout

  • 1.13 Konverzije tipovaDrugi nain jeste definisanje operatorske funkcije za konverziju Operatorska funkcija lanica klase X koja ima oblik operator T() definie konverziju iz tipa X u tip TOperatorska funkcija operator T() ne moe da bude statika metoda, niti moe da bude globalna prijateljska funkcija Nema argumente U pitanju je unarni operator Tip povratnog rezultata se ne navodi u deklaracijiPodrazumijeva se na osnovu imena funkcije

  • 1.13 Konverzije tipovaclass Complex{ private: float re; float im; public: Complex(float r = 0.0, float i = 0.0) : re(r), im(i){}; operator float(){return re;}};

    int main(){ Complex c1(1.2, 2.3); float f; f = c1; cout