Limbajul C++ si oop abc-doar


sa fie redeclarata,atat pentru clasa abstracta cat si pentru clasa deri-



Yüklə 1,36 Mb.
səhifə5/18
tarix12.09.2018
ölçüsü1,36 Mb.
#81721
1   2   3   4   5   6   7   8   9   ...   18

sa fie redeclarata,atat pentru clasa abstracta cat si pentru clasa deri-

vata.Astfel,declararea unei functii virtuale pure "forteaza" redeclararea

functie respective la nivelul descendentilor (spre deosebire de functia

virtuala la care redeclararea este optionala).

EXEMPLU: (vezi si cplus18.cpp)

#include

#include

class obiect1

{

private: virtual void arie()=0;

}

void obiect1::arie(){};

class obiect2:public obiect1

{ public: int z;

obiect2() { z=5; };

void arie() { z=z*7; };

};

int main()

{ obiect2 data1;

data1.arie();

cout << "\n z are valoarea: \n";

cout << data1.z;

getch();

}

In exemplul de mai sus,obiect1 este o clasa abstracta.Daca se omite rede-

finirea clasei arie(),atunci si clasa derivata obiect2 va fi tot abstracta

si nu va putea fi instantializata.Acest mecanism se utilizeaza atunci

cand clasa abstracta defineste doar prototipul unei serii de clase deri-

vate.In fiecare clasa derivata,va trebui ca functia virtuala pura sa

fie redefinita.O clasa abstracta se poate utiliza si pentru a declara un

tip de data care nu poate sa fie utilizata in program.De exemplu,puteti

realiza o clasa destinata exclusiv pentru depanarea programului.La nevoie,

derivati o clasa din clasa abstracta,redefiniti functia virtuala pura si

apoi depanati programul (se poate utiliza pentru depanare automata).

Clasele abstracte contribuie si ele la fenomenul de polimorfism.

O clasa derivata poate avea mai multi ancestori,adica se formeaza prin

preluarea datelor de la mai multe clase de baza.In acest caz se vorbeste

despre mostenire multipla.Situatia reciproca,in care o clasa de baza este

mostenita de mai multe ori,nu se numeste mostenire multipla ci se numeste

"derivare multipla".


-27-

EXEMPLU: ( vezi si cplus19.cpp )

#include

#include

class obiect1

{

public: int a,b; float c;

obiect1() { a=15;b=22;c=3.14; };

};

class obiect2

{ public: int d,e; float f;

obiect2() { d=33; e=45; f=2.72; };

};

class obiect3: public obiect1,public obiect2

{ public: float h;

obiect3(){ h=((a+b)*c)/((d+e)*f); };

};

int main()

{

obiect3 data1;

cout << "\n h are valoarea: \n ";

cout << data1.h;

getch();

}

Se observa ca clasa obiect3 se formeaza prin derivarea claselor obiect1 si

obiect2.Cu alte cuvinte,mosteneste ambele clase,astfel incat poate sa

utilizeze in constructor toti membrii claselor ancestoare.

Este foarte important sa nu se confunde specificatorul de derivare

(public,protected,private) cu specificatorul de acces la membrii clasei.

Daca nu se utilizeaza nici un specificator,valoarea implicita va fi de

tip "private".Exemplu: class A: class B este identica cu:

class A: private class B

Daca omiteti specificatorul,clasa derivata va avea toti membrii mosteniti

de tip private (adica nu vor avea vizibilitate decat locala).

Mostenirea multipla,introduce si o alta notiune,denumita ambiguitate.

Astfel,daca in doua clase diferite se utilizeaza acelasi identificator,iar

cele doua clase vor fi clase de baza pentru o clasa derivata,atunci in

clasa derivata se vor mosteni doi membri diferiti cu acelasi identificator

Aceasta situatie nu genereaza o eroare de compilare,dar in momentul in

care se va apela unul dintre cei doi membri "dublati",se va genera o

eroare de executie (compilatorul nu stie la ce adresa sa faca referinta).

