Sunteți pe pagina 1din 18

Programare Obiect-Orientat

Laborator III
Adrian Li / Ovidiu Grigore
2015

Scopul laboratorului

n Laboratorul III al materiei Programare Obiect-Orientat continu laboratorul II prin definirea/suprancrcarea operatorilor i introduce conceptul de
funcii friend.
n acest laborator se parcurg urmtoarele puncte:
operatori aritmetici: +, -, *, /, ~, etc.
operatori de comparaie: ==, !=, <, >, >=, <=
operatorul de cast
operatorul subscript [ ]
clasele istream si ostream i obiectele cin i cout
funcii friend
operatorii i

Desfurarea lucrrii

n C++ majoritatea operatorilor se pot suprancrca, nsemnnd c pentru


orice obiecte putem defini diverse operaii folosindu-ne strict de operatori. Lista
complet de operatori ce se pot suprascrie n C++ este urmtoarea:
new
+
!
^=
<=

delete
=
&=
>=

()
*
<
|=
&&

[]
/
>

||

%
+=

++

^
-=
=

&
*=
=
,

|
/=
==
->*

~
~=
~=
->

Operatorul [ ] reprezint operatorul subscript (sau de indexare) i este folosit


ca n cazul vectorilor pentru a putea explora element cu element. Operatorul (
) reprezint apelul unei funcii. De asemenea pe lng operatorii de mai sus se
poate suprancrca i operaia de cast-ing.
Pentru a suprancrca operatori pentru obiecte din clase diferite, acetia trebuiesc definii ca funcie friend extern clasei (exemplul n capitolul 2.7. Operatorii
=, (), [ ] i -> nu pot fi suprancrcai folosind funcii friend. Urmtorii operatori nu se pot suprancrca: . .* :: ?: sizeof. Forma general a funciilor
operator membre ale clasei este urmtoarea:
1
2
3
4

t i p _ r e t u r n a t o p e r a t o r #( p a r a m e t r i )
{
// o p e r a t i i
}

Pentru a ilustra exemple cu operatori, vom porni de la o clas care va modela


un numr complex. O vom numi Complex. Un numr complex este format
din dou pri: partea real i partea imaginar. Aceti doi membri i vom
seta ca fiind private. De asemenea, vom declara un constructor implicit care
iniializeaz cei doi membri cu 0, i un constructor cu parametri pentru a putea
da o valoare dorit. Neavnd de-a face cu memorie alocat dinamic, nu este
nevoie de constructor de copiere, operator de copiere i destructor. Ultima
funcie creat va fi cea de afiare sub forma 2+3i dac partea real este 2 i cea
imaginar este 3.
1
2

#i n c l u d e <i o s t r e a m >
u s i n g namespace s t d ;

3
4
5
6
7
8
9
10
11
12
13

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

14

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

15
16
17
18
19
20

void a f i s ( )
{
c o u t << t h i s >r e << "+" << t h i s >im << " i " << e n d l ;
}

21
22
23
24
25

};

26
27
28
29

