Documente Academic
Documente Profesional
Documente Cultură
Supraincarcareaoperatorilor
(continuare)
Supraincarcareaoperatorilor
Supraincarcareaoperatorilor
CAP. 3
[]
<nume>[<expresie>].
Să considerăm clasa vector, definită astfel: class vector{ private: intnrcomp; //nr. componentedouble
*tabcomp; //tabloulcomponentelor; adresade începutpublic: double &operator[](int); }
Supraincarcareaoperatorilor
CAP. 3
Pentrutipulabstractvector,operatoruldeindexarepoatefisupraîncărcat,astfelîncâtsăpermităaccesareaele
mentuluideindicen.Înacestcaz,operatoruldeindexaresepoatesupraîncărcaprintr-
ofuncţiemembrăaclasei(deoareceoperandulstângestedetipulclasei),şipoatefifolositsubforma:v[n]
(undevesteobiectalclaseivector;n-expresieîntreagă).Expresiav[n]esteechivalentăcuv.operator[](n)
(apelulexplicitalfuncţieioperator[]).
Supraincarcareaoperatorilor
CAP. 3
3.7. SUPRAINCARCAREA OPERATORULUI DE INDEXARE [ ]
Transferulparametruluicătrefuncţiacaresupraîncarcăoperatorulsepoatefaceprinvaloaresauprinreferinţă.Î
nmodobligatoriu,funcţiatrebuiesăreturnezereferinţacătreelementulaflatpepoziţian(pentruapermiteeven
tualelemodificărialeelementului,deoarecevector[n]estelvalue).
Supraincarcareaoperatorilor
CAP. 3
Pentru un tip abstract, prototipul funcţiei membre care supraîncarcă operatorul de indexare este :
În cazul în care operatorul se supraîncarcă printr-o funcţie prietenă, prototipul funcţiei este:
Supraincarcareaoperatorilor
CAP. 3
vector de bytes. Se implementează tipurile FileLoc şi File. #include <stdio.h> #include <iostream.h> //
Clasa"FileLoc" class File; class FileLoc{private: File* p_file; fpos_tfile_loc; FileLoc(File& f, fpos_tloc):
p_file(&f), file_loc(loc){} public: friend File; void operator=(char c); void operator=(constchar* str);
operator constchar(); };
Supraincarcareaoperatorilor
10
CAP. 3
3.7. SUPRAINCARCAREA OPERATORULUI DE INDEXARE [ ]// Clasa"File" class File {private: FILE* fp; //
ANSI C, pointer catreFILE public: friend FileLoc; File(constchar* name) // Constructor de
deschiderefisierpentrucitiresiscriere{fp= fopen(name, "r+"); } ~File() { fclose(fp);} // Destructor,
inchidefisierFileLocoperator[](fpos_tloc) // operator []; creazao instantaa claseiFileLoc{fseek(fp, loc,
SEEK_SET);return FileLoc(*this,loc); } };
Supraincarcareaoperatorilor
11
CAP. 3
Supraincarcareaoperatorilor
12
CAP. 3
3.7. SUPRAINCARCAREA OPERATORULUI DE INDEXARE [ ]// operator = (char *) // Utilizatsub forma f[n] =
"sir", undef[n] este un obiectde tipFileLoc// pentru memorarea sirului in fisier void
FileLoc::operator=(constchar* str) { if(p_file->fp!= NULL) {fputs(str, p_file->fp); } } // operator
constchar( ) // Utilizatsub forma c=f[n], undef[n] este un obiectde tipFileLocsi c este un caracter// pentru
citirea unui caracter din fisier FileLoc::operator constchar() { if(p_file->fp!= NULL) {return getc(p_file-
>fp); } return EOF; }
Supraincarcareaoperatorilor
13
CAP. 3
Supraincarcareaoperatorilor
14
CAP. 3
3.7. SUPRAINCARCAREA OPERATORULUI DE INDEXARE [ ]// Memorarea unui sir in fisier f[0] = "CREARE
SIR"; cout<< "Dupamemorareasiruluiprimii25 bytes = " << '\n'; for(i=0; i<25; i++) {c = f[i]; cout<< c; }
cout<< '\n'; }
Supraincarcareaoperatorilor
15
Supraincarcareaoperatorilor
16
CAP. 3
Avantajulalocăriidinamiceamemorieişiaeliberăriiacesteiacuajutoruloperatorilornewşidelete,faţădeutiliza
reafuncţiilormalloc,callocsaufree,constăînfaptulcăoperatoriialocă(eliberează)memoriepentruobiecte,dat
edetipabstract.Acestlucruesteposibildeoareceaceştioperatoriauosupraîncărcareglobală,standard.
Supraincarcareaoperatorilor
17
CAP. 3
În cazul în care supraîncărcarea standard este insuficientă, utilizatorul poate supraîncărca operatorii prin
metode (implicit!) statice. Pentru operatorul new, funcţia membră care supraîncarcă operatorul neware
prototipul: void * <nume_clasa>::operator new(size_t<lungime>);
Supraincarcareaoperatorilor
18
CAP. 3
adresa de început a zonei de memorie alocate dinamic. Tipul size_teste definit în stdlib.h. La aplicarea
operatorului, nu se indică nici o valoare pentru parametrul lungime (mărimea zonei de memorie
necesare obiectului pentru care se alocă dinamic memorie), deoarece compilatorul o determină,
automat.
Supraincarcareaoperatorilor
19
CAP. 3
Moduldeutilizarealoperatoruluinew:<nume_clasa>*<p>=new<nume_clasa>;Sau:<nume_clasa>*<p>=ne
w<nume_clasa>(<p1>,<p2>,<p3>);
Supraincarcareaoperatorilor
20
CAP. 3
Aplicareaoperatoruluinewsupraîncărcatdeutilizatordetermină,automat,apelulconstructoruluicorespunză
torclasei,saualconstructoruluiimplicit.<nume_clasa>*<p>=new<nume_clasa>;//apelconstrimplicitÎnadou
aformă,laalocareadinamicăamemorieiaparşiparametriiconstructorului(p1,p2,p3).<nume_clasa>*<p>=ne
w<nume_clasa>(<p1>,<p2>,<p3>);//apelconstrcuparametri
Supraincarcareaoperatorilor
21
CAP. 3
Operatoruldeletesesupraîncarcăprintr-ofuncţiemembrăcuprototipul:
void<nume_clasa>::operatordelete(void*);
Laaplicareaoperatoruluideleteseapelează,automat,destructorulclasei.
Supraincarcareaoperatorilor
22
CAP. 3
Să urmărim exemplul următor, în care se supraîncarcă operatorii newşi delete. #include <iostream.h>
#include <stdlib.h> #include <string.h> #include <stddef.h> #include <conio.h> //
-------------supraincarcareaoperatoruluinew static void *operator new(size_tmarime, intnr_elem)
{ cout<< "\nOperatornew al programatorului!\n"; void *rtn= malloc(marime); if (rtn!= NULL)
memset(rtn, nr_elem, marime); return rtn; }
Supraincarcareaoperatorilor
23
CAP. 3
Supraincarcareaoperatorilor
24
CAP. 3
class c1 { double n1, n2; public: c1(){n1=0; n2=0;} }; //. . . . intmain( ) { c1 *pc1=new c1; //se alocă
memorie pentru păstrarea unui obiect de tip c1 c1 *pc2=new c1(7, 5); //odată cu alocarea dinamică, se
realizează şi iniţializarea }
Supraincarcareaoperatorilor
25
CAP. 3
class c1{ double n1, n2; public: c1(){n1=0; n2=0;} c1(double x, double y) {n1=x; n2=y;} }; intmain( ) { c1
*pct1; pct1=new c1[100]; /*Se rezervă memorie ptr. 100 obiecte de tip c1. Se apelează constructorul
implicit de 100 de ori */ } Operatorii new, deletepermit alocarea dinamică şi pentru tablouri. În aceste
situaţii, se utilizează întotdeauna operatorii supraîncărcaţi global predefiniţi şi se apelează constructorul
fără parametri (dacă acesta există).
Supraincarcareaoperatorilor
26
CAP. 3
#include <iostream.h> class numar{ double *n; public: număr (double nr1); ~număr(); double val()
{return *n;} }; număr::număr(double nr1) {n=new double(nr1);} număr::~număr() { delete n;} intmain()
{număr a(7.53),b(2.14); număr *p1,*p2; p1=new număr(-1.74); cout<<p1<<'\n'; cout<<&p1<<'\n';
*p1=a; cout<<"p1="<<p1<<'\n'; delete p1; }
Supraincarcareaoperatorilor
27
Supraincarcareaoperatorilor
28
CAP. 3
Operatorul“apeldefuncţie”,utilizatsubforma
<nume> (<lista_param_efectivi>)
poatefiinterpretatcaooperaţiebinară,avândcaoperandstângnume,iarcaoperanddreptlista_param_efectivi
.Supraîncărcareaacestuioperatorbinar,nestatic,vapermiteutilizareasubforma:a(b,
…),sau(apelulexplicit):a.operator()(b,…).
Supraincarcareaoperatorilor
29
CAP. 3
Avantajeleunuiastfeldeoperatorsunt:Evaluareaşiverificarealisteideargumenteînmodsimilaruneifuncţiiob
işnuite;Mecanismuluideapel:deşioperatorulestebinar,celde-
aldoileaoperandfiindolistădeargumente(chiarvidă),funcţiaoperatorpoateaveaoricâţiparametri.
Supraincarcareaoperatorilor
30
CAP. 3
Încazulîncarenumelefuncţieiesteunpointercătreoanumităfuncţie(vezipointericătrefuncţii),apelulfuncţieis
erealizeazăprin:
(*<point_f>) (<lista_param_efectivi>);
Supraincarcareaoperatorilor
31
CAP. 3
Funcţiacaresupraîncarcăoperatorultrebuiesăfiemetodănestatică.Supraîncărcareaoperatorului()seutilizea
zăînmodfrecventladefinireaaşa-
numituluiiterator.Iteratoriiseutilizeazăînlegăturăcutipuriabstractededate,careconţincolecţiideelemente(l
iste,arbori,tabelededispersie,etc.).
Supraincarcareaoperatorilor
32
CAP. 3
Supraincarcareaoperatorilor
33
CAP. 3
Fie,deexemplu,clasacontainercareesteocolecţiedeobiectedetipoarecare,carepoatefiimplementatăcaunta
bloudeobiecte,caolistădenoduri,caunarborebinar,etc.Înfuncţiedeaceastăorganizare,clasacontainerconţin
eodatămembrădetipobiectsauunpointercătreobiectşiestecapabilsălivreze,perând,obiecteleelementealec
olecţiei.
Supraincarcareaoperatorilor
34
CAP. 3
#include <iostream.h> #include <string.h> class Nume{ char nume[25]; public: Nume(char *s='\0')
{ strcpy(nume, s); } display() { cout<< '\n' << nume; } friend char * operator&(Nume& nm){ return
nm.nume; } void operator() (char *s) { strcpy(s, nume); } };
Supraincarcareaoperatorilor
35
CAP. 3
Supraincarcareaoperatorilor
36
Supraincarcareaoperatorilor
37
CAP. 3
Supraîncărcareaoperatoruluiunar->(deselecţieindirectă,prinintermediulpointerului)serealizeazăprintr-
ometodănestatică.Expresia obiect -> expresie va fi interpretată ca (obiect.operator->())->expresie.
Deaceea,funcţiacaresupraîncarcăoperatorultrebuiesăreturnezefieunpointerlaunobiectalclasei,fieunobiec
tdeuntippentrucareestesupraîncărcatoperatorul->.
Supraincarcareaoperatorilor
38
CAP. 3
#include <iostream.h> typedefstructex{ intmembru; }; class ex1{ ex *pointer; public: void set(ex &p)
{pointer=&p;} ex * operator -> (void) {return pointer;} }; class ex2{ ex1 *pointer; public: void set(ex1 &p)
{pointer=&p;} ex1 * operator -> (void) {return pointer;} }; intmain() {ex A; ex1 B; ex2 C; B.set(A); B-
>membru=10; //apelal funcţieiex1::operator->() cout<<B->membru<<'\n'; }
Supraincarcareaoperatorilor
39
CAP. 3
Supraincarcareaoperatorilor
40
Supraincarcareaoperatorilor
41
CAP. 3
3.11. CONVERSII
Supraincarcareaoperatorilor
42
CAP. 3
3.11. CONVERSII
Conversiileimpliciteaulocînurmătoarelesituaţii:Încazulaplicăriioperatoruluideatribuire:operanduldrepte
steconvertitlatipuloperanduluistâng.Laapeluluneifuncţii:Dacătipulparametrilorefectivi(deapel)diferăde
tipulparametrilorformali,seîncearcăconversiatipuluiparametrilorefectivilatipulparametrilorformali.Lare
venireadintr-
ofuncţie:Dacăfuncţiareturneazăovaloareînprogramulapelant,laîntâlnireainstrucţiuniireturnexpresie;seînc
earcăconversiatipuluiexpresieilatipulspecificatînantetulfuncţiei.
Supraincarcareaoperatorilor
43
CAP. 3
3.11. CONVERSII
Conversiileexplicitepotfi:a)tip_predefinit_1->tip_predefinit_2b)tip_predefinit-
>tip_definit_de_utilizator(clasă)c)clasă->tip_predefinitd)clasă_1->clasă_2
Supraincarcareaoperatorilor
44
CAP. 3
3.11. CONVERSII
Pentrurealizareaunorastfeldeconversii,sefoloseşteoperatorulunardeconversieexplicită(cast),deforma:
(<tip>) <operand>
Exemplu:
intk; double x; x = (double) k / (k+1); /* În situaţia în care se doreşte obţinerea rezultatului real al
împărţirii întregului k la k+1, trebuie realizată o conversie explicită */ ÎnlimbajulC++ acelaşiefectse
poateobţineşiastfel: X = double (k) / (k+1); deoarece se apelează explicit constructorul tipului double.
Supraincarcareaoperatorilor
45
CAP. 3
3.11. CONVERSII
Supraincarcareaoperatorilor
46
CAP. 3
3.11. CONVERSII
Astfeldeconversiisepotrealizaatâtimplicit,câtşiexplicit,încazulîncarepentruclasarespectivăexistăunconstru
ctorcuparametriimpliciţi,detipulpredefinit.
Exemplu:
Pentruclasafracţiedefinităîncursurileanterioare,definireaunuiconstructorcuparametridetipint,vapermiter
ealizareaunorconversiiimplicitesauexpliciteint->fractie:
Supraincarcareaoperatorilor
47
CAP. 3
3.11. CONVERSII
class fracţie{ intnrt, nmt; public: fracţie( intnrt= 0, intnmt= 1); // . . . }; intmain() {fractief; f = 20; /*
ConversieIMPLICITĂ: înainteaatribuiriise converteşteoperanduldrept(de tip int) la
tipuloperanduluistâng(tip fracţie). */ f = fractie(20); /*ConversieEXPLICITĂ: se converteşteîntregul20
într-un obiectal claseifracţie(nrt=20 şinmt=1). */ }
Supraincarcareaoperatorilor
48
CAP. 3
3.11. CONVERSII
Acesttipdeconversieserealizeazăprintr-
unoperatorspecial(cast)careconverteşteobiectuldinclasălatipulpredefinit.Operatoruldeconversieexplicită
sesupraîncarcăprintr-ofuncţiemembrănestatică.
Supraincarcareaoperatorilor
49
CAP. 3
3.11. CONVERSII
Exemplul1:Pentruclasafracţie,săsesupraîncarceoperatorulde
conversieexplicită,caresărealizezeconversiifracţie-
>int.#include<iostream.h>classfracţie{longnrt,nmt;public:fracţie(intn=0,intm=1)
{nrt=n;nmt=m;}friendostream&operator<<(ostream&,constfracţie&);operatorint()
{returnnrt/nmt;}//conversiefracţie->int};
Supraincarcareaoperatorilor
50
CAP. 3
3.11. CONVERSII
ostream&operator<<(ostream&ies,constfracţie&f)
{ies<<'('<<f.nrt<<'/'<<f.nmt<<")\n";returnies;}intmain()
{fracţiea(5,4),b(3),c;inti=7,j=14;c=a;c=7;cout<<(fracţie)243<<'\n';cout<<"(int)a="<<(int)a<<'\n';//conversi
eexplicităcout<<"int(a)="<<int(a)<<'\n';//conversieexplicităintx=a;//conversiasefaceimplicit,înaintedeatri
buire}
Supraincarcareaoperatorilor
51
CAP. 3
3.11. CONVERSII
de conversie în long. #include <iostream.h> #include <conio.h> #include <time.h> class Data { intluna, zi,
an; public: Data() {} // constructor nulData(intl, intz, inta) { luna = l; zi = z; an = a; } Data(time_t); //
constructor de conversieoperator long(); // operator de conversieData->long void afisare(void); };
Supraincarcareaoperatorilor
52
CAP. 3
3.11. CONVERSII
void Data::afisare() { cout<<"Data="<< luna<< '/' << zi<< '/' << an<<'\n'; } Data::Data(time_tacum)
{ structtm *tim= localtime(&acum); zi= tim->tm_mday; luna= tim->tm_mon+ 1; if (tim->tm_year>=2000)
an=tim->tm_year-100; //pentruanul>=2000 else an=tim->tm_year; /*tm_year=anuldin data -1900*/}
Supraincarcareaoperatorilor
53
CAP. 3
3.11. CONVERSII
Supraincarcareaoperatorilor
54
CAP. 3
3.11. CONVERSII
Conversiadintip_abstract_1întip_abstract_2(dinclasă1înclasă2),serealizeazăcuajutorulunuiconstructoral
clasei2,careprimeştecaparametriobiectedinclasa1(fracţie->complex).
Supraincarcareaoperatorilor
55
CAP. 3
3.11. CONVERSII
Exemplul1:
#include <iostream.h> class fracţie{ intnrt, nmt; public: fracţie(int nr=0, int nm=1) {nrt=nr; nmt=nm;}
operator int() const//conversiefracţie-> int{return nrt/nmt;} friend ostream&operator<<(ostream&,
constfracţie&); friend class complex; /*cls. complex esteclasaprietenaptr. clasafracţie, fiecarefuncţiedin
complex esteprietenapentrufracţie*/ intîntreg() {return nrt/nmt;} };
Supraincarcareaoperatorilor
56
CAP. 3
3.11. CONVERSII
Supraincarcareaoperatorilor
57
CAP. 3
3.11. CONVERSII
intmain() { complex a(6.98, 3.2), b(9), c, d, e, q, s; int i=12, j=5, k;double x=1234.999, y=74.9897, u, z; c=i;
fractie r(7, 3), r1(9), t; d=x; //conversiedouble->complex(constructorcomplexcuarg. double)
e=complex(y,j); //apelexplicit al constr. complex; întâiconversiej de la intla double k=a;
//conversiecomplex->double->intu=a; //conversiecomplex->double
Supraincarcareaoperatorilor
58
CAP. 3
3.11. CONVERSII
59
CAP. 3Supraincarcareaoperatorilor
ÎNTREBĂRI 1. Cum se realizează conversia din clasă1 în clasă2? Daţi un exemplu. 2. Prin ce modalităţi se
pot supraîncărca operatorii? 3. Cum se realizează conversia din tip predefinit în clasă? În ce situaţii se
realizează conversiile implicite? 4. Ce restricţii impune mecanismul de supraîncărcare a operatorilor? 5.
Cum se poate realiza conversia dintr-un tip abstract (clasă) într-un tip predefinit? Exemplu. 6. Ce
observaţii puteţi face în legatură cu aritatea unui operator şi modul de supraîncărcare a acestuia? 7. În
cazul supraîncărcării metodelor, cum se poate realiza selecţia unei metode ?
60
CAP. 3
SFARSITUL Capitolului3
Supraincarcareaoperatorilor
PROGRAMAREACALCULATOARELORŞILIMBAJEDE PROGRAMAREII
Programareacalculatoarelorşilimbajede programareII