Pagina de start a forumului Informatica
 FAQ  •  Cautare  •  Membri  •  Grupuri   •  Inregistrare  •  Profil  •  Mesaje private  •  Autentificare
Subiectul urmator
Subiectul anterior
Creaza un subiect nou   Raspunde la subiect  Pagina de start a forumului Informatica » C++
Autor Mesaj
Admin
Administrator
Administrator


Data inscrierii: 07/Dec/2013
Mesaje: 1103

MesajTrimis: 14/12/2013 19:30 Raspunde cu citat (quote) Back to top

• Supraincarcarea functiilor si operatorilor sunt elemente esentiale in programarea C++. Ele ofera o baza importanta pentru polimorfism in momentul compilarii, dand o extensibilitate si flexibilitate limbajului.

• Supraincarcarea unei functii inseamna utilizarea aceluiasi identificator de functie pentru cel putin doua functii cu conditia ca sa difere intre ele prin soiuri si/sau numar de parametri (cu prototipuri diferite). In acest fel compilatorul poate selecta, la un clipă dat, functia care trebuie apelata.
Exemplu:
In biblioteca C exista functii cum ar fi:
abs( ) care returneaza valoarea absoluta a unui intreg;
iabs( ) care returneaza valoarea absoluta a unei date de tip float;
fabs( ) care returneaza valoarea absoluta a unei date de tip double.
Aceste functii realizeaza aceeasi actiune dar pentru tipuri deosebite de parametri. In C++ se poate folosi un singur identificator pentru functia respectiva in toate cele trei situatii.

//Se defineste functia abs() in cele trei situatii
int abs(int k);
double abs(double d);
long abs(long l);
main( )
{
cout<<abs(-345)<<"\n";
cout<<abs(-111.23)<<"\n";
cout<<abs(-7L)<<"\n";
return 0;
}
int abs(int k)
{
cout<<"Se foloseste functia abs() pentru intregi \n";
return k<0?-k:k;
}
double abs(double d)
{
cout<<"Se foloseste functia abs() pentru double \n";
return d<0?-d:d;}
long abs(long l)
{
cout<<"Se foloseste functia abs() pentru long \n";
return l<0?-l:l;
}

Se observa ca acelasi identificator de functie abs( ) indica o actiunea generala, iar compilatorul, avand in vedere tipul argumentului, va alege perfect metoda particulara pentru fiecare situatie. Datorita polimorfismului se realizeaza o reducere de la trei actiuni, la o singura actiune.
Exemplu:
………………………………………….
void adsir(char *s1, char *s2);
void adsir(char *s1, int k);
main ( )
{
char sir[50];
strcpy(sir,"Va");
adsir(sir,"multumesc .");
cout<<sir<<"\n";
adsir(sir,50);
cout<<sir<<"\n";
return 0;
}
//Se vor concatena doua siruri
void adsir(char*s1, char*s2){strcat(s1,s2);}

// Se va concatena un sir cu un intreg
void adsir(char*s1,int k)
{
char t[50];
sprintf(t, "%d",k);
strcat(s1,t);
}

S-a realizat supraincarcarea functiei adsir( ) si anume: o versiune concateneaza doua siruri cu functia strcat( ), iar a doua versiune transforma un intreg intr-un sir si apoi il adauga la un alt sir. Supraincarcarea este folosita pentru a crea o interfata prin care se adauga la un sir fie un alt sir, fie un intreg.

• Desigur, doua functii supraincarcate pot sa difere si prin tipul returnat, dar nu este suficient.
Exemplu:
// Supraincarcari eronate:
a) int func_f(int k);
float func_f(int k); // nu difera decat prin tipul returnat

b) void f(int *x);
void f(int x[]); // nu difera prin argument

• Conversia automata a tipului, in C++, poate conduce la aparitia unor ambiguitati in supraincarcarea functiilor.
Exemplu:
func_f(double d);
……………………
cout<<func_f('c');
// este corect pentru ca in C++ se realizeaza o conversie automata de la
// caracterul 'c' la echivalentul sau double.
// Totusi in unele situatii se pot produce ambiguitati.
……………………………………..
float func_f(float f);
double func_f(double f);
main( )
{
cout<<func_f(15.2)<<" ";
// se apeleaza functia func_f(double)
cout<<func_f(56);
// compilatorul nu este informat cu privire la convertirea intregului in
// float sau double.
return 0;
}
float func_f(float f){return f;}
double func_f(double f){return f;}