Pentru evitarea acestui gen de situatii,este bine sa utilizati pentru

toate datele din program identificatori cat mai discriminativi.In acest

manual,variabilele au fost denumite simplist,cu a,b,c,d...etc. pentru a

fi cat mai usor de urmarit.In aplicatiile reale,este bine sa utilizati

identificatori formati din 5-6 caractere (litere si cifre).Daca realizati

biblioteci de clase,incercati sa utilizati denumiri diferite pentru

fiecare tip de data,din fiecare clasa.Exista si o serie de conventii uti-

lizate pentru formarea denumirilor (Exemplu: notatia hungara).Daca doriti,

si puteti,este bine sa tineti cont si de aceste conventii.

Exista si situatii in care clasele sunt gata declarate in unitati se-

parate si nu se poate evita dublarea unui anumit identificator.Pentru


-28-

iesire din starea de "ambiguitate" se pot utiliza diferite artificii de

programare.Cea mai simpla solutie este sa utilizati o variabila globala

in care sa salvati valoarea membrului "dublat".

EXEMPLU: (vezi si cplus20.cpp )

#include

#include

float x,y;

class obiect1

{ public: int a,b; float c;

obiect() { a=15; b=22; c=3.14; };

};

class obiect2: int d,e; float c;

obiect2() { d=33; e=45; c=2.72; };

};

class obiect3: public obiect1,public obiect2

{ public: float h;

obiect3(){ h=((a+b)*x)/((d+e)*y); };

};

int main()

{

obiect1 numar;

x=numar.c;

obiect2 numar2;

y=numar2.c;

obiect3 data1;

cout << " \n h are valoarea: \n ";

cout << data1.h;

getch();

}

Se observa ca cele doua clase,obiect1 si obiect2 au cate un membru de tip

float declarat cu identificatorul "c".Fiecare clasa initializeaza acest

identificator cu alta valoare (3.14 si respectiv 2.72).Clasa obiect3

mosteneste ambii membri.In situatia in care se apeleaza membrul c din

clasa obiect3,intervine situatia de ambiguitate (se returneaza o eroare

de tip "Make failed").Pentru a evita aceasta situatie,am declarat doua

variabile globale de tip int,apoi am declarat obiecte din cele doua clase

si am salvat valorile celor doi membri.In clasa derivata,am utilizat cele

doua variabile globale in locul celor doi membri "dublati".Acest gen de

"artificiu tehnic" nu este recomandabil,dar poate reprezenta o solutie,in

situatii disperate.Solutia se poate utiliza si pentru a depana un program

"blocat" din cauza unei situatii de ambiguitate.

In rezumat,proprietatile claselor de obiecte sunt:

1.INCAPSULARE (datele au vizibilitate doar in interiorul clasei)

2.MOSTENIRE(o clasa derivata mosteneste membrii clasei ancestoare)

3.POLIMORFISM(o clasa poate genera obiecte diferite-redefineste functii)

4.AMBIGUITATE(o clasa poate accepta si membrii cu acelasi identificator)

5.ABSTRACTIZARE(o clasa cu o functie virtual pura nu are instante)

6.AUTOMATISM(prin constructor si destructor,aloca si dealoca memoria)

7.AUTONOMIE(o clasa permite operarea cu blocuri de date independente )

Pentru informatii mai detaliate despre clase si obiecte,consultati

literatura de specialitate.


-29-

MODULE,FILE,CONTEINERE,UNITATI,BIBLIOTECI
Limbajul C,cel care a stat la baza limbajului C++,a fost dezvoltat

prin expandarea unui algoritm intern utilizat de centralele telefonice.

Deoarece procesoarele centralei erau produse pe 16 biti,la fel a fost si

conceptia originala a acestui limbaj.Ca rezultat,C si urmasul sau C++ au

nevoie de structuri suplimentare pentru a comunica cu perifericele.

Limbajul C++ a fost dezvoltat intr-un moment in care majoritatea calcu-

