Cursul nr. 13 -...

46
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

Transcript of Cursul nr. 13 -...

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

}