i n t main ( )
{
Complex A;

Complex B( 2 , 3 ) ;

30
31

A. a f i s ( ) ;
B. a f i s ( ) ;

32
33
34

//0+0 i
//2+3 i

2.1

Operatori aritmetici

Prima operaie care o vom implementa va fi operaia de adunare, dat de operatorul +. Forma acesteia este dat n exemplul de mai jos, iar toate celelalte
operaii aritmetice ce implic doi termeni (- * /) sunt similare.
1
2
3
4
5
6
7

Complex o p e r a t o r +( c o n s t Complex &T2 )


{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 . r e ;
R e z u l t a t . im = t h i s >im + T2 . im ;
return Rezultat ;
}

n codul de mai sus, se ncepe la linia 1 cu declararea funciei operator+. Operatorul + este un operator ntre doi termeni. Primul termen este chiar obiectul
asupra cruia scriem operatorul (obiectul this). Al 2lea obiect este tot de tip
Complex, si este dat de T2. Funcia va returna Complex deoarece din adunarea a dou numere complexe rezult tot un numr complex. La linia 3 declarm
un nou obiect numit Rezultat, obiect care va ine minte rezultatul adunrii. Liniile 4 i 5 execut operaia de adunare efectiv (adunarea numerelor complexe)
iar linia 6 returneaz rezultatul obinut. Codul complet al acestui program
funcional, precum i exemplificarea operatorului este urmtorul.
1
2

#i n c l u d e <i o s t r e a m >
u s i n g namespace s t d ;

3
4
5
6
7
8
9
10
11
12
13

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

14
15
16
17
18
19

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

20
21
22
23
24

Complex o p e r a t o r +( c o n s t Complex &T2 )


{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 . r e ;

R e z u l t a t . im = t h i s >im + T2 . im ;
return Rezultat ;

25
26

27
28

void a f i s ( )
{
c o u t << t h i s >r e << "+" << t h i s >im << " i " << e n d l ;
}

29
30
31
32
33

};

34
35
36
37
38
39

i n t main ( )
{
Complex A( 5 , 1 ) ;
Complex B( 2 , 3 ) ;
Complex C ;

40

C = A + B;

41
42

A. a f i s ( ) ; //5+1 i
B . a f i s ( ) ; //2+3 i
C . a f i s ( ) ; //7+4 i

43
44
45
46

Observm, la linia 41 c se execut operaia de adunare ntre cei 2 termeni A


i B. Dac operatorul + nu ar fi fost definit, compilatorul ar fi dat o eroare
fiindc nu ar fi tiut s traduc aceast operaie. La fel se ntmpl i dac
dorim s adunm un numr complex cu un numr real. Practic, n
momentul de fa avem declarat operaia de adunare doar n felul urmtor:
adunare ntre dou numere Complexe i rezultatul obinut este Complex.
Dac dorim s adunm un numr complex cu un numr real (double) avem
urmtoarele posibiliti:
C = A + Complex(2, 0); unde nr. 2 este numrul real pe care vrem s-l
adunm
s suprancrcm din nou operatorul + pentru operaia de adunare cu
numere reale
Pentru a suprancrca operatorul + s poat face operaie de adunare cu numere
reale, trebuie ca termenul al 2lea al operaiei s fie de tip double.
Not. Reamintim c n C++ o funcie (fie ea i operator) se poate suprancrca
de cte ori este nevoie cu condiia ca cel puin un parametru al acesteia s fie
schimbat. Practic, pentru exemplul curent, putem avea doi operatori, ambii
returnnd un numr complex (deoarece operaia de adunare ntre un numr
complex si un numr fie complex fie real returneaz tot un numr complex),
unul avnd termenul al doilea de tip Complex, iar cellalt de tip double.
1
2
3
4
5

Complex o p e r a t o r +( c o n s t Complex &T2 )


{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 . r e ;
R e z u l t a t . im = t h i s >im + T2 . im ;

return Rezultat ;

6
7

8
9
10
11
12
13
14
15

Complex o p e r a t o r +( c o n s t d o u b l e &T2 )
{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 ;
R e z u l t a t . im = t h i s >im ;
return Rezultat ;
}

Codul complet, precum i alte explicaii se gsesc mai jos:


1
2

#i n c l u d e <i o s t r e a m >
u s i n g namespace s t d ;

3
4
5
6
7
8
9
10
11
12
13

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

14

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

15
16
17
18
19
20

Complex o p e r a t o r +( c o n s t Complex &T2 )


{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 . r e ;
R e z u l t a t . im = t h i s >im + T2 . im ;
return Rezultat ;
}

21
22
23
24
25
26
27
28

Complex o p e r a t o r +( c o n s t d o u b l e &T2 )
{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 ;
R e z u l t a t . im = t h i s >im ;
return Rezultat ;
}

29
30
31
32
33
34
35
36

void a f i s ( )
{
c o u t << t h i s >r e << "+" << t h i s >im << " i " << e n d l ;
}

37
38
39
40
41

};

42
43
44
45

i n t main ( )
{
Complex A( 5 , 1 ) ;

Complex B( 2 , 3 ) ;
Complex C ;

46
47
48

A. a f i s ( ) ; //5+1 i
B . a f i s ( ) ; //2+3 i

49
50
51

C = A + B;
C . a f i s ( ) ; //7+4 i

52
53
54

C = C + 3;
C . a f i s ( ) ; //10+4 i

55
56
57

C = A + B + C + 10;
C . a f i s ( ) ; //27+8 i

58
59
60

La linia 52 se poate observa prima operaie de adunare, executat de ctre primul operator+. La lina 55 putem observa operaia de adugare executat de
ctre al doilea operator+. La linia 58 este puin mai complex: ntre A i B se
execut primul operator, ntre B i C se execut tot primul operator, iar ntre
C i 10 se execut al doilea operator. Una din probleme de la sfrit v cere s
demonstrai ordinea executrii.
Programul urmtor conine operatorul - i operatorul tild (~). Operaiile * i
/ (nmulire i mprire) se pot implementa similar, folosind funciile matematice necesare. Operatorul tild este operatorul care n mod tradiional, aplicat
unui numr binar returneaz inversul acestuia (0 devine 1 i 1 devine 0 pentru
fiecare bit n parte). n exemplul nostru acesta a fost suprancrcat pentru a
calcula conjugatul complex al numrului. Sintaxa acestuia este diferit (nu
are parametri) deoarece este un operator unar (are un singur argument) spre
deosebire de +, -, etc care sunt operatori binari (ntre doi termeni).
1
2

#i n c l u d e <i o s t r e a m >
u s i n g namespace s t d ;

3
4
5
6
7
8
9
10
11
12
13

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

14
15
16
17
18
19

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

20
21
22
23
24

Complex o p e r a t o r +( c o n s t Complex &T2 )


{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 . r e ;

R e z u l t a t . im = t h i s >im + T2 . im ;
return Rezultat ;

25
26

27
28

Complex o p e r a t o r +( c o n s t d o u b l e &T2 )
{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 ;
R e z u l t a t . im = t h i s >im ;
return Rezultat ;
}

29
30
31
32
33
34
35
36

Complex o p e r a t o r ( c o n s t Complex &T2 )


{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e T2 . r e ;
R e z u l t a t . im = t h i s >im T2 . im ;
return Rezultat ;
}

37
38
39
40
41
42
43
44

Complex o p e r a t o r ( c o n s t d o u b l e &T2 )
{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e T2 ;
R e z u l t a t . im = t h i s >im ;
return Rezultat ;
}

45
46
47
48
49
50
51
52

Complex o p e r a t o r ~ ( )
// o p e r a t o r u l ~ ( inseamna b i t w i s e NOT . . s i
n o i o s a i l f o l o s i m s a returnam c o n j u g a t u l numarului complex )
{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e ;
R e z u l t a t . im = t h i s >im ;
return Rezultat ;
}

53

54
55
56
57
58
59
60

void a f i s ( )
{
c o u t << t h i s >r e << "+" << t h i s >im << " i " << e n d l ;
}

61
62
63
64
65

};

66
67
68
69
70
71

i n t main ( )
{
Complex A( 5 , 1 ) ;
Complex B( 2 , 3 ) ;
Complex C ;

72
73
74

A. a f i s ( ) ; //5+1 i
B . a f i s ( ) ; //2+3 i

75
76
77

C = A + B;
C . a f i s ( ) ; //7+4 i

78
79
80

C = C + 3;
C . a f i s ( ) ; //10+4 i

81

C = C B;
C . a f i s ( ) ; //8+1 i

82
83
84

C = B 2;
C . a f i s ( ) ; //0+3 i

85
86
87

A = ~A;
A. a f i s ( ) ; //51 i

88
89
90

C = ~B ;
C . a f i s ( ) ; //23 i

91
92
93

Pentru operatorul tild, observai c acesta se poate folosi n orice mod cu


putin ne gndim (exemplele de la liniile 88 i 91). Un alt operator unar este
operatorul de negare !.
Not. Dei operatorii + i - n exemplul de mai sus au fost folosii n a construi
adunarea i scderea ntre numere complexe, acest lucru nu este neaprat necesar. Dac se dorete, se pot implementa aceti operatori s fac orice altceva.
Spre exemplu, operatorul+ s fac de fapt scderea a dou numere complexe,
etc. De reinut este faptul c, dei sunt operatori, n esen codul lor este tot o
funcie, care poate fi scris dup bunul plac.

2.2

Operatori de comparaie

Operatorii de comparaie returneaz o valoare care poate fi fie adevrat (true)


fie fals (false). Spre exemplu, dac comparm dou numere din punct de
vedere A mai mare dect B, rezultatul poate fi adevrat, dac A este mai
mare dect B, sau fals, dac A este mai mic sau egal cu B. n exemplul de mai
jos vom implementa operatorii == i !=, rmnnd ca ceilali operatori s fie
implementai de voi ntr-o problem. Toi operatorii de comparaie sunt binari
i toi au aceeai sintax.
1
2

#i n c l u d e <i o s t r e a m >
u s i n g namespace s t d ;

3
4
5
6
7
8
9
10
11
12
13

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

14
15
16
17
18
19

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

20

Complex o p e r a t o r ~ ( )
{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e ;
R e z u l t a t . im = t h i s >im ;
return Rezultat ;
}

21
22
23
24
25
26
27
28

b o o l o p e r a t o r==(c o n s t Complex &T2 )


{
i f ( ( t h i s >r e == T2 . r e ) && ( t h i s >im == T2 . im ) )
return true ;
else
return f a l s e ;
}

29
30
31
32
33
34
35
36

b o o l o p e r a t o r !=( c o n s t Complex &T2 )


{
r e t u r n ! o p e r a t o r==(T2 ) ;
}

37
38
39
40
41

void a f i s ( )
{
c o u t << t h i s >r e << "+" << t h i s >im << " i " << e n d l ;
}

42
43
44
45
46

};

47
48
49
50
51
52

i n t main ( )
{
Complex A( 5 , 1 ) ;
Complex B( 2 , 3 ) ;
Complex C( 5 , 1 ) ;

53

A. a f i s ( ) ; //5+1 i
B . a f i s ( ) ; //2+3 i
C . a f i s ( ) ; //5+1 i

54
55
56
57
58
59
60
61

cout
cout
cout
cout

<<
<<
<<
<<

(A
(A
(A
(A

==
!=
==
!=

A)
A)
B)
B)

<<
<<
<<
<<

endl ;
endl ;
endl ;
endl ;

// 1
// 0
// 0
// 1

cout
cout
cout
cout

<<
<<
<<
<<

(A == ~B) << e n d l ;
// 0
(A == C) << e n d l ;
// 1
(~A == ~C) << e n d l ;
// 1
(~A != ~C) << e n d l ;
// 0

62
63
64
65
66
67

Observai c. pentru eficien, operatorul != este implementat folosindu-ne de


operatorul ==. Din punct de vedere logic, dac o expresie nu este adevrat,
atunci ea este fals. Funcia operator==() returneaz dac cei doi termeni sunt
egali, iar rezultatul acesteia este negat i returnat de funcia operator!=().

2.3

Operatorul de cast

Operatorul de cast se folosete n mod uzual pentru a transforma un tip de date


n altul, n msura n care acest lucru este posibil. Spre exemplu, se poate face
cast dintr-un numr mai mic ntr-un numr mai mare (s zicem din int n long
int, din char n int, din char n long int, etc), se poate face cast dintr-un numr
ntreg ntr-unul real, i invers (bineneles, cu pierdere de informaie).
n exemplul ce urmeaz suprancrcm operatorul de cast de la Complex ctre double. Practic, vom putea transforma un numr complex ntr-unul real.
Aceast operaie fizic vorbind este imposibil, aa c nou acest operator ne va
returna modulul numrului complex. Deci, dac vom ncerca s facem cast
unui numr complex ntr-unul real, vom obine modulul acestia.
1
2
3

#i n c l u d e <i o s t r e a m >
#i n c l u d e <math . h>
u s i n g namespace s t d ;

4
5
6
7
8
9
10
11
12
13
14

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

15

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

16
17
18
19
20
21

operator double ( ) const


{
r e t u r n s q r t ( t h i s >r e t h i s >r e + t h i s >im t h i s >im ) ;
}

22
23
24
25
26

void a f i s ( )
{
c o u t << t h i s >r e << "+" << t h i s >im << " i " << e n d l ;
}

27
28
29
30
31
32

};

33
34
35
36
37
38

i n t main ( )
{
Complex A( 5 , 2 ) ;

39
40
41

double d ;
d = ( d o u b l e )A;

42
43

A. a f i s ( ) ;

//5+2 i

10

c o u t << "d = " << d << e n d l ;

44
45

// 5 . 3 8 . .

De remarcat este c, la linia 2, includem o nou librrie: math.h. Datorit


acestei librrii avem acces la funcia de radical: double sqrt(double);. Operatorul de cast este declarat la linia 75, i folosit n program la linia 94.

2.4

Operatorul subscript

Operatorul subscript, sau operatorul index este operatorul folosit de ctre iruri
(array-uri). Cum numrul nostru complex nu are efectiv iruri de numere, vom
folosi acest operator pentru a returna fie numrul real, fie pe cel imaginar, ca
n exemplul de mai jos:
1
2
3

#i n c l u d e <i o s t r e a m >
#i n c l u d e <math . h>
u s i n g namespace s t d ;

4
5
6
7
8
9
10
11
12
13
14

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

15
16
17
18
19
20

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

21
22
23
24

d o u b l e& o p e r a t o r [ ] ( i n t i n d e x )
{
double i m p l i c i t = 0 ;

// o p e r a t o r u l s u b s c r i p t

25

switch ( index )
{
case 0:
r e t u r n t h i s >r e ;
break ;
case 1:
r e t u r n t h i s >im ;
break ;
default :
return i m p l i c i t ;
break ;
}

26
27
28
29
30
31
32
33
34
35
36
37
38

39
40
41
42

void a f i s ( )
{
c o u t << t h i s >r e << "+" << t h i s >im << " i " << e n d l ;

11

43
44
45

};

46
47
48
49
50
51

i n t main ( )
{
Complex A( 5 , 2 ) ;

52

A. a f i s ( ) ; //5+2 i
c o u t << A [ 0 ] << e n d l ; // 5
c o u t << A [ 1 ] << e n d l ; // 2

53
54
55
56

A[ 0 ] = 10;
A[ 1 ] = 3;
A. a f i s ( ) ; //10+3 i

57
58
59
60

Atenie: operatorul subscript funcioneaz n ambele sensuri! Asta


nseamn c putem deopotriv s citim i s scriem folosindu-ne de acesta.
Exemplul de citire se afl la liniile 54 i 55 i exemplul de scriere se afl la liniile 57 i 58. Implementarea operatorului pare mai ciudat: return face practic
legtura ntre operator i o anumit variabil-membru. Acest operator a fost
implementat ca dac indexul este 0, atunci s returneze partea real a numrului complex, iar dac indexul este 1 s returneze partea imaginar. La linia 34
tratm cazul cnd, dei nu ar trebui, programatorul ncearc s apeleze operatorul pentru un index diferit de 0 i 1. n acest caz, trebuie s-i dm o variabil
pe care s o citeasc sau scrie, altfel programul nostru se va opri cu erori. Acest
operator este util n momentul implementrii de liste, vectori i orice fel de
obiect ce cuprinde niruiri de date.

2.5

Clasele istream i ostream. Obiectele cin i cout

Ne abatem puin din studiul operatorilor pentru a reaminti cteva lucruri despre
librria iostream - nelipsit din programele pe care le studiem. Aceast librrie
conine, pe lng numeroase clase i funcii de sistem i dou clase speciale:
istream i ostream. Astea modeleaz streamurile de intrare i de ieire. Fr
s intrm prea mult n detalii, cin i cout sunt dou OBIECTE, de tip
istream respectiv ostream. Practic sunt dou obiecte declarate deja n librria
iostream, obiecte ce tiu s fac legtura, n cazul nostru, cin ntre program i
tastatur, i cout ntre program i ecranul consolei.
1

#i n c l u d e <i o s t r e a m >

2
3

...

4
5
6
7

int variabila ;
c i n >> v a r i a b i l a ;
c o u t << v a r i a b i l a ;

Practic, n momentul n care se dorete de la tastatur o informaie i apelm


cin variabila; apelm operatorul al obiectului cin. Analog, obiectul cout
12

are definit operatorul. Deci, foarte important de reinut: cin i cout nu


sunt funcii, ci sunt OBIECTE cu scopul de a manipula CONSOLA:
ConsoleIN i ConsoleOUT. Vom reveni asupra celor doi operatori i asupra
istream i ostream n capitolul 2.7.

2.6

Funcii friend

Cnd am vorbit prima data despre tipul de acces al variabilelor din clase i structuri, am zis c variabilele private i protected nu pot fi accesate din exteriorul
clasei, ci doar de funcii membre ale clasei. Acest lucru este total adevrat, cu
o excepie: clasele i funciile friend. O funcie friend este o funcie total
extern clasei dar care are acces i la membrii private i protected ai clasei.
Pentru ca o funcie f() s aib acces la membrii privai ai unei clase, acest
funcie trebuie s fie listat ca funcie friend. Un exemplu de funcie friend se
gsete n codul urmtor:
1
2

#i n c l u d e <i o s t r e a m >
u s i n g namespace s t d ;

3
4
5
6
7
8
9
10
11
12
13

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

14

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

15
16
17
18
19
20

f r i e n d v o i d f 1 ( Complex ) ;

21
22

};

23
24
25
26
27
28

v o i d f 1 ( Complex X)
{
c o u t << "Re = " << X. r e << e n d l ;
c o u t << "Im = " << X. im << e n d l ;
}

29
30
31
32
33
34
35
36

v o i d f 2 ( Complex X)
{
// a c e a s t a f u n c t i e i n c e a r c a s a a c c e s e z e r e s i im
// dar n e f i i n d f u n c t i e f r i e n d , nu a r e v o i e
c o u t << "Re = " << X. r e << e n d l ;
c o u t << "Im = " << X. im << e n d l ;
}

37
38

i n t main ( )

13

39

{
Complex A( 5 , 2 ) ;

40
41

f 1 (A) ;
f 2 (A) ;

42
43
44

// f u n c t i o n e a z a
// nu f u n c t i o n e a z a

n exemplul de mai sus funcia f1(Complex) este listat ca fiind prieten clasei
Complex, drept urmare are voie s acceseze membrii privai ai clasei, pe cnd
funcia f2(Complex) nu. Exemplul de mai sus nu este funcional la compilare
din cauz c funcia f2 ncearc s acceseze ceva ce nu are voie. Pentru a-l
face funcional, trebuie fie s tergem din funcia f2 liniile de cod care acceseaz
membri privai (liniile 34 i 35), fie s listm funcia f2 ca fiind funcie friend
clasei Complex.
Not. Adugnd o funcie la lista de funcii friend ale unei clase, nu este necesar ca funcia respectiv s i existe. Declarnd funcia ca fiind friend nseman
c orice funcie cu acel prototip va fi n mod implicit considerat friend.
Not. O funcie poate fi friend unui numr nelimitat de clase, i o clas poate
avea un numr nelimitat de funcii friend.
Pentru a lista o funcie ca fiind prieten a unei clase, tot ce trebuie s facem
este s scriem, n interiorul clasei, antetul funciei precedat de cuvntul friend
(vezi linia 21 din exemplul de mai sus).

2.7

Operatorii i

Operatorii i au fost lsai la sfrit pentru c vrem s i implementm


pentru a putea realiza urmtoarele dou linii:
1

#i n c l u d e <i o s t r e a m >

2
3
4
5
6

c l a s s Complex
{
...
};

7
8

...

9
10
11
12

Complex A;
c i n >> A;
c o u t << A << e n d l ;

Pentru aceasta, aveam nevoie de informaii despre librria iostream, despre istream, ostream, cin, cout i despre funcii friend. Practic, pentru a putea realiza
ce dorim la liniile 11 i 12 din codul de mai sus, trebuie s suprancrcm operatorul al clasei istream i operatorul al clasei ostream. Aceti doi operatori
trebuiesc implementai n afara clasei Complex, deoarece dac ar fi implementai n interiorul acesteia, termenul stng al operatorilor sau ar fi this,
lucru care nu coincide cu ce dorim: membrul stng este de tip istream/ostream,
nu Complex.
14

1
2

#i n c l u d e <i o s t r e a m >
u s i n g namespace s t d ;

3
4
5
6
7
8
9
10
11
12
13

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

14

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

15
16
17
18
19
20

f r i e n d o st re am& o p e r a t o r <<(o st re am& out , Complex& X) ;


f r i e n d i s t r e a m& o p e r a t o r >>(i s t r e a m& in , Complex& X) ;

21
22
23

};

24
25
26
27
28
29

o str ea m& o p e r a t o r <<(o st re am& out , Complex& X)


{
out << X. r e << "+" << X. im << " i " ;
r e t u r n out ;
}

30
31
32
33
34
35
36

i s t r e a m& o p e r a t o r >>(i s t r e a m& in , Complex& X)


{
i n >> X. r e ;
i n >> X. im ;
return in ;
}

37
38
39
40

i n t main ( )
{
Complex A( 5 , 2 ) ;

41

c o u t << A << e n d l ;

42
43

c i n >> A;
c o u t << A << e n d l ;

44
45
46

n implementare operatorului pentru ieire ( ) nu trebuie folosit cout, pentru c


acesta va fi chiar membrul stng, dat de aceast dat de obiectul out. Analog,
pentru operatorul de intrare, membrul stng cin va fi reprezentat n interiorul
operatorului de ctre in. Motivul pentru care cele dou funcii sunt friend
este c re i im sunt membri privai ai clasei Complex. Dac acetia ar fi fost
publici, nu ar fi fost nevoie s declarm cei doi operatori ca fiind friend.

15

2.8

Clasa complet implementat n acest laborator

n final este prezentat clasa complet implementat n acest laborator. Funcia


afis() a fost eliminat, operatorul inndu-i locul mult mai elegant.
1
2
3
4
5
6
7
8
9
10

c l a s s Complex
{
double re ;
d o u b l e im ;
public :
Complex ( )
{
t h i s >r e = 0 ;
t h i s >im = 0 ;
}

11
12
13
14
15
16

Complex ( d o u b l e re , d o u b l e im )
{
t h i s >r e = r e ;
t h i s >im = im ;
}

17
18
19
20
21
22
23
24

Complex o p e r a t o r +( c o n s t Complex &T2 )


{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 . r e ;
R e z u l t a t . im = t h i s >im + T2 . im ;
return Rezultat ;
}

25
26
27
28
29
30
31
32

Complex o p e r a t o r +( c o n s t d o u b l e &T2 )
{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e + T2 ;
R e z u l t a t . im = t h i s >im ;
return Rezultat ;
}

33
34
35
36
37
38
39
40

Complex o p e r a t o r ( c o n s t Complex &T2 )


{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e T2 . r e ;
R e z u l t a t . im = t h i s >im T2 . im ;
return Rezultat ;
}

41
42
43
44
45
46
47
48

Complex o p e r a t o r ( c o n s t d o u b l e &T2 )
{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e T2 ;
R e z u l t a t . im = t h i s >im ;
return Rezultat ;
}

49
50
51
52
53

Complex o p e r a t o r ~ ( )
{
Complex R e z u l t a t ;
R e z u l t a t . r e = t h i s >r e ;

16

R e z u l t a t . im = t h i s >im ;
return Rezultat ;

54
55

56
57

b o o l o p e r a t o r==(c o n s t Complex &T2 )


{
i f ( ( t h i s >r e == T2 . r e ) && ( t h i s >im == T2 . im ) )
return true ;
else
return f a l s e ;
}

58
59
60
61
62
63
64
65

b o o l o p e r a t o r !=( c o n s t Complex &T2 )


{
r e t u r n ! o p e r a t o r==(T2 ) ;
}

66
67
68
69
70

operator double ( ) const


{
r e t u r n s q r t ( t h i s >r e t h i s >r e + t h i s >im t h i s >im ) ;
}

71
72
73
74
75

d o u b l e& o p e r a t o r [ ] ( i n t i n d e x )
{
double i m p l i c i t = 0 ;

76
77
78

// o p e r a t o r u l s u b s c r i p t

79

switch ( index )
{
case 0:
r e t u r n t h i s >r e ;
break ;
case 1:
r e t u r n t h i s >im ;
break ;
default :
return i m p l i c i t ;
break ;
}

80
81
82
83
84
85
86
87
88
89
90
91

92
93

f r i e n d o st re am& o p e r a t o r <<(o st re am& out , Complex& X) ;


f r i e n d i s t r e a m& o p e r a t o r >>(i s t r e a m& in , Complex& X) ;

94
95
96

};

97
98
99
100
101
102

o str ea m& o p e r a t o r <<(o st re am& out , Complex& X)


{
out << X. r e << "+" << X. im << " i " ;
r e t u r n out ;
}

103
104
105
106
107
108
109

i s t r e a m& o p e r a t o r >>(i s t r e a m& in , Complex& X)


{
i n >> X. r e ;
i n >> X. im ;
return in ;
}

17

Probleme
1. Pentru exemplul cu doi operatori+ din capitolul 2.1 exemplificai ordinea
operaiilor pentru linia de cod: C = A + B + C + 10;.
2. Tot pornind de la exemplul din capitolul 2.1 testai urmtoarea linie de
cod n main(): C = 2 + A;. Dac nu funcioneaz, cum o putem face s
funcioneze ?
3. Folosindu-v de funcia de calcul al modulului numrului complex, implementat la operatorul de cast, implementai operatorii de comparaie
> < >= <= care compar dou numere complexe n funcie de modulul
acestora.
4. Implementai clasa Lista care s modeleze o list dinamic de date, similar listei de la SDA. Avei grij c lista efectiv de date va fi alocat
dinamic, i din acest motiv avei nevoie de constructor de copiere, operator de copiere i destructor. Clasa Lista trebuie s conin operatorul
subscript prin care se poate accesa orice membru al listei la fel cum se
acceseaz un element al unui vector, trebuie s poat fi afiat folosind
cout, precum i urmtoarele funcii: adugare element la nceputul listei,
adugare element n interiorul listei dup un alt element, adugarea unui
element la sfritul listei i tergerea unui element.
5. Folosind clasa Lista implementat la exerciiul anterior, adugai un membru private numit sortat. Dac acest element este 1, lista trebuie meninut ordonat cresctor (inclusiv la adugare i stergere).

18

S-ar putea să vă placă și