latoarelor erau proiectate cu o arhitectura de 32 de biti,motiv pentru

care C++ a extins formatul de lucru la 32 de biti.

In epoca moderna,formatul de 32 de biti nu mai este satisfacator,astfel

a fost necesar sa se introduca diverse structuri software,care sa permita

lucrul cu formate mult mai mari.Aceste structuri nu au corespondent hard-

ware ci sunt un fel de tabele,sau matrici,in care datele se expandeaza

pana la formatul necesar.Cu ajutorul acestor structuri,procesoarele mo-

derne pot opera cu volume din ce in ce mai mari de date.Cu cat un procesor

este mai puternic (opereaza cu mai multa memorie/unitatea de timp) cu

atat are nevoie de un volum din ce in ce mai mare de date/unitatea de timp

pentru a putea fi exploatat rational( Exemplu: -un procesor de 3 Gbiti

utilizat doar pentru a citi texte editate in MS-DOS este subexploatat).

Pentru a putea satura cu date procesoarele rapide,se creaza structuri din

ce in ce mai complexe,in care se executa un numar din ce in ce mai mare

de operatii simultane.

Un prim pas in acest sens,il reprezinta clasele si obiectele sau bazele

de date formatate.Toate datele incluse intr-un obiect formeaza un mediu

de operare,izolat de cel al celorlalte obiecte.Restul variabilelor,decla-

rate extern se spune ca au vizibilitate globala.In cazul in care o apli-

catie lucreaza simultan cu mai multe file de program,toate datele decla-

rate in afara obiectelor se vor acumula intr-un spatiu comun,cu vizibili-

tate globala.Acest fapt,poate fi avantajos in unele situatii,dar poate

genera situatii de ambiguitate in situatiile in care exista date denumite

la fel in file diferite.Pentru a putea grupa toate aceste date fara a crea

conflicte de identificator (ambiguitati) se pot forma module de program,

in care spatiul comun din memoria de operare va fi subimpartit in unitati

distincte.Aceste unitati vor fi asemanatoare cu un "supraobiect",in care

se pot grupa: variabile,constante,functii si proceduri,obiecte si clase,

file header si unitati sau biblioteci,etc.

Acest gen de module se declara cu ajutorul cuvantului cheie "namespace"

urmat de un identificator care denumeste modulul respectiv.Elementele

incluse intr-un astfel de modul se declara la fel ca si elementele unei

clase si pot fi apelate cu ajutorul operatorului de scope (::),la fel ca

si membrii unui obiect.Practic,un astfel de modul este un superobiect in

care se grupeaza toate elementele pe care dorim sa le izolam de restul

spatiului din memoria de operare.Cu cat memoria de operare este mai mare,

cu atat este mai comod de lucrat cu astfel de module.In module se pot

include filele header si bibliotecile dorite,astfel incat sa formeze un

anumit "mediu de operare" in care se pot executa algoritmii doriti.

Aceasta forma de suprastructurare este evidemta (si obligatorie) la

versiunile mai noi de program (incepand cu Visual C++) si este conceputa

special pentru programele care opereaza cu interfete grafice sau cu

obiecte si structuri de date complexe (file de 4-8 sau chiar 32 MB ).


-30-

Prin acest mecanism,mediul de operare nu mai este unic,ci este frag-

mentat.Astfel,in momentul necesar se incarca modulul dorit,se executa

operatia necesara,dupa care se poate elibera memoria pentru un nou modul.

EXEMPLU: ( vezi si cplus21.cpp )

#include

#include

namespace modul1 { int nr=5; };

namespace modul2 { float nr= 3.55; };

int main()

{

cout << "\n Se executa primul modul din program ! ";

cout << modul1::nr;

cout << "\n Se executa al doilea modul din program ! ";

cout << modul2::nr;

getch();

}

Se observa ca in program pot coexista fara probleme doua variabile din

tipuri diferite,cu valori diferite si cu acelasi identificator (nr).

Acest gen de compartimentare este extrem de util atunci cand pentru a

