cursul nr. 13 -...
TRANSCRIPT
Cursul nr. 13
PROGRAMARE ORIENTATA PE OBIECTE
- CLASE SI OBIECTE –
Principiile programării orientată pe obiecte (POO)
Clase şi obiecte (tipul class)
Clase cu membri obiecte. Compunerea claselor
Funcţii şi clase prietene unei clase
Supradefinirea operatorilor
Moştenirea. Clase derivate
Principiile programării orientată pe obiecte
Tehnologia programării orientate pe obiecte (OOP - Object
Oriented Programming sau POO – Programare Orientată pe
Obiecte)
• satisface cerinţele actuale ale dezvoltării de produse
software;
• oferă o mare flexibilitate şi eficienţă în activitatea de
programare;
• aplicaţiile realizate folosind POO sunt mai uşor de înţeles,
de depanat şi de dezvoltat decât aplicaţiile scrise folosind
limbaje procedurale.
Principiile programării orientată pe obiecte
Programarea obiectuală aplică principii specifice, şi anume:
încapsularea, care asigură o bună protecţie a datelor,
accesul la acestea putând fi strict controlat de
programator;
moştenirea, care permite construirea unor ierarhii
complexe de clase de date, cu preluarea proprietăţilor de
la descendent către noul tip de dată definit;
polimorfismul, care, într-o ierarhie de clase obţinută prin
moştenire, permite descrierea unei proprietăţi în mod
diferit, specific fiecărui nivel al ierarhiei.
Principiile programării orientată pe obiecte
Programarea orientata pe obiecte este o metoda de
implementare în care programele sunt organizate ca şi
colecţii de obiecte ce cooperează între ele;
Fiecare obiect reprezintă instanţa unei clase (reprezentarea
concretă);
Fiecare clasă aparţine unei ierarhii de clase, clasele fiind
unite prin relaţii de moştenire;
În limbajele orientate pe obiecte, obiectele şi nu algoritmii
sunt blocurile logice fundamentale;
Aplicaţiile sunt colecţii de obiecte - acestea reprezintă
entităţi care includ atât datele, cât şi procedurile care
acţionează asupra datelor, astfel încât ecuaţia POO este:
Obiect = Date + Metode
Principiile programării orientată pe obiecte
Se folosesc doi termeni: clasă şi instanţă.
Clasa este un tip de date şi reprezintă practic şablonul
pentru obiectele care se creează. O clasă se
caracterizează prin: numele clasei, atribute, funcţii şi
relaţii cu alte clase.
Instanţa este un obiect dintr-o clasă (de exemplu vector A,
este un obiect, o instanţă a clasei vector) şi are
proprietăţile definite de clasă. Pentru o clasă definită, se
pot crea mai multe instanţe ale acesteia.
Principiile programării orientată pe obiecte
Obiectele au o stare şi un comportament.
Starea unui obiect se referă la valorile asociate
elementelor conţinute în obiect (datele membre).
Comportamentul unui obiect este determinat de care
acţiunile pe care obiectul poate să le execute (metodele).
Atributele specificate în definiţia unei clase descriu valoric
proprietăţile obiectelor din clasă, sub diferite aspecte.
Metodele (funcţii membre) descriu comportamentul
obiectelor.
La definirea unei clase se definesc şi metodele acesteia
(numite şi funcţii membre).
Fiecare obiect are acces la setul de funcţii membre care
descriu operaţiile care pot fi executate asupra lui.
Metodele pot fi folosite de instanţele clasei respective, dar şi
de instanţele altor clase (prin mecanismul moştenirii).
CLASE ŞI OBIECTE
Clasele reprezintă tipuri de date care reprezintă şabloane
pentru obiecte care urmează a fi create. O clasă se
caracterizează prin: numele clasei, atribute, funcţii şi relaţii
cu alte clase.
Obiectele sunt instanţe ale claselor şi au proprietăţile definite
de clase.
Clasa = Date + Operaţii (metode)
Datele membre reprezintă atributele obiectelor şi ele conţin
seturi de valori proprii fiecărei instanţieri, pentru fiecare
existând alocare de memorie şi valori distincte.
Se pot defini şi atribute de clasă care se pot obţine prin date
membre statice, acestea având o unică alocare de memorie,
independentă de instanţierile clasei.
Metodele (funcţii membre) permit efectuarea de operaţii cu
obiectele clasei. Metodele pot fi folosite de instanţele clasei
respective, dar şi de instanţele altor clase prin mecanismul
moştenirii sau de funcţii independente (nemembre ale
claselor) dacă au fost declarate prietene clasei.
CLASE ŞI OBIECTE
C++ se distinge de limbajele POO pure prin faptul că permite
controlul accesului atât la datele membre, cât şi la funcţiile
membre unei clase.
În acest scop se folosesc specificatorii de control al
accesului:
public: membrul poate fi accesat de orice funcţie din
domeniul de declaraţie a clasei;
private: membrul este accesibil numai funcţiilor membre
şi prietene clasei;
protected: membrul este accesibil atât funcţiilor membre
şi prietene clasei, cât şi funcţiilor membre şi prietene
claselor derivate din clasa respectivă.
O funcţie membră a unei clase are acces la toate datele
membre ale oricărui obiect din clasa respectivă, indiferent de
specificatorul de acces.
CLASE ŞI OBIECTE
În C++ se pot declara mai multe categorii de clase folosind
cuvintele cheie: struct, union, respectiv class. Variabilele de
acest tip se numesc obiecte struct, union, respectiv class.
Tipurile class sunt mai frecvent utilizate, ele corespunzând
mai fidel conceptului POO.
CLASE ŞI OBIECTE
Sintaxa generală de declarare a unui tip de date class este:
class <nume_clasa> <: lista_clase_baza>
{ <lista_membri> } <lista_variabile>;
unde:
nume_clasa este un identificator care desemnează numele
tipului clasă declarat, care trebuie să fie unic în domeniul
în care este valabilă declaraţia;
lista_clase_baza este lista claselor din care este derivată
clasa declarată (dacă este cazul);
lista_membri reprezintă secvenţa cu declaraţii de datele
membre şi declaraţii sau definiţii de funcţii membre;
lista_variabile este lista variabilelor de tip nume_clasa.
CLASE ŞI OBIECTE
Datele membre ale clasei se declară prin tip şi nume cu
sintaxa:
specificator_de_acces:
tip_date nume_membru;
tip_date nume_membru;
…
Datele membre pot fi de orice tip, mai puţin tipul clasă
declarat, dar se admit pointeri către acesta, deci pot fi de
tipuri predefinite, char, int, float, etc., pot fi pointeri sau
tablouri de date, sau tipuri definite de utilizator, structuri,
clase, etc.
CLASE ŞI OBIECTE
Funcţiile membre ale clasei se declară în interiorul declaraţiei
clasei prin prototipul funcţiei (tip, nume, lista parametri) sau
prin definiţia completă a funcţiei, folosind sintaxa:
specificator_de_acces:
tip nume_funcţie(lista_parametri); // prototip functie
tip nume_funcţie(lista_parametri) // definiţie functie
{
// lista instructiuni
….
}
…
CLASE ŞI OBIECTE
Funcţiile membre ale unei clase definite în declaraţia acesteia
sunt implicit din categoria inline.
Pentru definiţiile de funcţii aflate în afara declaraţiei clasei
este necesar să se specifice numele clasei urmat de
operatorul de rezoluţie (::) alăturat numelui funcţiei.
Operatorul indică compilatorului că funcţia respectivă are
acelaşi domeniu cu declaraţia clasei respective, fapt ce
permite referirea directă a membrilor clasei. În caz contrar,
compilatorul consideră că se defineşte o funcţie cu acelaşi
nume, externă clasei respective.
tip nume_clasa:: nume_funcţie(lista_parametri)
{
// lista instrucţiuni
….
}
Funcţiile membre ale unei clase pot fi supradefinite şi pot
avea parametri impliciţi.
CLASE ŞI OBIECTE
La declararea obiectelor de tip clasă se foloseşte sintaxa
specifică declarării de variabile precizând tipul şi numele
acestora, adică se specifică numele clasei şi numele
obiectelor (lista de identificatori):
nume_clasa lista_identificatori;
CLASE ŞI OBIECTE
class Punct
{private: // se specifică accesul private la membrii clasei
int x, y; // date membre ale clasei
public: // se specifică acces public la membrii clasei
void init(int initx=0, int inity=0) // funcţie de iniţializare, funcţie
{ x = initx; // membră cu parametri impliciţi
y = inity;
}
int getx() // funcţie inline, returnează valoarea membrului x
{ return x; }
int gety() // funcţie inline, returnează valoarea membrului y
{ return y; }
void afisare() // funcţie de afişare a valorilor membrilor,
{ cout<<”\nx=”<<x<<”\tz=”<<y; }
void move(int dx, int dy); // funcţie membră cu parametri, definită în
// afara declaraţiei clasei
};
CLASE ŞI OBIECTE
Funcţia membră move() se defineşte în afara declaraţiei
clasei, folosind sintaxa:
void Punct::move(int dx, int dy)
{
x+=dx;
y+=dy;
}
Obiectele de tip Punct se declară, precizând tipul şi numele
lor:
Punct p1, p2; // se declară un obiect de tip Punct, p1 şi p2
CLASE ŞI OBIECTE
Pentru referirea datelor membre şi apelul funcţiilor membre
pentru un obiect, se folosesc operatorii de selecţie (.) şi (->),
ca în cazul structurilor şi uniunilor din C.
CLASE ŞI OBIECTE
p1.init(x1, y1); // iniţializarea obiectului Punct1 cu valorile x1, respectiv y1
p2.init(); // membrii x şi y preiau valorile implicite ale parametrilor, deci
// x=y=0
cout<<"\n x este = "<<p1.getx(); // afişarea coordonatei x
cout<<"\n y este = "<< p1.gety(); // afişarea coordonatei y
p1.move(10, 20); //modificarea coordonatelor obiectului p1
p1.afisare(); // afişarea caracteristicilor obiectului p1
Punct *pp; // se declară un pointer la Punct care poate
// prelua adresa unui obiect de tip Punct
pp = &p2;
pp-> move ( 5, 12); // apelul funcţiilor membre se face folosind
// operatorul de selecţie “->”
pp -> afisare(); // afişarea caracteristicilor obiectului p2 prin
// pointerul pp
Punct &rp = p1; // se declara referinţa rp la obiectul p1
rp.afisare(); // afişarea caracteristicilor obiectului p1 prin
// referinţa sa rp
CLASE ŞI OBIECTE
În definiţiile funcţiilor membre sunt necesare referiri la datele
membre ale clasei respective. Acest lucru se poate face fără
a specifica numele obiectului.
La apelarea unei funcţii membre, identitatea obiectului asupra
căruia se acţionează este cunoscută datorită transferului unui
parametru implicit care reprezintă adresa obiectului.
Dacă în definiţia unei funcţii este necesară utilizarea adresei
obiectului, acest lucru se realizează cu cuvântul cheie this,
asociat unui pointer către obiectul pentru care s-a apelat
funcţia.
void Punct::adresa()
{
cout << ”\n Adresa obiectului de tip Punct este:”
cout << this;
}
Constructori şi destructori
Pentru crearea, iniţializarea, copierea şi distrugerea
obiectelor, în C++ se folosesc funcţii membre speciale, numite
constructori şi destructori.
Constructorul se apelează automat la crearea fiecărui obiect
al clasei, indiferent dacă este static, automatic sau dinamic
(creat cu operatorul new), inclusiv pentru obiecte temporare.
Destructorul se apelează automat la eliminarea unui obiect, la
încheierea timpului de viaţă sau, în cazul obiectelor dinamice,
cu operatorul delete.
Aceste funcţii efectuează operaţiile prealabile utilizării
obiectelor create, respectiv eliminării lor. Alocarea şi
eliberarea memoriei necesare datelor membre rămâne în
sarcina compilatorului.
Constructori şi destructori
Constructorii şi destructorii se deosebesc de celelalte funcţii
membre prin câteva caracteristici specifice:
numele funcţiilor constructor sau destructor este identic
cu numele clasei căreia îi aparţin; numele destructorului
este precedat de caracterul tilde (~);
la declararea şi definirea funcţiilor constructor sau
destructor nu se specifică nici un tip returnat (nici măcar
tipul void);
nu pot fi moşteniţi, dar pot fi apelaţi de clasele derivate;
nu se pot utiliza pointeri către funcţiile constructor sau
destructor;
constructorii pot avea parametri, inclusiv parametri
impliciţi şi se pot supradefini; destructorul nu poate avea
parametri şi este unic pentru o clasă, indiferent câţi
constructori au fost declaraţi.
Constructori şi destructori
class Punct
{ private:
int x, y;
public:
Punct() // constructor implicit
{ cout<<”\nConstructor implicit\n”;
x=0; y=0;
}
Punct(int initx, int inity) // constructor cu parametri
{ cout<<”\nConstructor cu parametri\n”;
x=initx; y=inity;
}
~Punct() // destructor
{ cout<<”\nDestructor Punct\n”;
}
int getx() { return x; }
int gety() { return y; }
void move(int dx, int dy);
void afisare()
{ cout<<”\nx=”<<x<<”\tz=”<<y; }
};
Constructori şi destructori
Constructor de copiere
La crearea unui obiect, acesta poate prelua valorile
corespunzătoare ale unui obiect deja existent, prin apelul
unui constructor special, numit constructor de copiere.
Declaraţia constructorului de copiere pentru o clasă este
un constructor cu un parametru unic de tip referinţă la
obiecte de tipul clasei ce se defineşte:
nume_clasa( nume_clasa &);
În absenţa definirii explicite a constructorului de copiere
în cadrul clasei, compilatorul generează automat un
constructor de copiere care iniţializează datele membre
ale obiectului nou creat cu valorile corespunzătoare ale
obiectului specificat, copierea făcându-se membru cu
membru
Punct::Punct(Punct &P)
{ cout<< “\n Constructor de copiere”;
x=P.x;
y=P.y;
}
Manevrarea dinamică a obiectelor
Se pot crea şi distruge obiecte dinamice utilizând operatorii
new şi delete.
Operatorul new alocă memorie corespunzător tipului datei. În
plus, folosirea operatorului new în cazul tipurilor clasă, are ca
efect şi apelul unui constructor.
Operatorul delete, în momentul eliminării obiectului din
memorie va apela funcţia destructor.
Punct *pp; // declararea unui pointer la tipul Punct
pp=new Punct; // alocare dinamica de memorie - se apeleaza
// constructorul implicit
cout <<"\nPozitia referita prin Pointerul pp este:";
pp->afisare();
delete pp; // eliminarea obiectului alocat la adresa pp;
// se apelează în mod implicit destructorul
Tablouri de obiecte
Tablourile pot avea elemente de orice tip, inclusiv de tip
clasă.
La crearea unui tablou cu elemente de tip clasă, se va apela
constructorul clasei tip element pentru fiecare element în
parte.
În cazul tablourilor nu există posibilitatea specificării valorilor
corespunzătoare parametrilor, deci, pentru tipul clasă
corespunzător elementelor tabloului, este obligatoriu să
existe declarat constructor implicit sau constructor cu toţi
parametrii impliciţi.
Pentru fiecare element de tablou de tip clasă se apelează
constructorul, iar la încetarea domeniului de existenţă a
tabloului, pentru fiecare element de tablou se apelează
destructorul clasei.
Tablouri de obiecte
Tablourile pot avea elemente de orice tip, inclusiv de tip
clasă.
La crearea unui tablou cu elemente de tip clasă, se va apela
constructorul clasei tip element pentru fiecare element în
parte.
În cazul tablourilor nu există posibilitatea specificării valorilor
corespunzătoare parametrilor, deci, pentru tipul clasă
corespunzător elementelor tabloului, este obligatoriu să
existe declarat constructor implicit sau constructor cu toţi
parametrii impliciţi.
Pentru fiecare element de tablou de tip clasă se apelează
constructorul, iar la încetarea domeniului de existenţă a
tabloului, pentru fiecare element de tablou se apelează
destructorul clasei.
Tablouri de obiecte
Tablourile pot fi create prin:
a. alocare statică de memorie
b. alocare dinamică de memorie
a.
cout<<"\nSe aloca static un tablou cu 5 elemente de tip Punct\n";
Punct tab[5]; // declararea unui tablou cu elemente de tip Punct; se
// apelează de 5 ori constructorul implicit
cout<<"\nElementele tabloului au valorile:\n";
for( i=0; i<5; i++) // se apelează functia de afisare pentru fiecare
tab[i].afisare(); // element al tabloului
b.
cout<<"\nSe aloca dinamic un tablou cu 6 elemente de tip Punct\n";
pp=new Punct[6]; // se aloca memorie pentru un tablou cu 6 elemente de
// tip Punct; se apelează de 6 ori constructorul implicit
cout<<"\nElementele tabloului au valorile:\n";
for( i=0; i<6; i++) // se apelează functia de afisare pentru fiecare
pp[i].afisare(); //element al tabloului
...
delete [ ] pp;
Transferul obiectelor ca parametri sau rezultat al funcţiilor
Parametrii funcţiilor şi rezultatul returnat de către acestea
pot fi obiecte ale unor clase.
Transferul se poate face în cele trei moduri:
a. Transfer prin valoare
b. Transfer prin adresa
c. Transfer prin referinta
a. void functia_1(Punct p)
{ p.afisare();
p.move(1,2);
p.afisare();
}
b. void functia_2(Punct*p)
{ p->afisare();
p->move(1,2);
p->afisare();
}
c. void functia_3(Punct&p)
{ p.afisare();
p.move(1,2);
p.afisare();
}
CLASE CU MEMBRI OBIECTE. COMPUNEREA CLASELOR.
Agregarea sau compunerea (ierarhia de obiecte) este relaţia
între două obiecte în care unul dintre obiecte aparţine
celuilalt obiect. Semantic, agregarea indică o relaţie de tip
"part of" ("parte din").
Obiectul B este parte componentă a obiectului A:
Clasele pot avea membri de orice tip, mai puţin tipul clasă
care se defineşte, deci membrii unei clase pot fi la rândul lor
de tip definit printr-o altă clasă.
Clasele care conţin membri de tip clasă se numesc clase
compuse.
CLASE CU MEMBRI OBIECTE. COMPUNEREA CLASELOR.
class tablou
{ int nr_el; // dimensiunea tabloului
double *tab; // adresa tabloului de elemente
public:
tablou(); // constructor implicit
tablou(int); // constructor cu parametru
tablou(tablou &); // constructor de copiere
~tablou(); // destructor
void citire();
void afisare();
void modif(unsigned int, double);
};
class elev
{ char nume[30]; // sir de caractere
tablou note; // membru de tip tablou
public:
elev(int=8, char * =” ”);
~elev();
void citire_nume();
void citire_note();
void modif_nota(int, double);
void afisare(); // afiseaza numele, notele si media elevului
};
FUNCŢII ŞI CLASE PRIETENE UNEI CLASE
Accesul la membrii private ai unei clase se poate acorda, în
afara funcţiilor membre şi unor funcţii care nu sunt membre
ale clasei, dacă sunt declarate cu specificatorul friend.
Funcţiile declarate prietene unei clase pot fi funcţii
independente sau funcţii membre ale altor clase.
Funcţiile prietene sunt externe clasei, deci apelul lor nu se
face asociat unui obiect al clasei.
Funcţiile prietene sun funcţii ordinare, care se declară şi se
definesc folosindu-se sintaxa obişnuită. Relaţia de prietenie
cu o clasă este declarată în interiorul clasei căreia îi este
prietenă acea funcţie, ataşând cuvântul cheie friend la
prototipul funcţiei:
friend tip_functie nume_functie(lista_parametri);
Funcţiile prietene unei clase au acces direct la membrii
privaţi ai clasei, deci se încalcă principiul încapsulării, dar în
anumite situaţii sunt utile.
FUNCŢII ŞI CLASE PRIETENE UNEI CLASE
Funcţiile prietene au acces la toţi membrii clasei, ele operând
asupra obiectelor de tip clasă, obiecte declarate în funcţie,
sau care se transferă ca parametri ai funcţiei.
Transferul se poate face în orice modalitate, prin valoare, prin
adresă sau prin referinţă.
Pot fi referiţi toţi membrii obiectelor clasei prietene, private
sau public, referirea făcându-se prin numele obiectului,
operatorul de selecţie şi numele membrului, dată sau funcţie.
Se pot întâlni următoarele situaţii:
• funcţie independentă este prietenă unei clase ;
• funcţie membră a unei clase este prietenă altei clase;
• o funcţie este prietenă mai multor clase ;
• o clasă este prietenă altei clase (toate funcţiile membre
ale unei clase sunt prietene celeilalte clase).
FUNCŢII ŞI CLASE PRIETENE UNEI CLASE
class pozitie
{ int x, y; // x, y reprezinta coordonatele punctului
public:
pozitie(int abs=0, int ord=0) // constructor cu parametri impliciti
{ x=abs;
y=ord;
}
void deplasare(int dx, int dy) // functie membra, modifica
{ x+=dx; // coordonatele punctului
y+=dy;
}
friend double distanta(pozitie &, pozitie &); // funcţia distanta() se declară
// prietenă clasei pozitie
};
double distanta(pozitie &p1, pozitie &p2)
{ return sqrt((p1.x-p2.x)* (p1.x-p2.x)+ (p1.y-p2.y)* (p1.y-p2.y));
}
void main()
{ pozitie p1(1, 1), p2(3, 3); // declaratii de obiecte de tip pozitie
p1.deplasare(2, 2); // apel al funcţiei deplasare(); este functie membra
// a clasei, deci se apeleaza printr-un obiect al clasei
cout<<”\nDistanta dintre p1si p2 este:” << distanta(p1, p2); // apel al funcţiei
} // distanta()
SUPRADEFINIREA OPERATORILOR
Limbajul C++ permite programatorului definirea diverselor
operaţii cu obiecte ale claselor, folosind simbolurile
operatorilor standard.
Operatorii standard sunt deja supradefiniţi, ei putând intra în
expresii ai căror operanzi sunt de diferite tipuri fundamentale,
operaţia adecvată fiind selectată în mod similar oricăror
funcţii supradefinite.
Un tip clasă poate conţine definirea unui set de operatori
specifici asociaţi, prin supradefinirea operatorilor existenţi,
utilizând funcţii cu numele:
operator simbol_operator
unde:
- operator este cuvânt cheie dedicat supradefinirii
operatorilor;
- simbol_operator poate fi simbolul oricărui operator, mai
puţin următorii operatori: ( . ), (.*), (::) şi ( ? : ).
SUPRADEFINIREA OPERATORILOR
Pentru definirea funcţiilor operator se pot folosi două variante
de realizare:
• definirea funcţiilor operator cu funcţii membre clasei;
• definirea funcţiilor operator cu funcţii prietene clasei.
Prin supradefinirea operatorilor nu se pot modifica:
• pluralitatea operatorilor (operatorii unari nu pot fi
supradefiniţi ca operatori binari sau invers);
• precedenţa şi asociativitatea operatorilor.
SUPRADEFINIREA OPERATORILOR
Operatorii care se pot supradefini
Clasa de
prioritate Tip Operatori Asociativitate
1 Binar () [] -> de la stânga la dreapta
2 Unar ! ~ + - ++ -- & * (tip)
new delete
de la dreapta la stânga
3 Binar ->* de la stânga la dreapta
4 Binar * / % de la stânga la dreapta
5 Binar + - de la stânga la dreapta
6 Binar << >> de la stânga la dreapta
7 Binar < <= > >= de la stânga la dreapta
8 Binar = = != de la stânga la dreapta
9 Binar & de la stânga la dreapta
10 Binar ^ de la stânga la dreapta
11 Binar | de la stânga la dreapta
12 Binar && de la stânga la dreapta
13 Binar || de la stânga la dreapta
14 Binar = *= /= %= += -= &= ^=
|= <<= >>=
de la dreapta la stânga
15 Binar , (operator virgulă) de la stânga la dreapta
SUPRADEFINIREA OPERATORILOR
Funcţia operator trebuie să aibă cel puţin un parametru,
implicit sau explicit de tipul clasă căruia îi este asociat
operatorul.
Operatorii =, [], (), -> pot fi supradefiniţi doar cu funcţii
membre nestatice ale clasei.
Programatorul are deplină libertate în modul în care
defineşte noua operaţie, dar în general pentru a da o bună
lizibilitate programului, se recomandă ca noua operaţie să fie
asociată semnificaţiei originare, dacă ea există pentru
respectivul operator asociat cu clasa definită.
SUPRADEFINIREA OPERATORILOR
class complex
{ private:
double re, im;
public:
complex(double r=0, double i=0)
{ re=r; im=i; }
void afisare()
{ cout<<”\nre=”<<re<<”\tim=”<<im; }
// funcţia operator+ (operatie binara) este funcţie prietenă clasei complex
friend complex operator+(complex&, complex&);
// funcţia operator++ (operatie unara) este funcţie prietenă clasei complex
friend complex operator++(complex&);
};
complex operator+(complex& a, complex& b) // funcţia operator+() este funcţie
{ complex c; // externă clasei complex
c.re=a.re+b.re;
c.im=a.im+b.im;
return c;
}
complex operator++(complex&c)
{ c.re++;
c.im++;
return c;
}
SUPRADEFINIREA OPERATORILOR
void main()
{
complex c1(1, 2), c2(3, 4), c3, c4; // declaratii de variabile complex
c1.afisare();
c2.afisare();
c3=c1+c2; // operator+(c1,c2);
c3.afisare();
c4=c1+c2+c3; // operator+(operator+(c1,c2), c3);
c4.afisare();
(c1+c2).afisare();
++c1; // operator++(c1);
c1.afisare();
c3=++c2; // c3=operator++(c2);
c3.afisare();
}
SUPRADEFINIREA OPERATORILOR
class complex
{ private:
double re, im;
public:
complex(double r=0, double i=0)
{ re=r; im=i; }
void afisare()
{ cout<<”\nre=”<<re<<”\tim=”<<im; }
// funcţia operator+ (operatie binara) este funcţie membră a clasei complex
complex operator+(complex);
// funcţia operator++ (operatie unara) este funcţie membră a clasei complex
complex operator++();
};
complex complex::operator+(complex c) // definiţia funcţiei operator+()
{ complex aux;
aux.re=re+c.re;
aux.im=im+c.im;
return aux;
}
complex operator++()
{ re++;
im++;
return *this;
}
SUPRADEFINIREA OPERATORILOR
void main()
{
complex c1(1, 2), c2(3, 4), c3, c4; // declaratii de variabile complex
c1.afisare();
c2.afisare();
c3=c1+c2; // c1.operator+(c2);
c3.afisare();
c4=c1+c2+c3; // temp=c1.operator+(c2);
// c4=temp.operator+(c3);
c4.afisare();
(c1+c2).afisare();
++c1; // c1.operator++();
c1.afisare();
c3=++c2; // c3=c2.operator++();
c3.afisare();
}
MOŞTENIREA. CLASE DERIVATE.
Unul dintre principiile de bază ale programării orientate pe
obiecte este moştenirea.
Prin moştenire, pornind de la o clasă definită, cu anumite
proprietăţi, care constituie clasa de bază, se creează seturi
de clase asemănătoare, numite clase derivate, care
completează proprietăţile clasei de bază cu noi proprietăţi.
Clasele derivate conţin toţi membrii clasei de bază, la care se
adaugă noi membrii, date şi funcţii membre.
Clasa de bază nu este afectată de derivare, ea putând fi
compilată anterior eventualelor derivări.
Dintr-o clasă de bază se poate deriva o clasă care, la rândul
său, să servească drept clasă de bază pentru derivarea altora.
Prin această succesiune se obţine o ierarhie de clase.
Pornind de la clase simple şi generale, fiecare nivel al
ierarhiei adaugă noi proprietăţi, obţinându-se clase cu un grad
sporit de complexitate, devenind din ce în ce mai specializate.
Tehnica derivării asigură productivitate în procesul de
programare.
Se pot defini clase derivate care au la bază mai multe clase,
înglobând proprietăţile tuturor claselor de bază, procedeu ce
poartă denumirea de moştenire multiplă.
MOŞTENIREA. CLASE DERIVATE.
Sintaxa generală de declarare a unui tip de date class este de
forma:
class <nume_clasa> <: lista_clase_baza> {<lista_membri>}
<lista_variabile>;
lista_clase_baza cuprinde unul (în cazul unei derivări simple)
sau mai multe (în cazul unei derivări multiple) nume de clase,
însoţite de câte un specificator de acces.
Specificatorul de acces controlează drepturile de acces la
membrii clasei de bază.
Lista claselor de bază are sintaxa următoare:
specificator_acces clasa_baza_1, specificator acces
clasa_baza_2,…
Specificatorii de acces care se pot utiliza sunt public şi
private. Valoarea implicită este private.
MOŞTENIREA. CLASE DERIVATE.
Atributele de acces moştenite de clasele derivate
Atributul din
clasa de bază
Modificatorul de
acces
Accesul moştenit
de clasa derivată
Accesul din
exterior
private
private
inaccesibil inaccesibil
protected private inaccesibil
public private inaccesibil
private
public
inaccesibil inaccesibil
protected protected inaccesibil
public public accesibil
MOŞTENIREA. CLASE DERIVATE.
class punct
{ protected: // specificatorul de acces protected permite accesul la datele
// membre ale clasei punct din clasele derivate, asigurând în
// continuare protecţia faţă de funcţiile externe acestora
float x, y;
public :
punct(float a=0, float b=0) { x=a; y=b; }
void modific_punct(float dx, float dy) { x+=dx; y+=dy; }
void afisare() { cout<<"\nPunct: x="<<x<<"\ty="<<y; }
};
class cerc : public punct // în declaraţie se specifică clasa de bază punct cu
{ float raza; // acces public
public:
cerc(float r=0) { raza=r; }
// accesul la membrii clasei punct se face direct datorită specificatorului
// protected din clasa punct şi a specificatorului public ataşat clasei de bază
void afisare() { cout<<"\nCentru cerc: x="<<x<<"\ty="<<y;
cout<<"\tRaza="<<raza; }
void modific_cerc(float dx, float dy, float dr)
{ x+=dx; y+=dy; raza+=dr; } // acces direct la membrii clasei punct
};
MOŞTENIREA. CLASE DERIVATE.
void main()
{
punct p1(1.5, 2.5);
p1.modific_punct(1, 1);
p1.afisare();
cerc c1;
c1.modific_cerc(1.1, 2.2, 3.3);
c1.afisare();
c1.modific_punct(2.5, 4.6); // accesul la funcţiile membre clasei punct
// prin obiecte de tip cerc este permis
c1.afisare();
cerc * p_cerc; // declaratia unui pointer la tipul cerc
p_cerc = &c1;
p_cerc->afisare(); // apelul funcţiilor prin pointerul p_cerc
p_cerc-> modific_cerc(1.1, 2.2, 3.3);
p_cerc-> modific_punct(2.5, 4.6);
p_cerc->afisare();
}