• In C++, la selectarea functiei supraincarcate, se va tine cont de coincidenta intre cele doua liste de parametri (actuali si formali), ca numar si tip. #n cazul, in care o astfel de coincidenta nu exista, se va urmari selectarea acelei functii care va corespunde in urma unor conversii tip parametru actual in tip parametru formal, in ordine, dupa cum urmeaza:
(1) conversii predefinite (tipuri predefinite), fara trunchieri de informatii;
(2) conversii predefinite cu trunchieri de informatii;
(3) conversii predefinite cat si conversii ce corespund tipurilor definite de utilizator.
Daca in urma acestui proces este posibila selectarea mai multor functii, compilatorul va semnala eroare.

• Conform procesului de mostenire, daca CD este o clasa derivata a clasei de baza CB, atunci functiile membre ale clasei CB, vor fi functii membre si ale clasei CD. In general, inseamna ca o astfel de functie poate opera atat cu obiecte ale clasei CB cat si cu obiecte ale clasei CD. Exista insa situatii in care o functie mostenita sa nu poata fi apelata la obiecte ale clasei derivate. In acest caz se va proceda la supraincarcarea functiei pentru clasa derivata. La o astfel de supraincarcare pot ramane nemodificate identificatorul functiei, tipul si chiar numarul de parametri. Selectarea unor astfel de functii se va face in functie de obiectul pentru care sunt apelate.
Exemplu:
class CB
{
protected:
float u,v;
public:
CB(float t=0, float z=0)
{
u=t;
v=z;
}
void afis( )
{
cout<<”u=”<<u<<”\n”;
cout<<”v=”<<v<<”\n”;
}
};
class CD:public CB
{
protected:
float fu,fv;
public:
CD(float dt=0, float dz=0, float bt=0, float bz=0):CB(bt,bz)
{
fu=dt;
fv=dz;
}
void afis( )
{
........
...............
}
// se vor afisa cele patru valori ale obiectului curent , doua mostenite de la CB si doua specifice lui CD.
};
// #n definitia functiei afis( ) din CD se va apela functia afis( ) din CB cu ajutorul
// operatorului de rezolutie de domeniu.
void CD::afis( )
{
CB::afis( ); // pentru a afisa pe u,v
cout<<fu<<fv;
}

Exemple de apel:

CB ob(10,20);
CD od(10,20,30,40);
ob.afis( ); // functia membra a clasei CB
od.afis( ); // functia membra a clasei CD

• In afara faptului, ca functiile constructor au un rol unic in initializare, ele nu difera de alte feluri de functii. De aceea supraincarcarea functiilor constructor se intalneste foarte des. Supraincarcarea unui constructor permite crearea unui obiect cu cele mai convenabile metode.

• In C++, se pot supraincarca aproape toti operatorii, astfel incat ei sa efectueze diverse operatii in k clase create. La supraincarcarea unui operator, nu se pierde nimic din semnificatiile sale originale, ci doar se crește tipul obiectelor carora li se poate aplica.

• Un operator se poate supraincarca prin definirea unei functii operator. O functie operator defineste operatiile specifice pe care le va efectua operatorul supraincarcat relativ la clasa in care opereaza.

• Functiile operator pot fi sau nu functii membre ale clasei in care opereaza. De obicei, functiile operator, care nu sunt functii membre ale clasei in care opereaza, sunt functii friend.