proiecta o aplicatie avem nevoie de doua sau mai multe biblioteci de

functii,realizate de autori diferiti,dar care au utilizat aceeasi identi-

ficatori pentru date diferite.In aceasta situatie,filele se pot incarca

in module diferite si se pot apela in momentul in care sunt necesare:

EXEMPLU: ( vezi si cplus22.cpp )
namespace modul1 {

#include ;

#include ; };

int main()

{

int x=1;

for( x; x<10; x++ )

{

modul1::printf("text oarecare \n");

modul1::sleep(1);

}

}}

Pentru a incarca in memoria de operare toate datele dintr-un modul se va

utiliza formula: using namespace "numele modulului";

EXEMPLU: ( vezi si cplus23.cpp )

namespace modul1 {

#include ;

#include ; }

int main()

{

using namespace modul1;

printf("text oarecare \n");

getch();

}}

Observati avantajele acestui mecanism.Se incarca in memoria de operare

atat cat este necear pentru executie,sau tot modulul.


-31-

Cu ajutorul modulelor declarate prin "namespace" programatorul poate

gestiona mult mai usor spatiul de memorie.Exista si un astfel de modul

standardizat,denumit "namespace std",care este utilizat de catre biblio-

teca STL (Standard Template Library) si de multe alte file header sau

DLL,pentru descarca clasele definite.Pentru a putea avea acces la datele

definite in aceste unitati,trebuie sa includeti si comanda:

using namespace std;

Containerele sunt alt tip de "superclase" sau "superobiecte" si se

utilizeaza pentru a gestiona serii si colectii de obiecte.Acest tip de

structuri a fost definit anume pentru a putea efectua cat mai usor ope-

ratiile repetitive,asupra unor obiecte din acelasi tip,sau asupra unor

grupuri neomogene de date din tipuri diferite.Containerele sunt de fapt

clase template (parametrizate) si au toate in comun urmatoarele elemente:

un constructor implicit,un destructor si un operator de atribuire.

Containerele se pot imparti in trei tipuri fundamentale:

1.SECVENTIALE (double ended queue,list,vector )

2.ASOCIATIVE (map,multimap,set,multiset )

3.ADAPTOARE (priority-queues,queues,stack)

Fiecare tip de container detine si un set de functii specializate

(membrii clasei) prin care opereaza asupra datelor.Fiecare tip de con-

tainer detine o fila specializata in care este definita clasa si metodele

sale.Filele au acelasi nume ca si tipul de container: ,,

,,,,,.

Pentru a utiliza un astfel de conteiner,se incarca fila header corespunza-

toare,se declara "using namespace std;" apoi se declara tipul de data cu

o expresie de genul: conteiner identificator;

EXEMPLU: vector v1;

Pentru a apela membrii unui obiect,se utilizeaza un alt tip de data denu-

mit itaratori.Iteratorii au aceleasi proprietati ca si pointerii si se

pot apela si utiliza la fel ca si pointerii.Iteratorii pot fi de mai

multe tipuri:

1.input_iterator-(InIt)- citeste valori prin avansare.Poate fi incre-

mentat,comparat sau dereferit.Valoarea citita va fi de tipul

V=*X iar incrementarea se poate face prin V=*X ++

2.output_iterator-(OutIt)- scrie valori prin avansare pas cu pas.Poate

fi incrementat sau dereferit.Exemplu: *X++ = V

3.forward_iterator-(FwdIt)-citeste sau scrie valori prin incrementare.

Combina proprietatile celor doi iteratori de mai sus.

4.bidirectional_iterator-(BidIt)- citeste si scrie valori atat prin

incrementare cat si prin decrementare. V = *X ++ sau V = *X--

5.random_iterator-(RanIt) - are acces aleator atat pentru scriere cat

si pentru citire a valorilor,la orice adresa din conatiner.Este

cel mai versatil dintre iteratori si permite orice fel de operatie

aritmentica ce se poate efectua asupra pointerilor.Exemplu: poate

