ALTE DOCUMENTE
|
|||||||||
Definirea claselor si tipuri abstracte de date
O clasa este un tip de date a carei variabile sunt obiecte. Un obiect este o variabila care are membri functii la fel ca si posibilitatea de memorare a valorilor de date.
O structura este un tip definit ce permite declararea de membri variabile. Deci, pentru a obtine o clasa dintr-o structura, trebuie sa adaugam functii membru.
Incapsularea
Combinarea unui numar de articole, cum ar fi variabilele si functiile, intr-un singur pachet, cum ar fi obiectul unei clase, se numeste incapsulare.
Cand se defineste o functie membru, definitia trebuie sa includa numele clasei, pentru ca pot exista doua sau mai multe clase care au functii membru cu acelasi nume.
Operatorul :: se numeste operatorul rezolutiei de domeniu, si serverste la un scop similar cu cel al operatorului punct. Atat operatorul punct, cat si al rezolutiei de domeniu precizeaza din care clasa face parte functia membru respectiva.
ATENTIE ! Operatorul rezolutiei de domeniu :: este folosit cu numele clasei, pe cand operatorul punct e 151h77b ste folosit cu obiecte (adica variabile ale unei clase).
Numele clasei care precede operatorul rezolutiei de domeniu se numeste calificator de tip, deoarece acesta califica numele functiei la unul particular.
Sintaxa generala a definitiei unei functii membru a clasei C foloseste operatorul rezolutiei de domeniu :
Tip_Returnat C :: nume_functie (lista_parametri)
Exemplu:
Functia afisare() din programul C++ de mai jos apartine clasei zi_din_an. In concluzie, retinem ca operatorul punct este folosit pentru apelarea unei date sau functii membru ale unui obiect, iar operatorul rezolutiei de domeniu este folosit pentru definirea unei functii membru a unei clase.
Programul urmator este un exemplu simplu de clasa.
#include <iostream.h>
class zi_din_an
;
int main()
void zi_din_an::afisare()
Membrii private si public
Am vazut in exemplul precedent ca datele si functiile membru din clasa zi_din_an erau public. Deci acestea erau accesibile din orice functie a programului respectiv. Sunt situatii cand nu ne intereseaza modul de implementare (codificare, memorare) a datelor sau functiilor sau nu dorim sa fie accesibile. Atunci le vom declara private. Acest lucru se face folosind cuvantul rezervat private, lista membrilor care apar dupa acesta se numesc membri privati (date sau functii private).
Programul urmator ilustreaza aceasta tehnica pentru date private.
#include <iostream.h>
class zi_din_an
;
int main()
void zi_din_an::afisare()
void zi_din_an::citire()
void zi_din_an::set(int noua_zi, int noua_luna)
int zi_din_an::obtine_zi()
int zi_din_an::obtine_luna()
Cand se defineste o clasa, de obicei toti membrii variabila sunt privati. Asta inseamna ca membrii variabila pot doar sa fie accesati sau modificati prin functii membru.
Sintaxa generala este:
class nume_clasa
;
ATENTIE ! Nu uitati la sfarsitul declararii unei clase semnul ; Functiile membru care permit accesarea variabilelor membru private se numesc functii accessor (de acces). In exemplul precedent functiile obtine_zi si obtine_luna sunt functii accessor.
Este legala folosirea intructiunii de atribuire pentru obiecte. De exemplu in programul precedent daca scriem:
zi_nastere = azi;
aceasta este echivalenta cu
zi_nastere.zi = azi.zi;
zi_nastere.luna = azi.luna;
Mai mult, atribuirea este legala chiar daca varibilele membru sunt membri privati.
Comparatie intre class, struct si union
Structurile sunt folosite de obicei cu toate variabilele membru publice si fara functii mebru. Cu toate acestea, o structura C++ poate avea variabile membru private si functii membru private si publice. Totusi se recomanda, folosirea structurilor in varianta clasica.
Un union este similar cu un struct, cu exceptia faptului ca permite definirea de varibile care impar spatiul de memorie.
Exemplu:
union int_sau_long
un_numar;
Compilatorul va aloca memorie suficienta pentru memorarea variabilei un_numar pentru a incape in cel mai mare element din union.
Elementele unui union sunt accesata in aceeasi maniera ca la struct.
Constructori
Deseori, dorim sa initializam toate variabilele membru pentru un obiect cand il declaram. Constructorul este o functie membru care este automat apelata cand un obiect al acestei clase este declarat. Un constructor este folosit pentru initializarea valorilor unor sau tuturor variabilelor membru precum si pentru a face alte tipuri de initializari pe care le dorim. Exista doua exceptii fata de functiile membru obisnuite:
1. Un constructor trebuie sa aiba acelasi nume ca al clasei.
2. Definitia constructorului nu poate intoarce o valoare. Mai mult, nu se precizeaza tipul intors, nici macar void.
Exemplu: continuam exemplul precedent
class zi_din_an
;
Putem intelege obiectele azi, respectiv zi_de_nastere astfel:
zi_din_an azi(22, 3), zi_nastere(16, 4);
Este eronat sa facem astfel (ca la functii membru obisnuite):
zi_din_an azi, zi_nastere;
azi.zi_din_an(22, 3);
zi_nastere.zi_din_an(16, 4);
Un constructor nu poate fi apelat la fel ca functiile membru obisnuite. Definitia unui constructor se da in acelasi mod ca orice alta functie membru.
Exemplu:
zi_din_an::zi_din_an(int noua_zi, int noua_luna)
Observam ca definitia constructorului este similara cu cea a functiei membru set (din programul precedent). Diferenta este ca nu intoarce nimic (nici macar void).
In general, constructorii sunt supraincarcati, deci obiectele se pot initializa in mai multe moduri.
Un constructor se poate apela de mai multe ori pentru un obiect. Sintaxa apelului explicit a unui constructor este diferita de sintaxa folosita pentru apelul altor functii membru. Un constructor se apeleaza cu operatorul de asignare = in loc de operatorul punct.
Exemplu: Am vazut ca putem apela constructorul in momentul declararii, astfel:
zi_din_an azi(22,3);
Putem acum reapela contructorul, astfel:
azi = zi_din_an(22,3);
De fapt un constructor este o functie ce returneaza un obiect de tipul clasei respective.
ATENTIE ! Constructorul este privit ca o functie membru care initializeaza un obiect si poate fi apelat folosind o sintaxa neobisnuita.
Constructori fara argumente
Daca in definitia unei clase, exista macar o definitie de constructor, atunci C++ va alege spre folosinta definitia potrivita.
Exemplu:
class C1
;
Putem apela constructorul astfel:
C1 obiect(7,2.5);
O declaratie de genul
C1 obiect1;
este gresita deoarece exista in definitia clasei doar un singur constructor cu doua argumente. Declaratia de mai sus ar fi corecta daca ori declaram obiect1 de doua argumente, ori mai declaram in clasa C1 un constructor fara argumente.
Un constructor fara argumente se numeste constructor implicit, deoarece se aplica in cazul implicit cand declaram un obiect fara specificarea vreunui argument.
Exemplu: Redefinim clasa C1 astfel:
class C1
;
Acum declaratia C1 obiect1; este corecta.
ATENTIE ! Declaratia C1 obiect1; poate cauza probleme. Compilatorul ar putea crede ca este vorba de un prototip pentru o functie numita obiect1 fara argument si care intoarce o valoare de tip C1.
Daca am declarat un obiect al unei clase folosind constructorul implicit, atunci il putem initializa apoi folsind alt constructor.
Exemplu: pentru clasa de mai sus putem avea:
C1 obiect;
obiect = C1(4,6.7);
In schimb nu putem avea declaratiile (motivul este explicat mai sus):
C1 obiect();
obiect = C1(4,6.7);
Tipuri de date abstracte
Un tip de data este o multime de valori impreuna cu o multime de operatii de baza definite pentru aceste valori.
Exemplu:
int este un tip de data ce foloseste valorile
si operatiile +,-,*,/,% (si altele)
Un tip de data se numeste tip de data abstract (ADT-Abstract Data Type) daca programatorii ce folosesc acel tip nu au acces la detaliile implementarii valorilor si operatiilor.
Exemplu: tipurile predefinite (cum ar fi int) sunt tipuri de date abstracte.
Tipurile definite de programator, cum ar fi struct si class nu sunt implicit tipuri abstracte de date.
Daca nu sunt definite si folosite cu atentie, tipurile definite de programator pot fi folosite in mod neintuitiv pentru a face un program greu de inteles si de modificat. Modul cel mai bun de a evita aceste probleme este sa fim siguri ca toate tipurile de date declarate de programator sunt tipuri
abstracte de date.
Pentru a defini o clasa care sa fie un tip abstract de date, trebuie sa separam specificarile modului de folosire a tipului de catre programator de detaliile modului de implementare a tipului.
Separarea trebuie sa fie completa astfel incat la o schimbare in implementarea clasei, orice program care foloseste clasa abstracta de date sa nu necesite schimbari suplimentare. Un mod de a asigura aceasta separare este:
1.Facem toate variabilele membru ale clasei membri private.
2.Facem toate operatiile de baza de care programatorul are nevoie functii membru public ale clasei (specificand modul de folosire a fiecarei functii membru specifice).
3.Facem orice functie help a clasei membru private.
Interfata unui ADT (definit ca o clasa in C++) consta in functiile membru publice impreuna cu comentariile care specifica modul de folosire a acestor functii membru publice. Implementarea unui ADT consta in membrii privati ai clasei si definitiile functiilor membre publice si private.
Deci clasa poate fi impartita in interfata si implementare.
Exercitii propuse spre implementare
1.Scrieti un program C++ in care definiti o clasa contbancar ce contine marea majoritate a operatiilor bancare.
De exemplu, o schita pentru definitia acestei clase poate fi:
class contbancar
;
2.Scrieti un program C++ in care se definiti o clasa Arbore ce contine operatiile fundamentale asupra arborilor binari (creare, parcurgere, stergere, numarare).
ATENTIE ! Radacina si numarul de noduri se recomanda a fi declarate private.
|