• Sintaxa unei functii operator membra a unei clase;
tip_returnat iden_clasa :: operator id_operator(lista_param)
{ // operatii}
Cuvantul "operator" este un cuvant cheie, iar la crearea unei functii operator, id_operator reprezinta simbolul operatorului supraincarcat.

• Adesea, functiile membre operator returneaza un obiect din clasa asupra careia opereaza. De regula, ele nu sunt functii statice.

• Functia operator care supraincarca un operator binar contine un singur parametru. Motivul consta in aceea ca operandul din stanga operatorului binar este plasat implicit functiei prin pointerul this care este atasat functiei operator. Operandul din dreapta operatorului binar este transmis functiei opertor prin parametrul ob2. Apelul functiei operator este generat de obiectul reprezentat de operandul stang al operatorului binar respectiv.
Exemplu:
class ecran
{
int x0, y0;
public:
ecran(int x1, int y1)
{
x0=x1;
y0=y1;
}
void afis( )
{
cout<<x0<<"\n ";
cout<<y0<<"\n";
}
ecran operator +(ecran op2);
};
ecran ecran::operator +(ecran op2)
{
ecran u;
u.x0=op2.x0+x0;
u.y0=op2.y0+y0;
return u;
}
main( )
{
ecran ob_1(8,10), ob_2(9,15);
ob_1.afis( ); // se afiseaza 8 10
ob_2.afis( ); // se afiseaza 9 15
ob_1=ob_1+ob_2;
ob_1.afis( ); // se afiseaza 17 25
return 0;
}

• O situatie mai deosebita se intalneste la supraincarcarea operatorului binar de atribuire (asignare) „=“. Copierea datelor membre ale unui obiect sursa (reprezentat prin operandul drept al operatorului de atribuire) in datele membre corespunzatoare ale obiectului destinatie (reprezentat prin operandul stang al operatorului de atribuire), se poate realiza:
1) in faza de initializare, ceea ce implica si alocare de memorie
id_clasa ob_2=ob_1;
2) prin asignari de obiecte
id_clasa ob_1, ob_2;
ob_2=ob_1;

• Initializarea prin copiere se face cu susținerea constructorului de copiere. Daca un astfel de constructor nu exista in clasa respectiva, copierea se va face la indice de bit. Constructorul de copiere nu se apeleaza in situatia 2).

• Supraincarcarea operatorului de atribuire conduce la o solutionare corecta a operatiei de asignare de obiecte. O astfel de supraincarcare se va face in clase care contin date membre pointeri catre zone de memorie heap (alocare dinamica de memorie), sau exista functii care au ca parametri obiecte, respectiv returneaza obiecte.

• Ca si ceilalti operatori binari, supraincarcarea operatorului de atribuire se face cu o functie membra operator care nu este statica.

• Functia operator, care se mai poate identifica prin operator=( ), poate avea ca parametru:
a) un obiect de tipul clasei respective si returneaza un obiect de acelasi tip;
id_clasa id_clasa::operator = (id_clasa operand_drept);
b) o referinta si returneaza o referinta la obiectul curent;
id_clasa & id_clasa::operator =(id_clasa & operand_drept);

• In C++, in procesul de derivare, pentru membrii mosteniti dintr-o clasa de baza, in care s-a conceput supraincarcarea operatorului de atribuire, se apeleaza automat functia operator de supraincarcare. Pentru celelalte date membre se aplica procedeul de copiere la grad de bit. Daca operatorul de atribuire a fost supraincarcat pentru clasa derivata, functia operator realizeaza atribuirea obiectului sursa obiectului destinatie, in totalitate.

