You are on page 1of 8

3.12.2018.

Teme

Reference objekta
Korištenje referenci
Prosljeđivanje po vrijednosti vs. prosljeđivanje po referenci
Kopiranje objekata
Kopirajući konstruktor

Objektno-orijentirano programiranje
u programskom jeziku C++

3.12.2018. 1 3.12.2018. 2

Reference Referenca na jednostavni tip varijable (objekt)


Referenca = alias, sinonim, nadimak, drugo ime za varijablu (objekt) s kojim
sve što se radi s referencom napravljeno je i na varijabli (objektu) čiji je
je inicijalizirana
ona alias i obrnuto:
referenca se MORA inicijalizirati; mora se na nešto odnositi!
primjer:
operator adrese (&) koristi se za deklariranje reference int Var;
Sintaksa: (pretpostavka, neka je dano: tip var; ili tip var = inicijalna_vrijednost;) int & refVar = Var;
tip &referenca = var; refVar = 10;
std::cout<<"\n vrijednost od var je:" << Var;
Primjer:
std::cout<<"\n vrijednost od ref je:" << refVar;
int Var = 10;
Var = 100;
int & refVar = Var; //refVar je referenca na varijablu Var;
std::cout<<"\n vrijednost od var je:" << Var;
adresa reference = adresi objekta čiji je alias std::cout<<"\n vrijednost od ref je:" << refVar;
Primjer: Var = refVar;
cout<<"\n adresa &Var: " <<&Var; //ref. i var imaju istu adresu (npr. 002BFF08) std::cout<<"\n vrijednost od var je:" << Var;
cout<<"\n adresa &refVar: " <<&Var; // & je op. adrese std::cout<<"\n vrijednost od ref je:" << refVar;

3.12.2018. 3 3.12.2018. 4

Referenca se odnosi samo na 1 objekt Referenca objekta (instanca klase)


Referenca se uvijek odnosi na objekt čiji je alias, ne može se odnositi na
Primjer reference objekta (NE klase!):
neki drugi objekt!
primjer: Macka Suzi;
int Var1 = 100; Macka &refSuzi = Suzi; //refSuzi je referenca objekta Suzi klase Macka
int & refVar = Var1;
int Var2 = 1;
Sa referencom na objekt manipulira se jednako kao i sa samim objektom:
std::cout<<"\n vrijednost od Var1 je:" << Var1;
Primjer:
std::cout<<"\n vrijednost od refVar je:" << refVar;
cout << refSuzi.GetTezina(); //referenca pristupa članskim funkcijama

refVar = Var2; // koji je raz?


std::cout<<"\n vrijednost od Var1 je:" << Var1;
std::cout<<"\n vrijednost od refVar je:" << refVar;
std::cout<<"\n vrijednost od Var2 je:" << Var2;

3.12.2018. 5 3.12.2018. 6

OOP – C++, M. Ivašić-Kos 1


3.12.2018.

Primjer: referenca na objekt Kopiranje varijabli primitivnih tipova i tipova objekata


#include <iostream> referenca na
using namespace std; objekt kvd
void main(){
class Kvadrat{ Neka je: Neka je:
Kvadrat kvd; int Var1 = 2; Kvadrat kvd;
private: int & refVar = Var1; Kvadrat & rkvd = kvd;
cout << "\n Stranica a: " << kvd.getA();
int a;
Kvadrat & rkvd = kvd; Prije: Poslije: refVar=4 Prije: Poslije: rkvd.setA(4)
public:
Var1 2 Var1 4 kvd
Kvadrat(){ kvd
rkvd.setA(4); //mijenja se i vrijednost kvd
cout << "\n Konstruktor...\n"; refVar refVar
cout << "\n Stranica a objekta: " << kvd.getA();
a = 2; rkvd rkvd
cout << "\n Stranica a ref. objekta: " <<
}
rkvd.getA();
~Kvadrat(){ kvd: Kvadrat kvd: Kvadrat
}
cout << "\n Destruktor...\n"; poziv funkcije
iz reference a=2 a=4
}
na objekt kvd
int getA () const { return a; }
void setA (int aa) { a = aa; }
};
3.12.2018. 7

Korištenje referenci Primjeri poziva funkcija


Reference i/ili pokazivači koriste se kao parametri u deklaraciji/ definiciji void Drag (DisplayItem i);
funkcije prilikom: stvara se kopija stvarnog parametra koja označava drugi objekt (ali sa istim stanjem)
Prosljeđivanje vrijednosti funkciji po referenci (engl. passing by reference) stvarni argument može se zaštititi od promjene ključnom riječju const
- slanje funkciji adrese originalnog objekta umjesto njegove kopije koja se kreira unutar preporučljivo je, zbog performansi, predavati reference kao parametre.
dosega funkcije i sprema na stogu (prosljeđivanje po vrijednosti (engl. passing by value));
promjene u funkciji vrše se na originalnom objektu
kako bi funkcija mogla vraćati više vrijednosti void Highlight (DisplayItem &i);
nakon poziva fije. npr. Highlight (Item1) u funkciji se stvara drugo ime (alias) za
Prosljeđivanje vrijednosti funkciji po referenci povećava efikasnost i formalni parametar Item1 koji označava referencu na objekt označen trenutnim
smanjuje broj kopija objekta parametrom
• Svaki puta kada se funkciji proslijedi objekt po vrijednosti, stvara se kopija objekta na
stogu, a još jedna kopija se stvara i kada funkcija vraća objekt. void DisplayItem (const DisplayItem&);
• Za male objekte, kao što su cijeli brojevi, to je malena cijena i po pitanju performansi, i za kontrolu nad predavanjem kopija može se definirati operator kopiranja (tzv. copy
po pitanju zauzeća memorije, ali kod velikih objekata (instance klase ili strukture) constructor):
kopiranje objekata na stog i sa stoga može biti prilično zahtjevno (uključuje implicitne može biti pozvan eksplicitno (kada se deklarira objekt), ili implicitno (prilikom poziva
pozive konstruktora kopije i destruktora). funkcije po referenci)
3.12.2018. 9 3.12.2018. 10

Prosljeđivanje objekata metodama Primjer: Dana je definicija klase


#include <iostream>
using namespace std;
glavna Metoda
me toda ispisPovrsine class Kvadrat{
method int a;
a
public:
n 5 5 P assing by value
(vrije dnost je 5) Kvadrat(){
cout << "\n Pozvan je konstruktor...\n”;
a = 2;
c
}
mojKrug Re fere nca Refere nca P assing by refere nce Kvadrat (Kvadrat &k){ //svaki puta kada se radi kopija objekta, poziva se default copy constructor
(vrije dnost je refere nca na obje kt)
cout << "\n Pozvan je Copy konstruktor...\n";
a = k.a;
}
mojKrug: Krug ~Kvadrat(){ cout << "\n Pozvan je destruktor...\n“; }
int getA() const { return a; }
radius = 1 void setA (int aa) { a = aa; }
};

OOP – C++, M. Ivašić-Kos 2


3.12.2018.

Primjer: Prosljeđivanje objekta po vrijednosti - funkcije Primjer: Prosljeđivanje objekta po vrijednosti – poziv funkcije
void Povrsina1 (Kvadrat kvad){ // poziv po vrijednosti void main(){
Kvadrat kvd;
cout << "\n Stranica a u fiji1: " <<kvad.getA();
cout << "\n Pozivi fije1 (po vrijednosti, vodi) \n”;
cout << "\n Povrsina je " << kvad.getA() * kvad.getA();
Povrsina1(kvd);
kvad.setA(5); cout << "\n Stranica a nakon poziva fije1 (po vrijednosti, void): " << kvd.getA();
cout << "\n Stranica a u fiji1: " <<kvad.getA(); Povrsina2(kvd);
} cout << "\n Stranica a nakon poziva fije2 (po vrijednosti, vraća objekt): " << kvd.getA();
}
Kvadrat Povrsina2 (Kvadrat kvad){ // poziv po vrijednosti, povratni tip instanca Kvadrat
cout << "\n Stranica a u fiji2: " <<kvad.getA();
cout << "\n Povrsina je " << kvad.getA() * kvad.getA();
kvad.setA(10);
cout << "\n Stranica a u fiji2: " <<kvad.getA();
return kvad;
}

3.12.2018. 13 3.12.2018. 14

Primjer: Prosljeđivanje objekta po referenci - funkcije Primjer: Prosljeđivanje objekta po referenci – poziv funkcije
Kvadrat & Povrsina3 ( Kvadrat &kvad){ //poziv po referenci na objekt void main(){
Kvadrat kvd;
cout << "\n Stranica a u fiji3: " <<kvad.getA();
cout << "\n Poziv fije3 (reference) \n”;
cout << "\n Povrsina je " << kvad.getA()*kvad.getA();
Povrsina3(kvd);
kvad.setA(15); //- objekt nije zaštićen od promjena – preporuka const! cout << "\n Stranica a nakon poziva fije3 (reference): " << kvd.getA();
cout << "\n Stranica a u fiji3: " <<kvad.getA(); cout << "\n Poziv fije4 (pokazivaci) \n”;
return kvad; Povrsina4(kvd);
} cout << "\n Stranica a nakon poziva fije2 (pokazivaci): " << kvd.getA();
}
Kvadrat * Povrsina4 ( Kvadrat * kvad){ //poziv po pokazivacu - bolje na const objekt
cout << "\n Stranica a u fiji4: " <<kvad->getA();
cout << "\n Povrsina je " << kvad->getA()*kvad->getA();
kvad->setA(20); //ako je const nije moguće!
cout << "\n Stranica a u fiji4: " <<kvad->getA();
return kvad;
}

3.12.2018. 15 3.12.2018. 16

Prosljeđivanje objekata po vrijednosti i referenci Primjer: Prosljeđivanje objekta po referenci - const objekt
Prosljeđivanje instance klase (objekta) po vrijednosti poziva const Kvadrat & Povrsina3 (const Kvadrat & kvad){ //poziv po referenci na const objekt
podrazumijevani copy konstruktor koji stvara privremenu kopiju cout << "\n Stranica a u fiji3: " <<kvad.getA();
objekta.
cout << "\n Povrsina je " << kvad.getA()*kvad.getA();
Ukoliko funkcija vraćanja vrijednosti (objekt), kad funkcija završi s
radom još jednom se poziva copy konstruktor i potom dva puta //kvad.setA(15); //ako je const nije moguće!
destruktor da bi se uništile dvije novonastale privremene kopije cout << "\n Stranica a u fiji3: " <<kvad.getA();
proslijeđenog objekta funkciji. return kvad;
}
Reference i pokazivači su učinkovitiji, ali dozvoljeno im je mijenjati
vrijednosti varijabli stvarnih objekata – preporuka koristiti const const Kvadrat * Povrsina4 ( const Kvadrat * kvad) //poziv po pokazivaču na const objekt
pokazivač i const objekt
cout << "\n Stranica a u fiji4: " <<kvad->getA();
Const pokazivač može pozivati samo metode koje su u klasi definirane kao const
(ne mijenjaju vrijednost varijablama) cout << "\n Povrsina je " << kvad->getA()*kvad->getA();
Reference se ne mogu preusmjeriti na drugi objekt, stoga su one uvijek // kvad->setA(20); //ako je const nije moguće!
konstantne. cout << "\n Stranica a u fiji4: " <<kvad->getA();
return kvad;
}

3.12.2018. 18

OOP – C++, M. Ivašić-Kos 3


3.12.2018.

Primjer: Prosljeđivanje objekta po referenci – const objekt Korištenje referenci i pokazivača (istovremeno)
void main(){
Kvadrat kvd; Dozvoljeno je deklarirati i pokazivače i reference unutar liste
cout << "\n Pozivi fije3 (reference) \n”;
parametara iste funkcije zajedno sa vrijednostima koje se prosljeđuju
po vrijednosti.
Povrsina3(kvd);
cout << "\n Stranica a nakon poziva fije3 (reference): " << kvd.getA(); Klasa * Funkcija (Klasa1 &objekt1, Klasa2 *objekt2, tip var);
cout << "\n Pozivi fije4 (pokazivaci) \n”;
Povrsina4(kvd); Voditi računa kod navođenja deklaracija pokazivača i referenci da ne dođe do
cout << "\n Stranica a nakon poziva fije4 (pokazivaci): " << kvd.getA(); zabune
Primjer:
}
Macka Tom;
Macka & rTom, rMica; // referenca je samo rTom, a rMica je objekt

Deklaracija dvije reference treba izgledati ovako:


Macka &rTom, &rMica;

3.12.2018. 19 20

Kada koristiti reference, a kad pokazivače? Kopiranje objekata


class Kvadrat{ void main(){
Kada god je moguće koriste se referenci jer su jednostavnije za uporabu i bolje private: Kvadrat kvd2, kvd3;
skrivaju informacije. int a; kvd2=kvd3;
public: kvd2.setA(5);
Voditi računa da se reference uvijek moraju odnositi na neki objekt.
Kvadrat(){ cout << "\n Stranica a ref. na objekt: " << kvd2.getA();
Pri prosljeđivanju referenci u ili iz funkcije uvijek se valja zapitati: Na koji se objekt cout << "\n Pozvan je konstruktor...\n"; cout << "\n Stranica a ref. na objekt: " << kvd3.getA();
one zapravo odnose i postoji li on svaki put kad se funkcija pozove?!
a = 2; kvd3.setA(50);
}; cout << "\n Stranica a ref. na objekt: " << kvd2.getA();
Ako je potrebno preusmjeravanje mora se koristiti pokazivač. ~Kvadrat(){ cout << "\n Stranica a ref. na objekt: " << kvd3.getA();
Ako postoji mogućnost da objekt bude null mora se koristiti pokazivač jer cout << "\n Pozvan je destruktor...\n"; cout<< endl<< &kvd2 << endl;
reference ne mogu imati null vrijednosti. } cout<< &kvd3<< endl;
Npr. pristup memoriji na gomili vraća null ako operator new ne može alocirati cout<< endl;
memoriju. int getA() const { return a; } }
Kako referenca ne može biti null, prije inicijalizacije treba provjeriti vrijednost koju će void setA(int aa) { a = aa; }
vratiti operator newi: };
int *pInt = new int; //Inicijalizira se pokazivač na memorijski prostor
if (pInt != NULL) // provjeri je li taj prostor slobodan
int &rInt = *pInt; //dereferencira pokazivač

21 3.12.2018. 22

Kopiranje objekata na gomili Kopiranje objekata na gomili (2)


class Kvadrat{ void main(){ class Kvadrat{ void main(){
private: Kvadrat *kvd, *kvd1; private: Kvadrat *kvd, *kvd1;
int a; kvd = new Kvadrat; int a; kvd = new Kvadrat;
public: kvd1=kvd; public: kvd1 = new Kvadrat;
Kvadrat(){ kvd->setA(4); Kvadrat(){ kvd1=kvd;
cout << "\n Pozvan je konstruktor...\n"; cout << "\n Stranica a na 1. objekt: " << kvd->getA(); cout << "\n Pozvan je konstruktor...\n"; kvd->setA(4);
a = 2; cout << "\n Stranica a na 2. objekt: " << kvd1->getA(); a = 2; cout << "\n Stranica a na 1. objekt: " << kvd->getA();
}; kvd1->setA(40); }; cout << "\n Stranica a na 2. objekt: " << kvd1->getA();
~Kvadrat(){ cout << "\n Stranica a na 1. bjekt: " << kvd->getA(); ~Kvadrat(){ kvd1->setA(40);
cout << "\n Pozvan je destruktor...\n"; cout << "\n Stranica a na 2. objekt: " << kvd1->getA(); cout << "\n Pozvan je destruktor...\n"; cout << "\n Stranica a na 1. objekt: " << kvd->getA();
} cout<< endl<< &kvd << endl; } cout << "\n Stranica a na 2. objekt: " << kvd1->getA();
cout<< &kvd1<< endl; cout<< endl<< &kvd << endl;
int getA() const { return a; } delete kcd, kvd1; int getA() const { return a; } cout<< &kvd1<< endl;
void setA(int aa) { a = aa; } } void setA(int aa) { a = aa; } delete kcd, kvd1;
}; }; }

3.12.2018. 23 3.12.2018. 24

OOP – C++, M. Ivašić-Kos 4


3.12.2018.

Dva načina kopiranja objekata Kopirajući konstruktor


kopirajući konstruktor se automatski poziva svaki puta kada se stvori
stvaranje plitke kopije– stvara se novi objekt, ali on nastavlja “dijeliti” dio
kopija nekog objekta:
stanja s objektom na temelju kojega je nastao (shallow copy)
prilikom pridruživanja objekata (operator =)
to znači da nakon stvaranja objekta i nakon poziva kopirajućeg konstruktora postoje
prilikom poziva funkcije (objekt kao parametar funkcije)
dva objekta koji pokazuju na isti dio memorije
prilikom povrata vrijednosti funkcije
destruktor može doći u konflikt kada želi osloboditi prostor koji je već oslobođen
kopirajući konstruktor je članska funkcija koja inicijalizira objekt koristeći
drugi objekt iste klase
stvaranje duboke kopije – kopirajući konstruktor stvara u potpunosti novu
ima samo jedan parametar – referencu na objekt iste klase - preporuka da bude
kopiju objekta (deep copy)
CONST
to znači alociranje nove memorije i preuzimanje vrijednosti parametara iz objekta
predanog kopirajućem konstruktoru sintaksa funkcije:
destruktori ne dolaze u konflikt jer svaki oslobađa svoj memorijski prostor! Klasa (const Klasa &K);

primjer: //konstantna ref. na postojeću instancu mMacka klase Macka


Macka (const Macka &mMacka);

3.12.2018. 25 3.12.2018. 26

Kopirajući konstruktor – izvedba inline Kopirajući konstruktor – izvedba 2

class Kvadrat{ class Kvadrat{


class Kvadrat{ private: private:
class Kvadrat{ int a; int a;
private: private:
public: public:
int a; int a;
public: public: Kvadrat (const Kvadrat &); Kvadrat (const Kvadrat *);

Kvadrat (const Kvadrat &k){ Kvadrat (const Kvadrat *k){


//kod // kod
cout << "\n Copy konstruktor...\n"; cout << "\n Copy konstruktor.- dinamički\n";
a =k.a; a =k->a; }; };
} }
}; };
Kvadrat::Kvadrat(const Kvadrat &k){ Kvadrat::Kvadrat(const Kvadrat *k){
cout << "\n Copy konstruktor...\n"; cout << "\n Copy konstruktor ...\n";
a =k.a; a =k->a;
} }

3.12.2018. 27 3.12.2018. 28

Primjer: Kopirajući konstruktor Primjer: Kopiranje objekta s kopirajućim konstruktorom


class Kvadrat{ void main(){
private: Kvadrat kvd2;
int a; cout<<"\n adresa 1. objekta "<< &kvd2 << endl;
public: kvd2.setA(5);
Kvadrat(){
cout << "\n Stranica a 1. objekt: " << kvd2.getA();
cout << "\n Pozvan je konstruktor...\n";
a = 2; cout<< endl;
} Kvadrat kvd5(kvd2);
Kvadra t (const Kvadrat &k){ cout<<"\n adresa kopije objekta "<< &kvd5<< endl;
cout << "\n Pozvan je Copy konstruktor...\n"; cout << "\n Stranica a kopije: " << kvd5.getA();
a =k.a;
kvd5.setA(50);
}
~Kvadrat(){ cout << "\n Stranica a 1. objekt nakon set kopije: "
cout << "\n Pozvan je destruktor...\n"; << kvd2.getA();
} cout << "\n Stranica a kopije nakon set kopije: " <<
kvd5.getA();
int getA() const { return a; } cout<< endl;);
void setA(int aa) { a = aa; } }
};

3.12.2018. 29 3.12.2018. 30

OOP – C++, M. Ivašić-Kos 5


3.12.2018.

Primjer: Kopiranje objekta i poziv funkcije po vrijednosti Primjer: Kopiranje objekta i poziv funkcije (2)
void povrsina1 (Kvadrat kvad){ // poziv po vrijednosti void povrsina1 (Kvadrat kvad){ // poziv po vrijednosti
cout << "\n Povrsina je " << kvad.getA()*kvad.getA(); cout << "\n Povrsina je " << kvad.getA()*kvad.getA();
} }

Kvadrat povrsina2 (Kvadrat kvad){ // poziv po vrijednosti, povratni tip Kvadrat


cout << "\n Povrsina je " << kvad.getA() * kvad.getA();
return kvad;
void main(){ }
Kvadrat *kvd, *kvd1;
kvd = new Kvadrat; const Kvadrat & povrsina3 ( const Kvadrat & kvad){ //poziv po referenci
cout << "\n Povrsina je " << kvad.getA() * kvad.getA();
kvd1=kvd;
return kvad;
cout<< endl<< &kvd << endl; }
cout<< &kvd1<< endl;
cout << "\n\n Poziv fije1 (po vrijednosti, void) ...\n"; const Kvadrat * povrsina4 ( const Kvadrat * kvad){ //po pokazivacu
povrsina1(*kvd); cout << "\n Povrsina je " << kvad->getA( )* kvad->getA();
return kvad;
povrsina1(*kvd1);
}
}

3.12.2018. 31 3.12.2018. 32

Primjer: Kopiranje objekta i poziv funkcije (3) Primjer: Kopirajući konstruktor- gomila
void main(){ #include <iostream> ParNepar::ParNepar(int broj){
Kvadrat *kvd, *kvd1; using namespace std; this->broj=broj;
kvd = new Kvadrat; }
//kvd1 = new Kvadrat; class ParNepar{
private: ParNepar::ParNepar(const ParNepar *kopija){
kvd1=kvd; broj=kopija->broj;
int broj;
cout<< endl<< &kvd << endl; public: }
cout<< &kvd1<< endl; ParNepar () : broj(0) {};
cout << "\n\n Poziv fije1 (po vrijednosti, void) ...\n"; ParNepar (int broj); void ParNepar::unos(){
ParNepa r(const ParNepar *); cout<<"Unesi broj: ";
povrsina1 (*kvd1);
void unos(); cin>>broj;
cout << "\n Poziv fije2 (po vrijednosti, vraca objekt)...\n"; }
void provjera();
povrsina2 (*kvd1); };
cout << "\n Poziv fije3 (reference) ...\n"; void ParNepar::provjera(){
povrsina3 (*kvd1); if(broj%2==0)
cout<<"Broj "<<broj<<" je paran"<<endl;
cout << "\n Poziv fije4 (pokazivaci) ...\n";
else cout<<"Broj "<<broj<<" je neparan"<<endl;
povrsina4 (&*kvd1); }
delete kvd, kvd1;
}
3.12.2018. 33 3.12.2018. 34

Primjer: Kopirajući konstruktor- gomila Virtualni kopirajući konstruktori


int main(){ U nekim slučajevima potrebno je proslijediti pokazivač na bazni objekt i
ParNepar *br1, *br2, *br3; dobiti kopiju odgovarajućeg izvedenog objekta.
br1=new ParNepar();
br1->unos(); Uobičajeno rješenje: virtualna funkcija koja kreira i vraća novu kopiju
br1->provjera(); objekta trenutne klase.
br2=new ParNepar(3);
br2->provjera(); Primjer za klasu Sisavac:
br3=new ParNepar(br1); virtual Sisavac* Clone() { return new Sisavac (*this); }
br3->provjera();
return 0; // funkcija Clone vraća pokazivač na novi objekt Sisavac pozivajući kopirajući
} konstruktor s parametrom *this koji je konstantna referenca na trenutni objekt
Svaka izvedena klasa nadjačava funkciju Clone() jer je virtualna ->
kreiraju se odgovarajuće kopije izvedenih klasa pozivajući njihove
kopirajuće konstruktore
Primjer za podklase Pas i Macka:
virtual Sisavac* Clone() { return new Pas (*this); }
virtual Sisavac* Clone() { return new Macka (*this); }
3.12.2018. 35

OOP – C++, M. Ivašić-Kos 6


3.12.2018.

Primjer: Virtualni kopirajući konstruktori Primjer: Virtualni kopirajući konstruktori


#include <iostream> class Pas : public Sisavac {
using namespace std; public:
class Sisavac { Pas() { cout << “Pas konstruktor...\n”; }
public: virtual ~Pas() { cout << “Pas destruktor...\n”; }
Sisavac(): iGod(1) { cout << “ Sisavac konstruktor...\n”; } Pas (const Pas & rhs): Sisavac(rhs) {cout << “Pas copy konstruktor...\n”; }
virtual ~Sisavac() { cout << “ Sisavac destruktor...\n”; } void GlasaSe() const { cout << “Vau! Vau!\n”; }
Sisavac (const Sisavac & rhs): iGod (rhs.GetGod()) { cout << “Sisavac Copy konstruktor...\n”; } virtual Sisavac* Clone() { return new Pas(*this); }
virtual void GlasaSe() const { cout << “Sisavac GlasaSe!\n”; } };
virtual Sisavac* Clone() { return new Sisavac(*this); } // nereferencirani objekt
int GetGod()const { return iGod; } class Macka: public Sisavac {
protected: public:
int iGod; Macka() { cout << “Macka konstruktor...\n”; }
}; ~ Macka() { cout << “ Macka destruktor...\n”; }
Macka (const Macka & rhs): Sisavac(rhs) { cout << “Macka copy konstruktor...\n”; }
void GlasaSe() const { cout << “Miau! Miau!\n”; }
virtual Sisavac* Clone() { return new Macka (*this); }
};

Primjer: Virtualni kopirajući konstruktori Objekti kao parametri virtualnih funkcija


cout << "\n Kopiranje u drugi niz: \n ";
const int brojzivotinja = 3;
int main() {
Sisavac *niz2 [brojzivotinja ]; Virtualne funkcije funkcioniraju samo s pokazivačima i referencama.
for (i=0;i< brojzivotinja;i++)
Sisavac *niz [brojzivotinja ]; Prosljeđivanje nekog objekta po vrijednosti neće omogućiti pozivanje
niz2[i] = niz [i]->Clone();
int izbor, i; virtualnih funkcija.
cout << "\n poziv fije iz drugog niza objekata: \n ";
for ( i = 0; i<brojzivotinja ; i++) {
for (i=0;i< brojzivotinja;i++)
cout << “(1)Pas (2) Macka (3)Sisavac: “;
niz2[i]->GlasaSe();
cin >> izbor;
return 0;}
switch (izbor) {
case 1: niz[i] = new Pas;
break;
case 2: niz[i] = new Macka;
break;
default: niz[i] = new Sisavac;
break;
}
}

Primjer: objekti kao parametri funkcija Primjer: objekti kao parametri funkcija
#include <iostream> using namespace std; void main() {
class Sisavac { Sisavac* pMam = new Pas;
public: PokFunkcija(pMam);
Sisavac():iGod(1) { } RefFunkcija(*pMam); // * za vrijednost pokazivača
virtual ~Sisavac() { } VrFunkcija(*pMam);
virtual void GlasaSe() const { cout << “Sisavac se glasa!\n”; }
protected: pMam = new Macka;
int iGod; void RefFunkcija (Sisavac & rSisavac) { PokFunkcija(pMam);
rSisavac.GlasaSe();
}; RefFunkcija(*pMam);
}
class Pas : public Sisavac { VrFunkcija(*pMam);
public: void PokFunkcija (Sisavac * pSisavac) { delete pMam;
void GlasaSe() const { cout << “Vau! Vau!\n”; } pSisavac->GlasaSe(); }
}; }
void VrFunkcija (Sisavac vSisavac) { Prosljeđivanje nekog objekta po vrijednosti neće omogućiti pozivanje
class Macka: public Sisavac { vSisavac.GlasaSe(); implementacije virtualnih funkcija, nego će se pozvati funkciju u nadklasi.
public: }
Npr. Kod poziva po vrijednosti funkcija očekuje objekt Sisavca, tako da kompajler
void GlasaSe() const { cout << “Miau! Miau!\n”; }
poziva samo dio objekta Pas/Macka koji se odnosi na objekt nadklase (Sisavac) i
};
odgovarajuću funkciju GlasaSe() iz nadklase .

OOP – C++, M. Ivašić-Kos 7


3.12.2018.

Primjer: objekti kao parametri funkcija Obrnuti smjer: Iz podklase u klasu


void main() {
Sisavac* ptr=0; Tijekom izvršavanja programa Pokazivač na nadklasu ne može pristupiti metodama koje su definirane u
int izbor; bool kraj = false;
odlučuje se koji će se objekt podklasi.
while (kraj != true) {
cout << “(1) Pas (2) Macka (0) Kraj: “;
kreirati na gomili i pridružiti Npr. Ako objekt Pas ima metodu, lovackiPas(), koja nije definirana u klasi Sisavac i nije
pokazivaču na nadklasu. virtualna, tada joj se ne može pristupiti koristeći pokazivač na klasu Sisavac
cin >> izbor;
switch (izbor) { Cilj je pozvati implementaciju Rješenje može biti konvertiranje objekta nadklase u podklasu (casting)
case 0: kraj = true; odgovarajuće virtualne (kasnije!)
break;
funkcije.
case 1: ptr = new Pas;
break; Prosljeđivanje nekog objekta
case 2: ptr = new Macka; po vrijednosti neće omogućiti
break; pozivanje virtualnih funkcija,
default: ptr = new Sisavac;
nego će se pozvati
}
PokFunkcija(ptr);
implementacija te funkcije u
RefFunkcija(*ptr); nadklasi.
VrFunkcija(*ptr);
} delete ptr;}

Sažetak Zadaci

Reference objekta Za danu klasu rectangle napiši implementaciju konstruktora i


kopirajućeg konstruktora, te prikaži njegovo korištenje u glavnom
Korištenje referenci kao parametara funkcije programu.
Prosljeđivanje po vrijednosti vs. prosljeđivanje po referenci
class rectangle {
Kopiranje objekata vs. kopirajući konstruktor private:
float height;
float width;
int xpos;
int ypos;
public:
rectangle (float, float); // konstruktor
rectangle (const rectangle&); // kopirajući konstruktor
void draw();
void posn(int, int);
void move(int, int);
};

3.12.2018. 45 3.12.2018. 46

Zadaci - rješenje
rectangle::rectangle (const rectangle& old_rc) {
height = old_rc.height;
width = old_rc.width;
xpos = old_rc.xpos;
ypos = old_rc.ypos;
}

void main() {
rectangle rc1(3.0, 2.0); // konstruktor
rectangle rc2(rc1); // korištenje kopirajućeg konstruktora
rectangle rc3 = rc1; // alternativna sintaksa za kopirajući konstruktor

// naredbe;
}

OOP – C++, M. Ivašić-Kos 8

You might also like