Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 18

Elektrotehniki fakultet

Banja Luka

Programski jezici 1

KLASE I APSTRAKCIJA PODATAKA

3. dio

Goran Banjac
goran.banjac@etfbl.net

12/3/15

Klase 3. dio
Sadraj

Prijatelji klase
Dodjeljivanje objekata lan po lan
Konstruktor kopije

Prijatelji klase
Prijatelj klase nije lan klase, ali ima pravo pristupa privatnim (i zatienim) lanovima
date klase.

Da bi se neka funkcija deklarisala


kao prijatelj klase, prototip te
funkcije treba da se navede u
definiciji date klase uz navoenje
specifikatora friend.
class Klasa
{
friend tip funkcija();
...

Klasa A moe 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 deklarie da joj je klasa A prijatelj.
Prijateljstvo nije simetrino!
Ako je klasa A prijatelj klase B, to ne znai 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 znai 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 klase
Primjer:

2+3i uvecano za 1-2i iznosi: 3+i


3+i uvecano za 5.0 iznosi: 8+i

#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;
};
Ako se koriste preklopljene
void dodaj(Complex &c, const Complex &z)
prijateljske funkcije, prototip
{ c.re += z.re; c.im += z.im; }
svake od tih funkcija mora biti
void dodaj(Complex &c, double d)
deklarisan kao prijatelj date
{ c.re += d; }
klase!
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();
}

Prijatelji klase
Primjer:
#include <iostream>
using namespace std;
class B
{
friend class A;
private: int data;
};

Sve funkcije lanice klase A su


prijatelji klase B, jer je klasa A
deklarisana kao prijatelj klase B.

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

100
200

Dodjeljivanje objekata lan po lan

Operator dodjele (=) moe da se


koristi da bi se jedan objekat dodijelio
drugom objektu istog tipa.

Ovakva dodjela vri se po principu


kopiranje lan po lan (memberwise
copy) svaki podatak lan jednog objekta
kopira se u odgovarajuu lanicu drugog
objekta.
Primjer:

t1

t2

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;

ss

30

30

ss

mm

25

25

mm

hh

12

12

hh

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.2004
dat2 = 1.1.2001
Nakon kopiranja
dat2 = 31.12.2004

Dodjeljivanje objekata lan po lan


t1

#include <iostream>
using namespace std;

int main()
{
Test t1(100);
cout << "t1: "; t1.print();
Test t2;
t2 = t1;
cout << "t2: "; t2.print();
}

pi

0x3d2470

100

0x3d2470

Rezultat kopiranja
lan po lan

t2 = t1

t2

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

Pridrueni
dinamiki
objekat

Primjer:

pi

0x3d2470

Kopiranje lan po lan moe da


dovede do neeljenih efekata, jer i
original i kopija pokazuju na isti
dinamiki objekat, tj. kopija nema
vlastiti pridrueni dinamiki objekat!
t1: pi = 0x3d2470
t2: pi = 0x3d2470

*pi = 100
*pi = 100

Dodjeljivanje objekata lan po lan


t2
pi

0x3e2460
0x3e24e0

0x3e2460

100
0

0x3e24e0

t2 = t1

t1
pi

0x3e24e0

Pridrueni
dinamiki
objekat

#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();

Pridrueni
dinamiki
objekat

Primjer:

t2 (inicijalno):
pi=0x3e2460
t2 (nakon dodjele):
pi=0x3e24e0
t2 (nakon brisanja t1): pi=0x3e24e0

*pi=0
*pi=100
*pi=0

Konstruktor kopije

Konstruktor kopije u nekoj klasi je konstruktor koji moe 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 slui da se izbjegnu problemi vezani za kopiranje lan po


lan u sluaju objekata koji sadre pokazivae ili reference na dinamike
objekte.
Uobiajene deklaracije
kopije:
class X
{
public:
X(X &x);
};

konstruktora
class X
{
public:
X(const X &x);
};

Nedozvoljena deklaracija konstruktora


kopije:
class X
{
public: X(X x);
};

Tipine situacije u kojima se


aktivira konstruktor kopije:
X x1;
X x2(x1);
X x3=x1;

Konstruktor kopije
t1
pi

0x3e2460

pi

0x3e24e0

pi

0x3e24f0

100

0x3e2460

100

0x3e24e0

100

0x3e24f0

t2
t3

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

Pridrueni
dinamiki
objekat

Primjer:

t1 : pi = 0x3e2460
t2 : pi = 0x3e24e0
t3 : pi = 0x3e24f0

*pi = 100
*pi = 100
*pi = 100

Konstruktor kopije
Primjer:

Original: 0, 1, 2, 3, 4
Kopija:
0, 1, 2, 3, 4

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

Konstruktor kopije
Primjer:

Original: Banja Luka

#include <iostream>
Kopija: Banja Luka
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();
}

Konstruktor kopije
Primjer:

Original: Banja Luka

#include <iostream>
Kopija: Banja Luka
#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();
}

Konstruktor kopije
Tipino aktiviranje konstruktora kopije je kod kreiranja automatskih
objekata koji predstavljaju formalne argumente funkcija!
Primjer 1:

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

#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

122000

Konstruktor kopije
Tipino aktiviranje konstruktora kopije je kod kreiranja privremenih
objekata pri vraanju rezultata iz funkcije!
Primjer 1:

Primjer 2:

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

#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 K D D D D

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;
}
1/3 + 7/8 = 29/24
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);
}

You might also like