• Functia operator pentru supraincarcarea operatorului unar ++(preincrementare) nu contine parametri, operandul sau este transmis implicit prin pointerul this. Ca si la operatorul de atribuire, cel care isi modifica valoarea este operandul care a generat apelul functiei.
tip operator ++( )
{....// corpul operatorului preincrementare}

• Functia operator pentru supraincarcarea operatorului unar ++(postincrementare) :
tip operator++( int x)
{.
.........................
//corpul operatorului postincrementare, x primeste valoarea 0
}

• Analog pentru operatorii unari de predecrementare, respectiv postdecrementare (--).

Aplicatie:
Exemplificati supraincarcarea operatorilor binari - si =, respectiv a operatorului unar de preincrementare.
…………………………………………………….
class ecran
{
int x0,y0;
public:
ecran( );
// constructor implicit util in crearea obiectelor temporare
ecran (int x1, int y1){x0=x1; y0=y1;}
void afis( )
{
cout<<x0<<"\n ";
cout<<y0<<"\n";
}
ecran operator - (ecran op2);
ecran operator = (ecran op2);
ecran operator ++( );
};
ecran ecran::operator -(ecran op2)
{
ecran u;
u.x0=x0- op2.x0;
u.y0=y0- op2..y0;
return u;
}

ecran ecran::operator = (ecran op2)
{
x0=op2.x0;
y0=op2.y0;
return *this;
// se returneaza obiectul care a generat apelul "op1"modificat
}
ecran::operator ++( )
{
x0++;
y0++;
return *this;
}
main( )
{
ecran ob_1(5,8),ob_2(6,12), ob_3(10,10);
ob_1.afis( );
ob_2.afis( );
++ob_1;
ob_1.afis( ); // se afiseaza 6 9
ob_2=++ob_1;
ob_2.afis( ); // se afiseaza 7 10
ob_1 = ob_2= ob_3; // asignare multipla
ob_1.afis( ); // se afiseaza 10 10
ob_2.afis( ); // se afiseaza 10 10
return 0;
}
Sa observam functia operator "-". Operandul din dreapta operatorului "-" , conform semnificatiei operatiei de scadere, este scazut din operandul stang. Deoarece cel care genereaza apelul functiei operator este obiectul din stanga, datele din ob_2 trebuie scazute din cele corespunzatoare indicate prin pointerul this.

• Supraincarcarea operatorilor dintr-o asignare compusa:
Exemplu:
ecran ecran::operator +=(ecran op2)
{
x0=op2.x0+x0;
yo=op2.y0+y0;
return *this;
}

• La supraincarcarea operatorilor cu functii membre operator:
a) Nu se modifica precedenta operatorului;
b) Nu se modifica n-aritatea operatorului;

Aplicatie:
Utilizand supraincarcarea operatorilor "+" si "-" cu functii membre operator, sa se efectueze suma si diferenta a doi vectori de aceeasi dimensiune.

#include<iostream>
#include<math>
#include<conio>

class vector
{
double v[30];
int n;
public:
void cit_v(char*t);
void afis_v( );
vector operator+(vector &p);
vector operator -(vector &q);
double norma(void);
};
void vector::cit_v(char*t)
{
int m,i;
cout<<"DIM=\n";
cin>>m;
cout<<"VECTORUL \n";
for(i=1;i<=m;i++){
cout<<t<<"a"<<i<<"s=";
cin>>v[i];
}
n=m;
cout<<"\n";
}
void vector::afis_v( )
{
int i;
for(i=1;i<=n;i++)
cout<<i<<":"<<v[i]<<"\n";
}

vector vector::operator+(vector& p)
{
int i;
vector r;
for(i=1;i<=n;i++)
r.v[i]=v[i]+p.v[i];
r.n=n;
return r;
}
vector vector::operator-(vector &q)
{
int i;
vector r;
for(i=1;i<=n;i++)
r.v[i]=v[i]-q.v[i];
r.n=n;
return r;
}
double vector::norma(void)
{
int i;
double n=0;
for(i=1;i<=vector::n;i++)
n+=v[i]*v[i];
return sqrt(n);
}

void main( )
{
vector f,g,h;
clrscr( );
f.cit_v("a");
g.cit_v("b");
cout<<"a:\n";
f.afis_v( );
cout<<"Norma lui a="<<f.norma( )<<"\n";
cout<<"\n";
cout<<"b:\n";
g.afis_v( );
cout<<"Norma lui b="<<g.norma( )<<"\n";
cout<<"\n";
h=f+g;
cout<<"\n";
cout<<"c=a+b=";
h.afis_v( );
cout<<"\n";
h=f-g;
cout<<"d=a-b=";
h.afis_v ( );
getch( );
}
Vezi profilul utilizatorului Trimite mesaj privat
Afiseaza mesajele pentru a le previzualiza:   
Creaza un subiect nou   Raspunde la subiect

Subiectul urmator
Subiectul anterior
Nu puteti crea un subiect nou in acest forum
Nu puteti raspunde in subiectele acestui forum
Nu puteti modifica mesajele proprii din acest forum
Nu puteti sterge mesajele proprii din acest forum
Nu puteti vota in chestionarele din acest forum


Powered by phpBB © 2001, 2002 phpBB Group