executa salturi de la orice membru,la orice alt membru

6.reverse_iterator - poate fi de tip random sau bidirectional dar se

deplaseaza doar in directia inversa a containerului.

Dupa cum le spune si numele,se utilizeaza mai ales pentru operatii

repetitive in cadrul unor bucle FOR...WHILE...DO etc.Orice iteroator

poate fi inlocuit de un obiect de tip pointer.Daca sunteti mai familia-

rizati cu pointerii,puteti utiliza pointeri in locul iteratorilor.


-32-

Conteinerele sunt destinate pentru operatii cu serii mari de date din

acelasi fel,sau din tipuri diferite.Containerul va avea acelasi tip de

data cu elementele pe care le contine.Exemplu: va fi de tip struct daca

contine structuri sau va fi de tip INT daca nu contine decat valori nu-

merice de tip INT.In functie de tipul de data si de numarul de obiecte

pe care le contine,durata pentru a accesa un anumit membru,sau pentru a

cauta un anumit membru in memorie depinde si de tipul containerului.

Astfel,tipul vector,care este de tip arie si lucreaza cu iterator de

tip random-acces are un timp de acces la membri constant (cel mai scurt),

dar timpul pentru sortare sau cautare a datelor depinde de numarul de

elemente din container.Prin contrast,containerele de tip stiva au atat

timpul de cautare si sortare cat si timpul de acces la membri dependent

de numarul de elemente din container.In cazul in care lucrati cu baze

de date care contin sute de mii de inregistrari,diferentele dintre tipu-

rile de conteinere devin din ce in ce mai pronuntate.Alegerea tipului de

container se va face atat in functie de tipul datelor arhivate cat si in

functie de numarul estimat de inregistrari,raportat la viteza de proce-

sare.In general,containerele se utilizeaza pentru a forma arhive mari de

date,iar tipul de container preferat este tipul vector.

Tipul vector

METODE (allocator_type,assign,at,back,begin,capacity,clear,const_iterator,

const_reference,const_reverse_iterator,difference_type,empty,end,

erase,front,get_allocator,insert,iterator,max_size,operator[],

pop_back,push_back,rbegin,reference,rend,reserve,resize,reverse_i-

terator,size,size_type,swap,value_type,vector)

Poate contine elemente cu lungime variabila,pe care le arhiveaza sub

forma de arii de date.Accesul la membri este de tip random si constant.

Accesul la membri este foarte rapid,deoarece nu trebuie sa parcurga toata

memoria ci acceseaza direct adresa,cu ajutorul pointerului.Cautarea unui

element prin comparatie,sau inserarea la o anumita adresa,este determinata

de dimensiunea conteinerului si de numarul de elemente parcurse pana la

identificarea adresei dorite.Alocarea si dealocarea spatiului pentru

fiecare element se face automat,printr-un obiect de alocare (alocator).

Daca un container de tip vector este realocat (s-a depasit capacitatea

maxima) atunci toti iteratorii si pointerii anteriori devin invalizi

(deoarece se schimba adresele de memorie ale elementelor).

Tipul vector este cel mai frecvent utilizat,deoarce permite facil

accesul la orice membru al containerului cu ajutorul unui iterator de

tip random-acces si a functiei at().Prin comparatie,containerele de tip

stiva functioneaza dupa principiul LIFO(Last In First Out) sau FIFO (First

In First Out).Pentru a putea avea acces la un anumit membru din stiva,

trebuie extrasi pe rand toti membri situati intre capatul stivei si cel

cautat,dupa care,dupa efectuarea operatiei dorite,toti membri extrasi

trebuiesc introdusi inapoi in stiva,in ordinea in care au fost extrasi.

Este usor de imaginat faptul ca o astfel de operatie poate sa dureze

destul de mult timp,mai ales atunci cand se lucreaza cu mii si zeci de

Yüklə 1,36 Mb.

Dostları ilə paylaş:
1   2   3   4   5   6   7   8   9   ...   18




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©muhaz.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin