18
Programski jezici 1 3. dio Elektrotehnički fakultet Banja Luka KLASE I APSTRAKCIJA PODATAKA Goran Banjac [email protected] 08/23/2022

C++ Klase 3

Embed Size (px)

DESCRIPTION

C++

Citation preview

Page 1: C++ Klase 3

Programski jezici 1

3. dio

Elektrotehnički fakultetBanja Luka

KLASE I APSTRAKCIJA PODATAKA

Goran [email protected]

04/22/2023

Page 2: C++ Klase 3

Klase – 3. dio

Sadržaj Prijatelji klase Dodjeljivanje objekata “član po član” Konstruktor kopije

Page 3: C++ Klase 3

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.

Page 4: C++ Klase 3

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

Page 5: C++ Klase 3

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!

Page 6: C++ Klase 3

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.

Page 7: C++ Klase 3

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

Page 8: C++ Klase 3

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

Page 9: C++ Klase 3

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!

Page 10: C++ Klase 3

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

Page 11: C++ Klase 3

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

Page 12: C++ Klase 3

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

Page 13: C++ Klase 3

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

Page 14: C++ Klase 3

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

Page 15: C++ Klase 3

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

Page 16: C++ Klase 3

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

Page 17: C++ Klase 3

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

Page 18: C++ Klase 3

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