Upload
milana-tomic
View
230
Download
1
Embed Size (px)
DESCRIPTION
C++
Citation preview
Programski jezici 1
3. dio
Elektrotehnički fakultetBanja Luka
KLASE I APSTRAKCIJA PODATAKA
Goran [email protected]
04/22/2023
Klase – 3. dio
Sadržaj Prijatelji klase Dodjeljivanje objekata “član po član” Konstruktor kopije
Prijatelji klase
Da bi se neka funkcija deklarisala kao prijatelj klase, prototip te funkcije treba da se navede u definiciji date klase uz navođenje specifikatora friend.class Klasa{
friend tip funkcija();
...};
Prijatelj klase nije član klase, ali ima pravo pristupa privatnim (i zaštićenim) članovima date klase.
Klasa A može da bude prijatelj klase B. Tada su sve funkcije članice klase A prijatelji klase B.
class B {
friend class A; ...
};
Principi prijateljstva“Prijateljstvo se daruje, a ne uzima!”Da bi klasa A bila prijatelj klasi B, klasa B mora eksplicitno da deklariše da joj je klasa A prijatelj.
“Prijateljstvo nije simetrično!” Ako je klasa A prijatelj klase B, to ne znači da je i klasa B prijatelj klasi A.
“Prijateljstvo nije tranzitivno!” Ako je klasa A prijatelj klase B i ako je klasa B prijatelj klase C, to ne znači da je i klasa A prijatelj
klasi C.
Prijatelji klase
Primjer:
#include <iostream>using namespace std;
class Data{ friend void setX(Data &, int); // deklaracija prijatelja public: Data() { x=0; } int getX() const { return x; } private: int x;};
void setX(Data &dat, int val){ dat.x = val; // dozvoljeno: setX je prijatelj klase Data}
int main(){ Data d; cout << "d.x nakon kreiranja: " << d.getX() << endl;
setX(d, 10); // postavi x pomocu prijatelja
cout << "d.x nakon poziva setX: " << d.getX() << endl; } d.x nakon kreiranja: 0
d.x nakon poziva setX: 10
Prijatelji klasePrimjer:#include <iostream>using namespace std;class Complex{ friend void dodaj(Complex &c, const Complex &z); friend void dodaj(Complex &c, double d); public: Complex(double r=0, double i=0) : re(r), im(i) {}; double getRe() { return re; } double getIm() { return im; } void print() { if (re!=0) { cout << re; if (im>0) cout << "+"; } if (im!=0) { if (im!=1) cout << im; cout << "i"; } } private: double re, im;};
void dodaj(Complex &c, const Complex &z) { c.re += z.re; c.im += z.im; }
void dodaj(Complex &c, double d) { c.re += d; }
int main(){ Complex a(2,3), b(1,-2); a.print(); cout << " uvecano za "; b.print(); dodaj(a,b); cout << " iznosi: "; a.print(); cout << endl; a.print(); cout << " uvecano za 5.0 iznosi: "; dodaj(a,5.0); a.print();}
2+3i uvecano za 1-2i iznosi: 3+i3+i uvecano za 5.0 iznosi: 8+i
Ako se koriste preklopljene prijateljske funkcije, prototip
svake od tih funkcija mora biti deklarisan kao prijatelj date
klase!
Prijatelji klase
Primjer:
#include <iostream>using namespace std;
class B{ friend class A; private: int data;};
class A{ public:
static void setB1(B &b, int data) { b.data = data; }
static int getB1(B &b) { return b.data; }
void setB2(B &b, int data) { b.data = data; }
int getB2(B &b) { return b.data; }};
int main(){ B b; A::setB1(b,100); // preko ZF cout << A::getB1(b) << endl;
A a; a.setB2(b,200); // preko PF cout << a.getB2(b);}
100200
Sve funkcije članice klase A su prijatelji klase B, jer je klasa A
deklarisana kao prijatelj klase B.
Dodjeljivanje objekata “član po član”
Operator dodjele (=) može da se koristi da bi se jedan objekat dodijelio drugom objektu istog tipa.
Ovakva dodjela vrši se po principu “kopiranje član po član” (memberwise copy) – svaki podatak član jednog objekta kopira se u odgovarajuću članicu drugog objekta.
Primjer:
class Time{ public: Time(int h=0,int m=0,int s=0)
{ hh=h; mm=m; ss=s; } private: int hh, mm, ss;
};...Time t1(12,25,30),t2;
t2=t1;
t1
12
25
30
hh
mm
ss
t2
hh
mm
ss
12
25
30
Dodjeljivanje objekata “član po član”
Primjer:
#include <iostream>using namespace std;
class Date{ public: Date(int=1, int=1, int=2001); void print(); private: int dd, mm, gg;};
Date::Date(int d, int m, int g) { gg = g; mm = m; dd = d; }
void Date::print() { cout << dd << '.' << mm << '.' << gg; }
int main(){ Date dat1(31, 12, 2004); Date dat2; cout << "dat1 = "; dat1.print(); cout << "\ndat2 = "; dat2.print(); dat2 = dat1; cout << "\nNakon kopiranja \ndat2 = "; dat2.print();}
dat1 = 31.12.2004dat2 = 1.1.2001Nakon kopiranjadat2 = 31.12.2004
Dodjeljivanje objekata “član po član”
Primjer:
#include <iostream>using namespace std;
class Test{ public: Test(int i=0) { pi = new int; *pi = i; } void print() { cout << "pi = " << pi; cout << "\t*pi = " << *pi << endl; } private: int *pi;};
int main(){ Test t1(100); cout << "t1: "; t1.print(); Test t2; t2 = t1; cout << "t2: "; t2.print();}
t1: pi = 0x3d2470 *pi = 100t2: pi = 0x3d2470 *pi = 100
t1
pi
Pridruženidinamičkiobjekat
0x3d2470 100 0x3d2470
t2 = t1
t2
pi 0x3d2470
Rezultat kopiranja “član po član”
Kopiranje “član po član” može da dovede do neželjenih efekata, jer i
original i kopija pokazuju na isti dinamički objekat, tj. kopija nema
vlastiti pridruženi dinamički objekat!
Dodjeljivanje objekata “član po član”
Primjer:
#include <iostream>using namespace std;class Test{ public: Test(int i=0) { pi = new int(i); } void print() { cout << "pi=" << pi; cout << "\t*pi=" << *pi << endl; } ~Test() { delete pi; } private: int *pi;};int main(){ Test t2; cout << "t2 (inicijalno):\t";
t2.print(); { Test t1(100); t2 = t1; cout << "t2 (nakon dodjele):\t"; t2.print(); } cout << "t2 (nakon brisanja t1):\t"; t2.print();}
t2 (inicijalno): pi=0x3e2460 *pi=0t2 (nakon dodjele): pi=0x3e24e0 *pi=100t2 (nakon brisanja t1): pi=0x3e24e0 *pi=0
t2
pi
Pridruženidinamičkiobjekat
0x3e2460 0 0x3e2460
t2 = t1
t1
piPridruženidinamičkiobjekat
0x3e24e0 100 0x3e24e0
0x3e24e0
0
Konstruktor kopije
Konstruktor kopije u nekoj klasi je konstruktor koji može kao argument da primi jedan objekat iste klase.
Konstruktor kopije uvijek se poziva kad se neke objekat date klase inicijalizuje nekim drugim objektom te klase.
Konstruktor kopije služi da se izbjegnu problemi vezani za kopiranje “član po član” u slučaju objekata koji sadrže pokazivače ili reference na dinamičke objekte.
Uobičajene deklaracije konstruktora kopije:class X{ public: X(X &x);};
Nedozvoljena deklaracija konstruktora kopije: class X{ public: X(X x);};
Tipične situacije u kojima se aktivira konstruktor kopije:
X x1;X x2(x1);X x3=x1;
class X{ public:
X(const X &x);};
Konstruktor kopije
Primjer:
#include <iostream>using namespace std;
class Test{ public:
Test(int i=0) { pi = new int(i); }
Test(Test &t) { pi = new int(*t.pi); }
void print() const { cout << "pi = " << pi; cout << "\t*pi = " << *pi << endl; }
~Test() { delete pi; }
private: int *pi;};
int main(){ Test t1(100); cout << "t1 : "; t1.print(); Test t2=t1; cout << "t2 : "; t2.print(); const Test t3(t2); cout << "t3 : "; t3.print();}
t1 : pi = 0x3e2460 *pi = 100t2 : pi = 0x3e24e0 *pi = 100t3 : pi = 0x3e24f0 *pi = 100
t1
pi
Pridruženidinamičkiobjekat
0x3e2460 100 0x3e2460
t2
pi 0x3e24e0 100 0x3e24e0
t3
pi 0x3e24f0 100 0x3e24f0
Konstruktor kopije
Primjer:
#include <iostream>using namespace std;class Niz{ public: Niz(int nn=1) { if (nn<1) nn=1; n=nn; data=new int[n]; for (int i=0; i<n; i++) data[i]=i; } Niz(const Niz &original) { n=original.n; data=new int[n]; for (int i=0; i<n; i++) data[i]=original.data[i]; } void print() const { for (int i=0; i<n; i++) { cout << data[i]; if (i<n-1) cout << ", "; } } ~Niz() { delete [] data; } private: int n; int *data;};int main(){ const Niz original(5); cout << "Original: "; original.print(); cout << endl; Niz kopija(original); cout << "Kopija: "; kopija.print(); cout << endl;}
Original: 0, 1, 2, 3, 4Kopija: 0, 1, 2, 3, 4
Konstruktor kopije
Primjer:
#include <iostream>using namespace std;
class String{ public: String(char *t) { int bz=0; while (*(t+bz)) bz++; s = new char[bz+1]; while (bz>=0) { *(s+bz)=*(t+bz); bz--; } } String(const String &original) { int bz=0; while (*(original.s+bz)) bz++; s = new char[bz+1]; while (bz>=0) { *(s+bz)=*(original.s+bz); bz--; } } void print() const { cout << s << endl; } ~String() { delete [] s; } private: char *s;};
int main(){ const String original("Banja Luka"); cout << "Original: "; original.print(); String kopija(original); cout << "Kopija: "; kopija.print();}
Original: Banja LukaKopija: Banja Luka
Konstruktor kopije
Primjer:
#include <iostream>#include <cstring>using namespace std;
class String{ public: String(char *t) { s = new char[strlen(t)+1]; strcpy(s,t); } String(const String &original) { s = new char[strlen(original.s)+1]; strcpy(s,original.s); } void print() const { cout << s << endl; } ~String() { delete [] s; } private: char *s;};
int main(){ const String original("Banja Luka"); cout << "Original: "; original.print(); String kopija(original); cout << "Kopija: "; kopija.print();}
Original: Banja LukaKopija: Banja Luka
Konstruktor kopije
Tipično aktiviranje konstruktora kopije je kod kreiranja automatskih objekata koji predstavljaju formalne argumente funkcija!
Primjer 1:
#include <iostream>using namespace std;
class A { public: A() { cout << '1'; } A(A &a) { cout << '2'; } ~A() { cout << '0'; }};
void f(A &a) { A b=a; }
int main(){ A a; f(a);}
1200
Primjer 2:
#include <iostream>using namespace std;
class A { public: A() { cout << '1'; } A(A &a) { cout << '2'; } ~A() { cout << '0'; }};
void f(A a) { A b=a; }
int main(){ A a; f(a);}
122000
Konstruktor kopije
Tipično aktiviranje konstruktora kopije je kod kreiranja privremenih objekata pri vraćanju rezultata iz funkcije!
Primjer 1:
#include <iostream>using namespace std;class A { public: A() { cout << "K "; } ~A() { cout << "D "; }};A f() { A a, b, c; return b; }int main() { A b; b=f(); }
K K K K D D D D
Primjer 2:
#include <iostream>using namespace std;class A { public: A() { cout << "K "; } ~A() { cout << "D "; }};A f(int x) { A b, c; if (x) return b; else return c; }int main() { A b; b=f(1); }
K K K D D D D
Konstruktor kopije
Primjer:
#include <iostream>using namespace std;
class Razlomak{ friend Razlomak zbir(const Razlomak &, const Razlomak &); friend void print(const Razlomak &); public: Razlomak(int b=0, int n=1) : broj(b), imen(n) {} private: int broj, imen;};
Razlomak zbir(const Razlomak &a, const Razlomak &b){ Razlomak t; t.broj = a.broj * b.imen + a.imen * b.broj; t.imen = a.imen * b.imen; return t;}
void print(const Razlomak &r){ if (r.broj==0) cout << 0; else cout << r.broj << '/' << r.imen;}
int main(){ Razlomak c(1,3), d(7,8), x; print(c); cout << " + "; print(d); x = zbir(c,d); cout << " = "; print(x);}
1/3 + 7/8 = 29/24