Sunteți pe pagina 1din 172

PROGRAMAREA ORIENTATĂ

PE OBIECTE
CONCEPTE GENERALE
 Stilul de programare care îl numim în mod obişnuit
programare orientată pe obiecte POO a apărut relativ recent
în istoria limbajelor de programare.
 Acesta este un stil particular şi foarte comod pentru
numeroase situaţii.
 El a fost creat pentru a depăşii limitele programării
structurate bazate în principal pe utilizarea largă a
procedurilor, funcţiilor, a pointerilor sau a tipurilor de date
mai mult sau mai puţin evoluate.
 Programarea structurată foarte practică mai ales pentru
sisteme de programe mici sau aplicaţii reduse negrafice, este
depăşită în ceea ce priveşte aplicaţiile mari cu elemente
grafice unde mult mai indicată este programarea orientată pe
obiecte.
 Programarea orientată pe obiecte utilizează elementele
programării dar se bazează pe orientarea pe obiecte.
CONCEPTE GENERALE
 Orientarea pe obiecte reprezintă organizarea de resurse soft
într-o colecţie de obiecte, distincte şi discrete, care înglobează
atât structuri de date cât şi funcţiile de prelucrare ale acestora.
 Această organizare este o extindere a programării tradiţionale,
în care structurile de date şi funcţiile de prelucrare sunt doar
lejer conectate.
 Identificarea obiectelor pentru o aplicaţie dată se face prin
maparea conceptelor de bază vehiculate de aplicaţia
respectivă.
 Un obiect se defineşte ca fiind un concept, o abstractizare şi
înţeles precis din punct de vedere al aplicaţiei de rezolvat.
Obiectele permit următoarele avantaje:
 oferă o mai bună înţelegere a problemei de rezolvat;
 oferă un "schelet" de pornire pentru implementare.
 O clasă de obiecte grupează un număr oarecare de obiecte cu
proprietăţi similare. Această similitudine se referă atât la
descriere (date sau atribute), cât şi la comportare (funcţii sau
metode), dar în acelaşi timp şi la relaţiile posibile cu alte
obiecte.
CONCEPTE GENERALE
 Diferenţele dintre obiectele de aceeaşi clasă se materializează în
diferenţe între valorile datelor de descriere.
 Totodată, pentru fiecare obiect este specificat tipul clasei din
care provine. Clasa este elementul de programare care ne
permite transcrierea cât mai bună a unui concept din viaţa
concretă într-un limbaj de programare. Ea permite definirea atât a
datelor relativ la o entitate cât şi a acţiunilor asociate (funcţii sau
metode).
 Implementare software a unui concept cum ar fi un sistem de
calcul se poate printr-o clasă. Această clasă va fi caracterizată de
anumite date (atribute) şi anumite acţiuni (metode, funcţii).
Această clasă va conţine numai elementele caracteristice, putând
definii pe baza ei şi concepte particulare cum ar fi laptop şi PDA.
Reprezentarea acestor clase este dată în figura 1.
 Atributele reprezintă caracteristici unice în cadrul unei clase de
obiecte. La nivel de obiect fiecare atribut primeşte o anumită
valoare care se poate modifica pe parcursul duratei de viaţă a
obiectului respectiv. Două sau mai multe obiecte pot avea valori
identice sau valori diferite pentru un acelaşi atribut.
CONCEPTE GENERALE
CONCEPTE GENERALE
 Metodele sau operaţiile sunt funcţii de prelucrare care se aplică
obiectelor de o anumită clasă. Toate obiectele unei clase admit
acelaşi set de metode, metode care la rândul lor pot să
primească un număr oarecare de parametri suplimentari.
Identificarea unei metode se face atât prin nume, cât şi prin
semnătură.
 Pentru ca unui obiect să i se poată aplica metode - funcţii de
prelucrare - acel obiect trebuie să fie creat (definit). Definirea
unui obiect poartă numele de instanţiere. După ce un obiect şi-a
îndeplinit misiunea el este eliminat. Durata de viaţă a obiectelor
depinde de la obiect la obiect şi de la aplicaţie la aplicaţie.
Abstractizare şi modelare
 In orice domeniu de activitate umană, abordarea unui proiect porneşte
de la construirea unui model cu scopul unei mai bune înţelegeri a
problemei de rezolvat.
 Prin abstractizare se izolează aspectele esenţiale de cele neesenţiale,
bineînţeles în funcţie de perspectiva de abordare a problemei de
rezolvat.
 În consecinţă, pentru o aceeaşi problemă, pot exista mai multe
abstractizări, deci mai multe modele. Nu putem vorbi de modele corecte
şi modele incorecte, ci de modele adecvate şi modele inadecvate.
 Prin esenţă, o abstractizare este o reprezentare incompletă a realităţii şi
tocmai aceasta dă valoare modelului corespunzător.
 La fel ca şi în abordarea structurată, în abordarea orientată pe obiecte,
procesul dezvoltării unei resurse soft, porneşte de la un model.
 Aceasta este o abstractizare menită a face posibilă etapa următoare de
implementare. În domeniul ingineriei soft, programarea structurată a
făcut un mare pas înainte introducând necesitatea abordării unei
aplicaţii din trei perspective diferite, rezultând astfel trei modele diferite.
În abordare structurată, cele trei modele, pe care le numim şi sub-
modele sunt:
 modelul static;
 modelul dinamic;
 modelul funcţional.
Abstractizare şi modelare
 În modelarea orientată pe obiecte apar două modificări esenţiale:
 modelul care captează aspectele statice ale aplicaţiei devine
modelul obiectual
 accentul cade pe acest model şi nu pe cel funcţional.
 În multe aplicaţii mai simple modelele dinamic şi funcţional se
construiesc în primul rând pentru o mai bună înţelegere a
modelului obiectual.
Modelul obiectual
 Pune în evidenţă aspectele statice ale aplicaţiei, dar nu prin
identificarea unor sub-ansamble, mai mult sau mai puţin arbitrare,
ci prin identificarea conceptelor cu care operează aplicaţia.
 Acestor concepte li se asociază obiecte, iar modelul obiectual
conţine o sinteză a acestor obiecte, a relaţiilor dintre ele, precum
şi a proprietăţilor lor.
 Construirea unui sistem în jurul obiectelor cu care operează,
surprinde mult mai bine realitatea decât o abordare care porneşte
de Ia aspecte funcţionale.
Abstractizare şi modelare
Modelul dinamic
 Sugerează succesiunea în timp a creării obiectelor, pe măsura
necesităţii existenţei lor, precum şi distrugerea acestora după ce şi-au
îndeplinit misiunea.
 Crearea unui obiect mai poartă şi numele de instanţiere.
 Pentru obiectele implementate Ia nivelul unui nucleu, deciziile de
instanţiere şi distrugere se iau la nivelul clientului acelui nucleu.
Totodată, modelul dinamic indică ordinea de invocare a a metodelor,
pentru fiecare obiect instanţiat.

Modelul funcţional
 Descrie aspectele comportamentale ale obiectelor, indiferent de
ordinea de instanţiere a obiectelor şi indiferent de ordinea de invocare a
acestor aspecte.
 Fiecărui aspect comportamental îi corespunde o funcţie, numită şi
metodă. Modelul funcţional, descrie funcţionarea în mare a acestor
metode, rezumându-se la ilustrarea relaţiilor între parametrii de intrare
şi valorile de ieşire ale fiecărei metode în parte, fără însă a oferi detalii
legate de implementarea algoritmilor corespunzători.
Metodologii orientate pe
obiecte
 Există la ora actuală mai multe metodologii orientate pe obiecte pentru
analiza, proiectarea şi implementarea de resurse soft.
 Una din metodologii este OMT - Object Modeling Technique .
 Aceasta presupune o etapizare a etapelor de dezvoltare, precum şi un
sistem grafic de reprezentare a obiectelor şi a relaţiilor dintre acestea.
 Metodologia OMT se bazează pe construirea unui model tridimensional
al aplicaţiei, pe baza căruia se adaugă gradat detaliile de implementare
în ultima fază a procesului de dezvoltare.
 În mare, metodologia OMT este ilustrată în figura 2.

 Fig.1. Esenţa abordării OMT


Metodologia OMT
 Dezvoltarea unei aplicaţii în metodologia OMT presupune
parcurgerea în mod repetitiv, până la obţinerea unui produs
acceptabil, a următoarelor etape:
Analiza
 Această etapă porneşte de la specificaţiile problemei de rezolvat.
Scopul acestei etape constă într-o înţelegere profundă a
domeniului aplicaţiei, precum şi a cerinţelor concrete ale
aplicaţiei.
 Rezultatul etapei de analiză este modelul aplicaţiei, format din
cele trei sub-modele:
 modelul obiectual - cel mai important;
 modelul dinamic;
 modelul funcţional.
 Un model corect trebuie să poată fi uşor înţeles de specialiştii din
domeniul aplicaţiei, fără cunoştinţe de programare.
Metodologia OMT
Proiectarea sistem
 In această etapă se iau deciziile de nivel înalt privind arhitectura aplicaţiei,
în ansamblul ei.
 Acum se decid subansamblele mari ale aplicaţiei, precum şi resursele
platformei gazdă ce trebuie disponibilizate şi gestionate.
 În ce priveşte componentele aplicaţiei, acum se aleg modalităţile lor de
implementare - hard sau soft -, protocoalele de comunicaţie între nivelele
ogice adiacente şi se stabilesc "contractele de cooperare" între obiectele
ce interacţionează de pe nivele diferite.
 In aplicaţii mari, se recomandă ca fiecărui nivel să i se construiască un
model propriu. în ce priveşte resursele maşinii, acum se stabilesc
strategiile de alocare şi gestiune a memoriei dinamice şi a altor resurse
sistem identificate prin handle proprii.
Proiectarea obiectelor
 Pornind de la modelul obiectual şi de la deciziile proiectării sistem, în
această etapă se adaugă o descriere mai amănunţită a claselor de
obiecte. Astfel, acum se specifică numele atributelor şi tipurile lor, precum
şi numele metodelor şi semnăturile acestora. Toate aceste nume trebuie
alese cu grijă pentru a se mapa cât mai bine domeniului aplicaţiei.
Metodologia OMT
Implementarea
 În sfârşit, în aceasta etapă se trece la dezvoltarea claselor de
obiecte şi a relaţiilor dintre acestea.
 Această implementare se materializează în module soft, sau
dacă este cazul, chiar şi în module hard.
 Partea cea mai semnificativă de efort este dirijată spre
codificarea algoritmilor corespunzători metodelor.
 Această etapă se doreşte a fi simplă şi oarecum mecanică,
deoarece toate deciziile majore au fost deja luate în etapele
precedente.
 La acest efort pot fi cooptaţi şi programatori care nu mai au
viziunea de ansamblu a aplicaţiei. Oricum, regulile de bază de
tehnică şi stil trebuiesc în continuare respectate cu stricteţe.
 Tot în această etapă se poate lua decizia introducerii unor
obiecte nerelevante din punct de vedere al aplicaţiei, dar
indispensabile etapei de implementare, cum ar fi: liste înlănţuite,
arbori şi altele.
Metodologia OMT
 Sigur, întregul proces prezentat trebuie privit ca şi
un ciclu interativ. Totodată, efortul necesar testării şi
validării, pas cu pas, a produsului nu trebuie deloc
neglijat, chiar dacă abordarea orientată pe obiecte
duce, printre altele, şi la minimizarea acestei etape.
 Fiecare metodologie de proiectare orientată pe
obiecte, sugerează un set de reprezentări grafice,
folosite pentru reprezentarea modelelor obiectuale.
 Acestea trebuie să ofere o imagine clară şi intuitivă
a claselor şi obiectelor, precum şi a relaţiilor dintre
clase, stabilite în faza de modelare.
Ierarhizarea unei aplicaţii pe
nivele
 Tehnica structurării unei aplicaţii pe nivele ierarhice, care comunică
între ele prin mecanism CLIENT-SERVER este perfect utilizabilă şi în
abordare orientată pe obiecte.
 Astfel, fiecare nivel implementează grupe de clase, numite şi ierarhii de
clase, grupând concepte care împreună formează un subansamblu de
sine stătător.
 In astfel de situaţii, fiecare nivel poate fi modelat şi implementat
separat.
 În cazul în care resursele înglobate în aceste clase sunt suficient de
generale ele pot fi plasate în biblioteci, cu scopul refolosirii lor şi de
către alte aplicaţii.
 Comunicarea între nivele ierarhice adiacente realizate obiectual,
presupune doua procese distincte:
 clientul transmite server-ului "ordine" pentru instariţiere de obiecte nucleu;
 clientul transmite serverului "ordine" de apel pentru metodele oferite de
obiectele din nucleu ce au fost instanţiate.

 Rolul subsistemelor de acest fel constă în simplificarea abordării unui


proiect prin metoda "divide et impera".
Caracteristicile unui limbaj
orientat pe obiect
Termenii generali ce descriu cel mai bine caracteristicile
esenţiale ale unui limbaj orientat pe obiect sunt:

 Abstracţia – defineşte caracteristicile esenţiale unui obiect


văzut din exterior. Selectarea obiectelor abstracte sa a
claselor este un punct important în realizarea unui program.
 Încapsularea – dă posibilitatea utilizării unitare a codului şi a
datelor. Unităţile de încapsulare în C++ sunt class şi struct.
Limbajul C++ folseşte mai mult class decât struct, singura
diferenţă fiind că în tipul de date class pot exista date şi
metode ianccesibile din exterior.
 Moştenirea – permite definirea unor noi clase pornind de la
cele existente. Marele avantaj al moştenirii este obţinerea prin
derivare a datelor şi metodelor în clasa creată. Caracteristicile
moştenite de clasa creată pot fi ajustate după necesităţi. Este
posibil de asemenea derivarea unei clase din mai multe clase
de bază (moştenire multiplă).
Caracteristicile unui limbaj
orientat pe obiect
Prin moştenire se pot obţine obiecte specializate pe baza unor
obiecte mai generale. Avantajul apare când, pentru a crea un
obiect, nu mai trebuie să pornim de la zero, ci putem deriva
obiectul dintr-o clasă care are proprietăţi comune cu obiectul
care dorim să-l obţinem.
 Polimorfismul – posibilitatea ca fiecare obiect să răspundă în
felul său la o metodă cu acelaşi nume.
 Modularitatea – posibilitatea grupării claselor în module.

Un mediu creat pentru realizarea aplicaţiilor Windows este Visual


C++, fiind cel mai folosit compilator de C++ la ora actuală. El se
bazează pe biblioteca de clase MFC (Microsoft Foundation
Classes) ce permite crearea rapidă a unor cadre de aplicaţii pe
baza conceptului de document-view sau de aplicaţie bazată pe
un dialog.
Clase de obiecte C++
 O clasă reprezintă un tip de date definit de programator. Ea permite
reprezentarea datelor şi metodelor de manipulare a acestor date
într-o grupare simplă şi ordonată .
 Dacă se foloseşte o bibliotecă de clase existentă cum ar fi MFC,
atunci programatorul poate defini direct obiecte de tipul acelei clase.
Definitia unei clase presupune:
 a) declararea clasei care consta in specificarea datelor si
prototipurilor funcțiilor componente (inclusiv functii inline) intr-un
fișier antet care are identificatorul încheiat, de obicei, cu .h;
 b) implementarea clasei ce consta in definițiile funcțiilor
componente care indica comportamentul tipului de date reprezentat
de clasa respectiva. Daca funcțiile prezente in declararea clasei
sunt corect adecvate scopului propus, atunci utilizatorul nu mai are
nevoie de definirea lor si implementarea se poate face intr-un fisier
separat (pentru unele compilatoare identificatorul unui astfel de fisier
se incheie cu .cpp).
Clase de obiecte C++
 Forma generală a declaraţiei unui tip class este similară cu a tipurilor struct
din C:
 class <nume_clasa> <:lista_clase_baza>
 {<lista_membri>
 } <lista_var>;
 nume_clasa este numele tipului clasă declarat şi 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_membrii reprezintă secvenţa de declaraţii ale membrilor clasei.
Lista conţine declaraţii de date membre sau definiţii de funcţii membre .
Datele membre pot fi de orice tip, mai puţin tipul de clasă declarat.
 lista_var este lista numerelor variabilelor de tip nume_clasa.
 Deşi nume_clasă şi lista_var apar opţionale, ca şi în cazul tipurilor de
structură din C, cel puţin una dintre ele trebuie să existe.
 De regulă nume_clasa nu se omite, pentru a pute declara ulterior obiecte de
acest tip.
Clase de obiecte C++
 Domeniul unui identificator de clasa este local si incepe din
momentul declararii clasei pana la finalul blocului respectiv. Daca
o clasa este declarata in afara oricarei functii sau clase,
domeniul sau este intregul fisier.
 Domeniul membrilor unei clase coincide cu domeniu clasei
respective.
 Daca prototipurile functiilor membru se afla in declaratia
clasei respective, definitiile lor (cu exceptia celor inline) sunt
date in exteriorul declaratiei clasei, folosind operatorul de
specificare de domeniu "::".
 Acesta indica faptul ca domeniul functiei respective este acelasi
cu domeniul clasei din care face parte.
 Sintaxa definitiei unei functii membru a unei clase:
 tip id_clasa :: id_func_membru(...){...};
Specificatori de acces
 Tipul de date (class) permite declararea unor date protejate sau
private, aceste date nefiind vizibile în afara clasei, nici măcar de
către obiectele de tipul respectiv.
 Controlul accesului la componentele unei clase poate fi realizat
utilizând specificatorii:
 public – membrul poate fi accesat de orice funcţie din domeniul
declaraţiei clasei;
 private – membrul este accesibil numai de funcţii din interiorul
clasei sau de către funcţii prietene (friend) ale clasei;
 protected – similar cu private dar accesul se extinde pentru
funcţiile membre şi prietene derivate din clasa respectivă.
 O funcţie membră a unei clase are acces la toate datele membre din
clasa respectivă, indiferent de specificatorul de acces.
 Dacă nu specificăm tipul de acces, membrii vor fi private în mod
implicit.
 Sintaxa de utilizare a unui specificator de acces este:
 spec_de_acces:
Specificatori de acces
 O clasa contine:
 - o parte protejata/privata care asigura implementarea clasei;
 - o parte publica care reprezinta interfata clasei respective cu
celelalte secțiuni din program.
 Interfata la o clasa se refera la informația pe care utilizatorul trebuie
sa o cunoasca pentru a se putea folosi de facilitatile oferite de acea
clasa.
 De aceea trebuie cunoscut:
 -identificatorii functiilor membru publice ale clasei;
 -prototipurile functiilor membru;
 -scopul functiilor membru.
 Protectia membrilor intr-o clasa este indicata cu ajutorul unor
specificatori de acces/ modificatori de protectie.
Obiecte C++
 Un obiect reprezinta un element (instantiere) al clasei respective.
Pentru a crea un obiect in C++ trebuie definita forma sa generala
(trebuie să definim clasa folosind cuvantul cheie class).
 În C++, un obiect reprezintă o variabilă definită ca fiind de tipul
clasei din care face parte.
 Declararea obiectelor se poate realiza o dată cu definiția clasei după
acoladă, reprezentând lista de variabile asociată clasei sau separat.
 La declararea obiectelor este suficient să se specifice numele clasei
fără cuvântul cheie class.
 nume_clasă nume_obiect;
 Pentru un obiect se poate apela o anumită funcție. Acest lucru se
poate realiza astfel:
 nume_obiect.nume_funcție(par1, par2 ..);
Obiecte C++
 In C++, obiectele unei clase se pot manipula folosind functiile
membru si operatorii definiti pentru acea clasa.
 O astfel de functie are, de regula, unul sau mai multi parametri si
returneaza o valoare.

 Mecanismul de transmitere prin valoare consta in primirea de


catre functie a parametrilor actuali intr-o stiva (stack) care este o
structura de date de tip LIFO. Functia preia parametrii din stiva si ii
folosește in blocul sau fara a avea acces la locatiile lor de memorie.
 Ea folosește doar copii locale ale acestor parametrii care vor fi
eliminate din stiva la revenirea din functie. Prin urmare, printr-un
astfel de mecanism, functia respectiva nu-si poate modifica
parametrii cu care a fost apelata.
Clase şi obiecte C++
 Exemplu:
 #include <iostream>
 using namespace std;
 void suma (int x){x+=100; }
 void main(){
 int u=200;
 suma(u);//apel functie
 cout << "u=" << u<<"\n";
 system("pause");
 }
 Se va observa ca se afiseaza valoarea 200 (valoarea transmisa
parametrului formal al functiei) si nu 300 cat ar trebui dupa executia
functiei.
 Problema se poate rezolva folosind parametrii tip pointer.
Clase şi obiecte C++
 Exemplu:
 #include <iostream>
 using namespace std;
 void suma (int *x){ *x+=100;}
 void main(){
 int u=200;
 suma(&u);//apel functie
 cout << "u=" << u<<"\n";
 system("pause");
 }
 In acest caz se va afisa pentru u valoarea 300.
Obiecte C++
 In C++, s-a aratat ca se utilizeaza conceptul de referinta, ce poate fi
utilizat la fel ca obiectul referit. Referinta reprezinta adresa
obiectului respectiv deosebindu-se de pointer prin faptul ca ea nu
este o variabila reala. Ea este initializata in momentul definirii si
valoarea ei nu se poate modifica ulterior.
 Transmiterea unei referinte la un obiect evita efectuarea de copii
inutile si permite o implementare eficienta.
 Referinta se foloseste in transmiterea de parametri, daca:
 a) functia trebuie sa modifice parametrii actuali de la apel;

 b) functia nu modifica parametrii actuali, dar trebuie evitata


copierea obiectelor in stiva (economie de memorie). In acest
ultim caz se va folosi specificatorul const pentru a indica faptul
ca parametrul transmis prin referinta nu va fi modificat de functia
respectiva.
 Exemplu: definire clasă student.
Clase şi obiecte C++
 class Student
 {
 public:
 char Nume[100];
 char Prenume[100];
 int Varsta;
 protected:
 char Facultatea[30];
 char Sectia[30];
 int anul;
 int nr_restante;
 private:
 long media_ultim_an;
 double bursa;
 public:
 Student();
 long aflaMedia();
 void schimbaMedia(long MediaNoua);
 private:
 int Afla_nr_restante();
 };
Utilizarea operatorului :: in
definirea variabilelor globale
 Intr-o declaratie de clasa se poate modifica accesul ori de cate
ori este necesar.
 Tipurile struct si union reprezinta cazuri particulare de clase
care se distanteaza de conceptul OOP.
 O diferenta esentiala intre class si struct consta in faptul ca
datele membru in struct, in mod implicit, sunt publice, iar
membrii din class, in mod implicit, sunt privati.
 Operatorul „::“ mai este numit si operator de scop. Scopul si
accesibilitatea unui identificator se pun in evidenta cu ajutorul
acestui operator.
 Sintaxa:
 ::variabila operator;
Utilizarea operatorului :: in
definirea variabilelor globale
Exemplu:
 #include<iostream>
 #include<conio.h>
 using namespace std;
 int i=100; // declararea si initializarea lui i ca variabila globala
 void f1(){
 int i=9; // declararea lui i ca variabila locala /in functia f1
 i++; // incrementarea variabilei locale i
 cout<<"i="<<i;
 cout<<"\n";}
 void f2(){
 int i=5; // declararea lui i ca variabila locala in functia f2
 ::i++; // incrementarea lui i global desi este „mascat“ de declararea //unui i local
 int k=::i;
 cout<<"k="<<k;}
 void main()
 {f1();
 f2();
 getch();}
Utilizarea operatorului :: in
definirea variabilelor globale
 Se observa ca in C++, variabilele locale pot fi create in orice
pozitie din cod. Se pot folosi, cand este util, nume de functii
standard de biblioteca (read, write, fopen etc.) drept nume de
functii utilizator, urmand a fi reutilizate intr-o anumita maniera.
 Exemplu:
 //definirea functiei utilizator
 int A::fopen(char*pn="fis.dat", char*pa="rt")
 {
 //……………………………..
 ::fopen(pn, pa);// apel la functie de biblioteca
 …………………
 }
Utilizarea operatorului :: in definirea
variabilelor membru şi globale
 Din urmatorul exemplu reiese cum se poate utiliza operatorul "::" in cadrul unei
functii membru ce opereaza cu variabile membru si cu variabile globale.
 Exemplu:
 #include<iostream.>
 using namespace std;
 #include<conio.h>
 int v=20; // declarare variabila globala cu domeniul de tip fisier care incepe din
acest punct
 class B{
 int v; // declararea unei variabile membru /privata a clasei
 public:
 void init(int x){v=x;}
 void f(); //declarare functie membru (prototip)
 };
 void B::f(){ //definitia functiei membru
 int u=v++; //postincrementarea variabilei membru v
 cout<<"u="<<v;
 ::v++; //postincrementarea variabilei globale v
 int r =::v;
 cout<<"\n";
 cout<<"r="<<r; }
Utilizarea operatorului :: in definirea
variabilelor membru şi globale
 void main(){
 B c;
 c.init(10);
 c.f(); }
 Un membru al unei clase poate fi definit prin construcţia
 nume_clasa::membru
 Una din motivatiile prezentei identificatorului clasei in fata
operatorului "::" este impusa si de faptul ca trebuie sa se distinga
functiile cu acelasi identificator care apartin la clase diferite.
 In plus, se permite operarea directa cu variabila membru, fara
precizari suplimentare cu privire la identitatea sa. Mai exact, toate
variabilele folosite intr-o functie membru a unei clase si
nedeclarate in ea, se presupun, in mod implicit, ca fiind membru
ale acelei clase. Daca prin procesul de compilare nu se stabileste
aceasta, se va trece la identificarea lor ca variabile globale.
Clase derivate
 Prin mecanismul de moştenire sau derivare se pot crea clase noi pe
baza unor clase existente.
 Clasa din care se moşteneşte se numeşte clasă de bază, clasa care
moşteneşte se numeşte clasă derivată.
 Clasa derivată moşteneşte toţi membrii clasei de bază, dar nu va putea
avea acces niciodată la membrii declaraţi private în clasa de bază.
Practic, datele şi metodele se transferă de la clasa de bază la clasa
derivată beneficiind deci de proprietăţi şi de un comportament
asemănătoare cu cele ale clasei de bază.
 Există şi conceptul de moştenire multiplă – o clasă derivată poate să
moştenească de la mai multe clase de bază.
 Exemplu:
 class A
 {
 private:
 int i2;
 };
Clase derivate
 class B: public A
 {
 public:
 int i3;
 };
 Membrul i2 din clasa A, fiind declarat private,
nu este vizibil în clasa derivată B, indiferent
de mofificatorul de acces.
Funcţii membre inline
 Funcţiile mici, cu puţine instrucţiuni, apelate frecvent se compilează
ineficient (se rezervă spaţiu în stivă pentru parametrii şi rezultat, se
efectuează salt la funcţie şi apoi salt pentru revenire). Mult mai eficientă
ar fi expandarea apelului funcţiei prin corpul ei, ca în macroinstrucţiuni. \
 Apelul unei funcţii declarate inline este înlocuit la compilare prin corpul
funcţiei (apel realizat prin expandare).
 O funcţie inline nu trebuie să conţină bucle.
 Funcţiile membre definite în interiorul clasei sunt în mod implicit inline,
dar este posibil ca şi funcţii definite în afara clasei să fie declarate
explicit inline (expandate).
 class Data{
 public:
 int zi();
 ...
 private:
 int a, l, z;
 };
 // functie declarata in mod explicit inline inafara clasei
 inline int Data::zi(){return z;};
Funcţii membre inline
 // definirea clasei – fisierul punct.h
 class punct{
 private:
 double x0, y0; // date membre
 public:
 inline void init(double x=0, double y=0); //nu era necesara
 inline void setx(double x=0){ x0=x; }; //declararea explicita
 inline void sety(double y=0){ y0=y; }; //erau considerate inline
 double getx(){ return x0; }; // este implicit inline
 double gety(){ return y0; };
 void afisare();
 };
Funcţii membre inline
 // fisierul punct.cpp
 #include <iostream.>
 using namespace std;
 #include <iomanip.h>
 //desi este definita in afara clasei este inline (apel expandat)
 inline void punct::init(double x, double y)
 {
 x0 = x;
 y0 = y;
 };
 //nu este inline (apel=salt cu revenire)
 void punct::afisare(){
 long f = ios::fixed;
 cout << setiosflags(f) << setw(6) << setprecision(2);
 cout << “(“ << x0 << “,” << y0 << “)” << endl;
 };
 };
Constructori şi destructori
 Iniţializarea asigurată de funcţia membru init() este lăsată la latitudinea
utilizatorului. Este de preferat o iniţializare mai sigură a obiectului, care să se
facă în mod implicit la declararea obiectului.
 Iniţializarea obiectelor se face prin intermediul unor funcţii speciale numite
constructori.
 Folosirea funcţiei initD() pentru iniţializarea obiectelor clasei Data este nesigură
– putem uita să facem iniţializarea sau să facem o iniţializare repetată.
 Un obiect poate fi declarat neiniţializat sau iniţializat. Exemple:
 Complex z; // obiect neiniţializat
 Complex z1(-1.5, 2.); // obiect initializat
 O soluţie sigură o reprezină declararea unei funcţii având scopul explicit de
iniţializare a obiectelor. O asemenea funcţie poartă numele de constructor.
 Constructorul este o funcţie publică, care iniţializează datele membre, având
acelaşi nume cu numele clasei şi care nu întoarce nici o valoare.
 class Data{
 ...
 public:
 Data(int, int, int); // constructorul
 ...
 };
Constructori şi destructori
 Considerăm definiţia clasei Complex:
 #include <stdio.h>
 class Complex{
 private:
 double re, im;
 public:
 void scrie();
 };
 void Complex::scrie(){
 printf(“(%4.1lf , %4.1lf)\n”, re, im);
 };
 void main(){
 Complex z; //obiect neinitializat
 z.scrie();
 }
 Programul este corect din punct de vedere sintactic. Lipsa unui constructor
definit de utilizator, care să iniţializeze obiectele este remediată de compilator.
Astfel, pentru clasa C, dacă nu se defineşte în mod explicit un constructor,
compilatorul generează în mod implicit constructorul: C::C(){}, care crează
datele membre ale clasei. Acest constructor implicit nu face nici o iniţializare a
datelor membre, aşa că se vor afişa nişte valori foarte mari, reprezentând
conţinutul memoriei neiniţializate.
Constructori şi destructori
 Pentru a evita aceasta, se recomandă programatorului să îşi definească un
constructor implicit (fără parametri), care să iniţializeze datele membre (în
exemplul nostru iniţializarea la 0 pentru partea reală şi cea imaginară a
obiectului număr complex). Constructorul implicit acţionează asupra obiectelor
neiniţializate.
 Clasa Complex, prevăzută cu acest constructor este:
 class Complex{
 private:
 double re, im;
 public:
 Complex(){re=0.; im=0.};
 void scrie();
 };
 Se preferă scrierea constructorului, folosind o listă de iniţializare, conform
sintaxei:
 Complex() : re(0.), im(0.){};
 De această dată, în urma execuţiei se va afişa ( 0.0 , 0.0).
 Dacă se declară obiecte iniţializate, iniţializarea acestora trebuie făcută de către
un constructor de iniţializare, care trebuie definit în mod explicit de către
utilizator.
Constructori şi destructori
 Pentru clasa Complex, un constructor de iniţializare, are forma:
 class Complex{
 private:
 double re, im;
 public:
 Complex(double x, double y) : re(x), im(y){};
 void scrie();
 };
 void main(){
 Complex z1(-1., 2.); //obiect initializat
 Complex z2; //obiect neinitializat
 ...
 }
 Dacă se declară un constructor de iniţializare, compilatorul nu mai generează un
constructor implicit, astfel că pentru obiectele neiniţializate (în exemplul de mai sus z2)şi
tablourile de obiecte se va genera eroare. Putem defini deci doi constructori (şi în general
oricâţi, având în mod evident semnături diferite), unul implicit şi celălalt de iniţializare:
 Complex() : re(0.), im(0.){}; //constructor implicit
 Complex(double x, double y):re(x),im(y){}; //ctor de initializare
Constructori şi destructori
 Clasa de mai jos defineşte mai mulţi constructori:
 class Data{
 int a, l, z;
 public:
 Data(int, int, int); // a, l, z
 Data(int, int); // l, z
 Data(int); // z
 Data(); // implicit cu data curenta
 Data(const char*); // data reprezentata de sir
 ...
 };
 Se preferă înglobarea constructorului implicit în constructorul de
iniţializare, folosind parametri cu valori implicite. Constructorul de
iniţializare poate fi folosit drept constructor implicit, dacă toţi parametrii
sunt prevăzuţi cu valori implicite.
 Complex(double x=0., double y=0.):re(x),im(y){};
Constructori şi destructori
 Folosirea argumentelor implicite poate reduce numărul de constructori.
 În exemplul următor, în lipsa argumentelor, constructorul asigură
iniţializarea datei cu valori preluate din obiectul static azi.
 class Data{
 int a, l, z;
 public:
 Data(int aa=0, int ll=0, int zz=0);
 ...
 };
 Data::Data(int aa, int ll, int zz){
 a = aa? aa : azi.a;
 l = ll? Ll : azi.l;
 z = zz? zz : azi.z;
 };
 Utilizatorul este obligat să-şi definească proprii constructori numai în
situaţiile în care obiectul alocă dinamic spaţiu în memorie.
Constructori şi destructori
 Nu pot fi definiţi mai mulţi constructori impliciţi .(fiind supraîncărcaţi, diferiţii
constructori trebuie să aibă semnături diferite).
 Un constructor cu un singur argument defineşte o funcţie pentru conversia
de tip de la tipul argumentului la tipul clasei. Deci vom putea iniţializa un obiect
printr-o atribuire de forma:
 clasa ob=argument;
 Atriburea de mai sus poate fi considerată ca o conversie implicită. Pentru a o
dezactiva, constructorul cu un argument trebuie să fie precedat de cuvântul
cheie explicit.
 Operaţia de eliminare a unui obiect din memorie este realizată de o funcţie
destructor, având acelaşi nume cu al clasei, fără argumente, care nu întoarce
nici o valoare. Pentru a face distincţie faţă de constructor, numele destructorului
începe cu ~.
 Un destructor pentru un obiect este apelat în mod implicit la ieşirea din
domeniul de definiţie al obiectului sau la sfârşitul programului, pentru obiectele
globale sau statice. Sunt foarte rare situaţiile în care programatorul apelează
explicit un destructor. Dacă o clasă nu are definit destructor, compilatorul
generează un destructor implicit.
Constructori şi destructori
 Programatorul nu apelează în mod explicit constructorii sau
destructorul. Constructorii se apelează în mod implicit la declararea
obiectelor. Destructorul este apelat implicit la ieşirea din blocul în care
este declarat obiectul.
 Obiectele create (cu new[])de către un constructor explicit
trebuiesc distruse (cu delete []) de către un destructor definit în mod
explicit.
 La definirea unei funcţii constructor sau destructor nu trebuie
definit tipul rezultatului întors de funcţie (nici măcar void).
 Iniţializarea obiectului de către constructor se poate face prin
iniţializarea datelor membre cu valorile parametrilor sau prin copierea
datelor membre ale unui obiect transmis ca parametru. În acest din
urmă caz, avem de a face cu un constructor de copiere.
 Un obiect poate fi iniţializat cu o copie a unui alt obiect al clasei
sub forma clasa ob1(ob2);
 De exemplu:
 Complex z1(1., -2.), z2(z1);
Constructori şi destructori
 O operaţie de tipul Clasa ob = Clasa(initializare) prin intermediul
constructorului, crează un obiect şi îi iniţializează datele membre. Exemplu:
 Complex z2 = Complex(1., -2.);
 are acelaşi efect cu declaraţia precedentă. Spre deosebire de acesta:
 Complex z2;
 Z2 = Complex(1., -2.);
 crează un obiect temporar, pe care îl copiază într-un obiect existent.
 Copierea unui obiect folosind operatorul de atribuire realizează o copiere
membru cu membru a obiectului sursă (din dreapta) în obiectul destinaţie
(din stânga)
 Data d=d1; //atribuire
 Data *pd = new Data(d1); //creare obiect anonim initializat
 Copia se face membru cu membru. Obiectul ce urmează a fi copiat
este transmis prin referinţă. Compilatorul va genera pentru clasa C, un
constructor implicit de copiere: C::C(const C&); care realizează copierea
datelor membru cu membru (copiere superficială). Exemplu:
 punct p1;// apeleaza constructorul implicit scris de programator
 // care asigura initializarea la (0, 0)
 punct p2(2,5); //initializare explicita constructor de initializare)
 punct p3(p2); //initializare prin copiere constructor de copiere)
Constructori şi destructori
 Constructorul implicit de copiere nu funcţionează corect în caz că
obiectul alocă dinamic memorie. În acest caz programatorul trebuie să-
şi definească propriul constructor de copiere, care să realizeze o
copiere profundă, a datelor indicate de pointeri şi nu o copiere a
pointerilor.
 Obiectele clasei pot fi copiate prin atribuire. Copierea se face
membru cu membru. Exemplu:
 Complex z1(-1., 2.);
 Complex z = z1;
 Data d1=Data(2004,10,5);
 Iniţializarea este mai eficientă decât atribuirea. În cazul atribuirii
există o valoare (veche) a obiectului, care trebuie ştearsă şi prin
atribuire se copiază valoarea nouă a obiectului din dreapta operatorului
de atribuire.
 Vom considera un exemplu în care se alocă dinamic memorie
pentru datele membre. Fie clasa persoana, prevăzută cu mai mulţi
constructori şi un destructor:
Constructori şi destructori
 class persoana{
 private:
 char* nume;
 char* adresa;
 char* cnp;
 public:
 persoana(char* n=””,char* a=””,char* c=””);
 persoana(persoana& p);
 ~persoana();
 };
 persoana::persoana(char* n, char* a, char* c){
 nume=new char[strlen(n)+1];
 strcpy(nume, n);
 adresa=new char[strlen(a)+1];
 strcpy(adresa, a);
 cnp=new char[strlen(c)+1];
 strcpy(cnp, c);
 };
Constructori şi destructori
 persoana::persoana(persoana& p){
 nume=new char[strlen(p.nume)+1];
 strcpy(nume, p.nume);
 adresa=new char[strlen(p.adresa)+1];
 strcpy(adresa, p.adresa);
 cnp=new char[strlen(p.cnp)+1];
 strcpy(cnp, p.cnp);
 };
 persoana::~persoana(){
 delete [] nume;
 delete [] adresa;
 delete [] cnp;
 };
Constructori şi destructori
 Dacă o clasă conţine date membre constante sau referinţe, acestea nu
pot fi iniţializate în corpul constructorului, ci printr-o listă de iniţializare
plasată după antetul constructorului şi separată de acesta prin
 Constructorii şi destructorii sunt apelaţi implicit la definirea,
respectiv distrugerea obiectelor. Obiectele sunt construite în ordinea
declarării lor şi sunt distruse în ordine inversă declarării.
 Clasele care conţin membri const şi membri referinţe trebuie să
aibe un constructor definit de programator, întrucât referinţele trebuiesc
iniţializate.
 În absenţa unor declarări explicite, compilatorul furnizează
următoarele funcţii membre:
 - un constructor implicit
 - un constructor de copiere
 - un operator de atribuire
 - un destructor implicit
 - un operator de adresare
Membrii statici ai unei clase
 Membrii unei clase care sunt declaraţi cu acest specificator se
numesc statici şi au un rol aparte în cadrul clasei.
 Pentru datele nestatice ale unei clase există copii distincte în
fiecare obiect.
 Datele statice există într-o singură copie, comună tuturor
obiectelor.
 Crearea, iniţializarea şi accesul la această copie sunt total
independente de obiectele clasei.
 Funcţiile membre statice efectuează operaţii care nu sunt
asociate obiectelor individuale, ci întregii clasei.
 Un membru static poate fi referit de funcţiile ne-membre prin
două metode:
 Indicând numele clasei şi folosind operatorul de rezoluţie de
domeniu;
Membrii statici ai unei clase
 Specificând un obiect al clasei şi folosind operatorul de selecţie
 „ .”.

 class A {
 static int i;
 };
 int A::i;
 main()
 {
 A::i=10;
 A od;
 int n = od.i;
 }
Cuvântul cheie this
 La apelarea unei funcţii membre, aceasta este informată asupra identităţii
obiectului asupra căruia va acţiona prin transferul unui parametru implicit
care este adresa obiectului.
 De exemplu, în cazul apelului:
 ob.verificare(i); funcţia verificare() primeşte şi adresa obiectului ob, în afară
de valoarea i.
 De asemenea există cazuri în care adresa obiectului este necesar să fie
utilizată în definiţia funcţiei.
 Acest lucru este realizat în C++ de cuvântul cheie this, asociat unui pointer
către obiectul pentru care s-a apelat funcţia.
 Cuvântul this are sens şi poate apare numai în definiţia unor funcţii
membre.
 Exemplul următor adaugă clasei student o funcţie adresa(), care afişează
adresa obiectului:
 Exemplul 1:
 student::adresa()
 {
 cout<<”Adresa obiectului pentru care s-a apelat funtcia este”;
 cout<<this;
 }
Cuvântul cheie this
 ............
 student stTI; // Se defineşte un obiect stTI aparţinând clasei TI.
 stTI.adresa(); // Afişează adresa obiectului stTI.

 Exemplul 2
 Vom crea două obiecte de tip numărător n1 şi n2. Utilizând pointerii *n1
şi *n2 putem reprezenta grafic modul în care pointează aceste obiecte.

n1-> cifra _sute n2-> cifra _sute


cifra_zeci cifra_zeci
cifra_unităţi cifra_unităţi
setare() setare()
avans() avans()
afisare() afisare()
Cuvântul cheie this
 Pentru adresarea unei anumite funcţii membră a clasei s-a
utilizat operatorul “.”
 n1. setare();
 sau
 n2.avans();
 Funcţia setare din clasa numarator poate fi definită astfel:
 void numarator ::setare(int cs, int cz, int cu)
 {
 this->cifra_sute=cs;
 this->cifra_zeci=cz;
 this->cifra_unitati=cu;
 }
Cuvântul cheie this
 Operatorul this va puncta pe începutul structurii clasei ca în figura
următoare:

this -> cifra _sute


cifra_zeci
cifra_unităţi
setare()
avans()
afisare()

 Utilizând acest operator putem să ne referim la orice element al


obiectului curent dar nu însă şi în interiorul unei funcţii.
 Notaţia *this va reprezenta referirea la întregul obiect.
Functii de tipul prieten friend
 O funcţie de tip friend este in esenţă o funcţie standard, care nu este
membra a clasei ci are numai acces la membrii de tip privat ai
acelei clase.
 Iată o clasa denumită casa
 class grupa {
 double data;
 public:
 double intalniri ;
 void Andra(intalniri);
 friend double prieteni(grupa*p);
 };
 Declaraţia unei funcţii prietene se poate face oriunde in cadrul
declaraţiei clasei şi oferă funcţiei de a avea acces la oricare dintre
membri.
Functii de tipul prieten friend
 Funcţia rămâne externă, deci nu este permis un apel
asociat unui obiect, de forma x.fct( ) sau x ->fct( ).
 Sunt posibile următoarele situaţii:
 o funcţie independenta este prietena a unei clase;

 o funcţie membră a unei clase este prietena altei


clase;
 o funcţie este prietena mai multor clase;

 toate funcţiile unei clase y sunt prietene ale altei clase


x; - în acest caz se spune ca clasa y este prietena a
clasei x.
SUPRAINCARCAREA FUNCTIILOR SI
OPERATORILOR
 Supraincarcarea functiilor si operatorilor (overloading) sunt elemente
esentiale in programarea C++. Ele ofera o baza importanta pentru
polimorfism in timpul compilarii, dand o extensibilitate si flexibilitate
limbajului.
 Supraincarcarea unei functii inseamna utilizarea aceluiasi identificator
de functie pentru cel putin doua functii cu conditia ca ele sa se
deosebeasca prin tipuri si/sau numar de parametri, adica sa aiba
prototipuri diferite.
 In acest fel compilatorul poate selecta, la un moment dat, functia care
trebuie apelata.
 In C++, se pot supraincarca aproape toţi operatorii, astfel incat ei sa
efectueze diverse operatii in mai multe clase create. La
supraincarcarea unui operator, nu se pierde nimic din semnificatiile
sale originale, ci doar se extinde tipul obiectelor carora li se poate
aplica. Supraincarcarea operatorilor se refera la o facilitate specifica
limbajului C++. Este vorba de a oferi posibilitatea programatorului sa
atribuie operatorilor si alte sensuri decat cele predefinite.
 Un operator binar supraincarcat, de exemplu *, poate realiza operatia
de inmultire si intre obiecte de tip matrice, numere complexe, numere
rationale.
FUNCTIE OPERATOR
 Un operator se poate supraincarca prin definirea unei functii
operator. O functie operator defineste operatiile specifice pe care le
va efectua operatorul supraincarcat corespunzator clasei in care
opereaza.
 Functiile operator pot fi sau nu functii membru ale clasei in care
opereaza. De obicei, functiile operator, care nu sunt functii membru
ale clasei, sunt functii friend.
 Sintaxa unei functii operator membru a unei clase;
 tip_ret iden_clasa::operator semn_op(lista_par)
 { // operatii}
 Cuvantul "operator" este un cuvant cheie, iar la crearea unei functii
operator, semn_op reprezinta simbolul operatorului supraincarcat.
 De regula, functiile operator membru returnează un obiect al clasei
asupra căreia operează si nu sunt funcții statice.
 Funcţia operator membru care supraîncarcă un operator binar
conține un singur parametru.
FUNCTIE OPERATOR
 Motivul consta in faptul 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 operator prin parametrul existent in functie.
 Apelul funcției operator este generat de obiectul ce reprezintă
operandul stâng al operatorului binar respectiv.
 Exemplu:
 Sa se implementeze clasa complex realizând operațiile aritmetice
adunare, scădere, înmulțire si impartire prin supraîncărcarea
operatorilor respectivi cu functii operator membru.
 #include<iostream.h>
 #include<conio.h>
 #include<math.h>
 class complex{
 double re,im;
 public:
 complex(double a=0.0,double b=0){re=a;im=b;}
FUNCTIE OPERATOR
 void cit(){
 cout<<"Dati partea reala. ";cin>>re;
 cout<<"Dati partea imaginara. ";cin>>im;
 getch();}
 complex operator+(complex &c1);
 complex operator-(complex &c2);
 complex operator*(complex &c3);
 complex operator/(complex &c4);
 void afis(){
 if(im<0)cout<<re<<im<<"*i";
 else cout<<re<<"+"<<im<<"*i";}
 };
FUNCTIE OPERATOR
 complex complex::operator+(complex &c1){
 complex u;
 u.re=re+c1.re;
 u.im=im+c1.im;
 return u;}
 complex complex::operator-(complex &c2){
 complex v;
 v.re=re-c2.re;
 v.im=im-c2.im;
 return v;}
 complex complex::operator*(complex &c3){
 complex t;
 t.re=re*c3.re-im*c3.im;
 t.im=re*c3.im+im*c3.re;
 return t;}
FUNCTIE OPERATOR
 complex complex::operator/(complex &c4){
 complex z;
 z.re=(re*c4.re+im*c4.im)/(c4.re*c4.re+c4.im*c4.im);
 z.im=(im*c4.re-re*c4.im)/(c4.re*c4.re+c4.im*c4.im);
 return z;}
 void main(){
 complex z1,z2,z3;
 int n;
 clrscr();
 z1.cit();
 z2.cit();
 z3=z1+z2;
 cout<<"\nSuma este: ";z3.afis();
 z3=z1-z2;
 cout<<"\nDiferenta este: ";z3.afis();
 z3=z1*z2;
 cout<<"\nProdusul este: ";z3.afis();
 z3=z1/z2;
 cout<<"\nRaportul este: ";z3.afis();
 getch();}
FUNCTIE OPERATOR
 Analizand functia operator-() se observa ca operandul din
dreapta operatorului "-" , conform semnificatiei operatiei de
scadere, este scazut din operandul stang. Deoarece cel care
genereaza apelul functiei operator este obiectul indicat de
operandul stang, datele operandului drept trebuie scazute din
cele corespunzatoare indicate prin pointerul this.
 Exemplu:
 Sa se implementeze o clasa "sir" care sa permita efectuarea
unor operatii cu siruri ca:initializare, copiere, atribuirea unui sir
unui alt sir, afisarea lor si sa se supraincarce operatorul "+"
pentru concatenarea a doua siruri.
FUNCTIE OPERATOR
 #include<iostream.h>
 #include<conio.h>
 #include<string.h>
 class sir{
 char *p;
 int l;
 public:
 sir(char*s);
 sir(int n=45);
 sir(const sir&);
 ~sir();
 int ret_l();
 void afis();
 sir operator+(sir &s2);
 };
FUNCTIE OPERATOR
 sir::sir(char*s){
 l=strlen(s);
 p=new char[l+1];
 strcpy(p,s);}
 sir::sir(int dim){
 l=dim;
 p=new char[l+1];
 *p='\0';}
 sir::sir(const sir&s){
 l=s.l;
 p=new char[l+1];
 strcpy(p,s.p);}
 sir::~sir(){ delete p; }
 int sir::ret_l(){ return l; }
 void sir::afis(){ cout<<"\n"<<p; }
FUNCTIE OPERATOR
 sir sir::operator+(sir &s){
 sir suma(l+s.l);
 strcpy(suma.p,p);
 strcat(suma.p,s.p);
 return suma;}
 void main(){
 clrscr();
 sir s1("CONCURSUL DE ");
 sir s2("PROGRAMARE IN C++");
 sir s3;
 s3=s1+s2;
 s3.afis();
 cout<<"\nSirul afisat are lungimea:"<<s1.ret_l();
 getch();}
FUNCTIE OPERATOR
 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 in doua
moduri:
 1) initializare prin copiere
 id_clasa ob_d=ob_s;
 2) atribuiri de obiecte
 id_clasa ob_s, ob_d;
 ob_d=ob_s;
 Initializarea prin copiere este insotita de alocare de memorie si se face
cu ajutorul constructorului de copiere. Acesta este apelat automat la
instantierea unui obiect printr-o declaratie de forma 1). Daca un astfel
de constructor nu exista in clasa respectiva, copierea se va face la nivel
de bit.
FUNCTIE OPERATOR
 Aplicatie:
 Se va utiliza supraincarcarea operatorilor binari + si *, cu functii operator
membru, intro
 clasa matrice.
 #include <iostream.h>
 #include <stdio.h>
 #include <conio.h>
 #include<math.h>
 class matrice {
 private:
 int mat[10][10];
 public:
 matrice(int i,int j);
 matrice();
 matrice(matrice&);
 void afiseaza();
 matrice operator+(matrice&);
 matrice operator*(matrice&);
 };
FUNCTIE OPERATOR
 matrice::matrice(int r,int p) {
 int j;
 for(int i=0;i<r;i++)
 for(j=0;j<p;j++) {
 cout<<" mat["<<i<<"]["<<j<<"]=";
 cin >>mat[i][j]; } }
 int r;
 matrice::matrice(){
 int j;
 for(int i=0;i<r;i++)
 for(j=0;j<r;j++)
 mat[i][j]=0; }
 matrice::matrice(matrice& m) {
 for(int i=0;i<r;i++)
 for(int j=0;j<r;j++)
 mat[i][j]=m.mat[i][j]; }
 void matrice::afiseaza(){
 int i,j;
 for(i=0;i<r;i++){
 cout<<"\n";
 for(j=0;j<r;j++)
 cout<<mat[i][j]<<"\t"; }
 cout<<"\n"; }
FUNCTIE OPERATOR
 matrice matrice::operator+(matrice& k) {
 int i,j;
 matrice t;
 for(i=0;i<r;i++)
 for(j=0;j<r;j++)
 t.mat[i][j]=mat[i][j]+k.mat[i][j];
 return t; }
 matrice matrice::operator*(matrice& k){
 int u,v,i,rez;
 matrice t;
 for(u=0;u<r;u++)
 for(v=0;v<r;v++) {
 rez=0;
 for(i=0;i<r;i++)
 rez+=mat[u][i]*k.mat[i][v];
 t.mat[u][v]=rez; }
 return t; }
FUNCTIE OPERATOR
 void main(){
 clrscr();
 cout<<"\n r=";cin>>r;
 matrice m(r,r),n;
 m.afiseaza();
 n=m+m;
 n.afiseaza();
 getch();
 n=m*m;
 n.afiseaza();
 getch();}
Directive de compilare
condiţionată
 Una dintre directivele de compilare condiţionată este
 #ifndef simbol // urmată de
 #define simbol
 Acest cuplu de directive va fi folosit în numeroase
exemple. Semnificaţia lui este următoarea: dacă până în
acel loc simbol nu a fost definit, va fi definit acum (cu
#define). Dacă era deja definit, atunci se va ignora
instrucţiunea #define. Deci se evită redefinirea.
 Cuplul următor:
 #ifdef simbol
 # define simbol
 #endif
 Are efect exact contrar cazului de mai sus.
 Funcţia #define în C++ este utilizată şi pentru definirea
unor macrodefiniţii cu parametrii.
Directive de compilare
condiţionată
 Exemplu:
 # define PI 3.14
 # define unghi(v) 180*arccos(v)/PI
 ua = (b*b + c*c -a*a)(2*b*c);
 a=unghi(ua);
 Directiva #undef anulează o definiţie anterioară a unui identificator cu
# define.
 Sintaxa este:
 # undef nume_macrodef
 După această directivă, nume_macrodef este detaşat de semnificaţia
asociată anterior şi este posibilă redefinirea sa cu #define.
 #error –Această directivă determină complilatorul să oprească
compilarea atunci când o întâlneşte. Directiva este utilizată pentru
depanare.
 Directivele de compilare condiţionată permit compilarea unor porţiuni
selectate din codul sursă.
 Sunt folosite de exemplu, când se doreşte obţinerea mai multor
variante ale aceluiaşi program.
Directive de compilare
condiţionată
 Sintaxa construcţiei condiţionale este:
 # if(exp1)
 sectiunea_1
 #else
 sectiunea_2
 # endif
 sau
 #if(exp1)
 sectiune_1
 #elif(exp2)
 sectiune_2
 .
 .
 #elif(expn)
 sectiune_n
 #else(exp)
 sectiune_n+1
 #endif
Prevenirea redeclarării
claselor
 Programele realizate până acum conţineau definiţiile claselor în
acelaşi fişier cu funcţia main().
 O tehnică obişnuită în C++ este de a declara şi defini clasa într-
un fişier antet inclus cu o comandă de genul următor:
 #include <nume_fişier_antet>
 Apariţia în mai multe locuri a instrucţiunii #include referitoare la
acelaşi fişier antet, nu ar fi sancţionată ca eroare, dar ar prelungii
durata compilării.
 Pentru evitarea unei astfel de situaţii este recomandabil utilizarea
următoarei secvenţe de instrucţiuni de preprocesare:
 #ifndef nume
 #define nume
 //declaraţia şi definiţia clasei
 #endif.
Prevenirea redeclarării
claselor
 Exemplu:
 fişerul antet counter.h
 #ifndef counter_h
 #define counter_h
 # include <iostream.h>
 class numarator //definitia clasei numarator
 { .........
 ...............}
 #endif counter_h
 Această tehnică stă la baza modularizării programelor.
SISTEMUL DE I/E DIN C++
 Deşi limbajul C++ conţine toate rutinele din biblioteca de I/E a
limbajului C, el ne pune la dispoziţie şi un sistem propriu de I/E
orientat pe obiecte, care ne ajută să citim/scriem obiecte de
diferite tipuri.
 Principalul avantaj al sistemului de I/E din C++ constă în faptul că
el poate fi redefinit în cadrul propriilor clase.
 Ca şi în limbajul C, sistemul de I/E din C++ nu face deosebire între
operatori care folosesc consola şi cele care utilizează fişiere.
 Sistemul de I/E din C++ operează prin “streams”.
 La execuţia unui program scris în C++, următoarele patru streams
sunt predefinite: (fluxuri de I/E)
 cin intrare standard - tastatură
 cout ieşire standard - ecran
 cerr eroare standard - ecran
 clog versiunea tampon a lui cerr - ecran
 Acestea au prototipul în iostream.h.
SISTEMUL DE I/E DIN C++
 Clasa IOS asigură operaţiile cu format, verificarea erorilor şi a
informaţiilor de stare, IOS este folosită drept clasă de bază
pentru următoarele trei clase: ISTREAM, OSTREAM şi
IOSTREAM. Clasa IOS_base conţine funcţii şi variabile membre,
care controlează sau monitorizează funcţionarea de bază a unui
stream.
 Se pot formata datele într-un mod similar funcţiei printf() folosind
sistemul de I/E din C++.
 Fiecare stream din C++ are asociat cu el un număr de “indicatori
de format” (flags), care determină modul de afişare; ei sunt
codificaţi într-o variabilă de tip “integer”. Tipul de enumerare
următor definit în clasa IOS_base, conţine constantele
corespunzătoare acestor “indicatoare”.
SISTEMUL DE I/E DIN C++
namespace std {
class ios_base {
public:
typedef implementation-defined-bitmask-type fmtflags;
static const fmtflags boolalpha;
static const fmtflags dec;
static const fmtflags fixed;
static const fmtflags hex;
static const fmtflags internal;
static const fmtflags left;
static const fmtflags oct;
static const fmtflags right;
static const fmtflags scientific;
SISTEMUL DE I/E DIN C++
 static const fmtflags showbase;
 static const fmtflags showpoint;
 static const fmtflags showpos;
 static const fmtflags skipws;
 static const fmtflags unitbuf;
 static const fmtflags uppercase;
 static const fmtflags adjustfield;
 static const fmtflags basefield;
 static const fmtflags floatfield;
 ...
 };
 }
SISTEMUL DE I/E DIN C++
 Când se poziţionează un flag de format, este activată caracteristica
respectivă; când el este şters, se utilizează formatul implicit.

 La operaţia de citire când este fixat flag-ul:


 boolalpha – determina afisarea variabilelor logice cu true sau false;
 skipws – se ignoră caracterele de tip whitespace (spaţiu, tab, newline),
când este şters caracterele nu mai sunt ignorate.
 left – se aliniază rezultatul la stânga.
 right – se aliniază rezultatul la dreapta.
 internal – se extinde o valoare numerică astfel încât să se completeze
câmpul, prin inserarea de spaţii între caractere de bază.
 oct – determină afişarea în sistem octal.
 hex – determină afişarea în sistem hexazecimal.
 dec – se revine în sistem zecimal.
 showbase – generează afişarea ieşirii în baza de numeraţie
corespunzătoare. 1F va fi afişat 0 x 1F
 showpoint – determină afişarea tuturor zerourilor şi al punctului
zecimal ale unei valori în format virgulă mobilă.
 showpos – determină afişarea semnului, înaintea valorilor zecimale
pozitive.
SISTEMUL DE I/E DIN C++
 scientific – generează afişarea numerelor în format virgulă
mobilă, folosindu-se notaţia ştiinţifică, f. exp.
 unitbuf – goleşte tamponul după fiecare scriere.
 fixed – valorile în format virgulă mobilă sunt afişate folosindu-se
notaţia normală (cu punct fix).
 stdio – când este poziţionat indicatorul stdio , fiecare stream este
eliberat după o operaţie de ieşire, ceea ce determină scrierea în
dispozitivul fizic cuplat la stream.
 uppercase – afişare cu majuscule.
 Pentru a fixa un flag de format, utilizăm funcţia setf() care este
membră a clasei IOS_base.
SISTEMUL DE I/E DIN C++
 Sintaxa este
 fmtflags setf(
 fmtflags _Mask
 );
 fmtflags setf(
 fmtflags _Mask,
 fmtflags _Unset
 );
 Parametrii
 _Mask –flagurile care se activează.
 _Unset -flagurile care se dezactivează.
SISTEMUL DE I/E DIN C++
 De exemplu petru a activa flag-ul showpos, putem folosi instrucţiunea:
STREAM.setf (ios_base ::showpos);
 STREAM se referă la streamul afferent (cout sau cin)
 Setf() – este o funcţie membră a clasei IOS, şi efectuează stream-ul
creat de aceasta. Orice apel al funcţiei setf() se referă la stream-ul
corespunzător.
 Fiecare stream conţine informaţiile de stare a propriului format. Prin
aplicarea unui operator de tip OR valorilor, putem poziţiona mai mulţi
indicatori de stare. De exemplu, apelul de mai jos poziţionează flag-urile
showbase şi hex;
 cout.setf(ios_base :: showbase , ios_base :: hex);
 Întrucât indicatorii de format sunt definiţi în clasa IOS, trebuie să
obţinem accesul la ei prin utilizarea operatorului de rezoluţie :: şi a
numelui de clasă.
 Funcţia unsetf() este complementară funcţiei setf(). Pentru a afla
stările curente ale indicatorilor se foloseşte funcţia flags(), membră a
clasei IOS. Aceasta înapoiază starea curentă a fiecărui flag de format.
SISTEMUL DE I/E DIN C++
 Aplicaţie:
 #include <iostream>

 void main( )
 {
 using namespace std;
 int i = 10;
 cout << i << endl;
 cout.unsetf( ios_base::dec );
 cout.setf( ios_base::hex );
 cout << i << endl;

 cout.setf( ios_base::dec );
 cout << i << endl;
 cout.setf( ios_base::hex, ios_base::dec );
 cout << i << endl;
 }
UTILIZAREA FUNCŢIILOR WIDTH()
ŞI PRECISION()
 Există trei funcţii membre ale clasei IOS, care poziţionează
parametrii de format:
 lăţimea câmpului
 precizia

 Când este afişată o valoare, ea ocupă doar spaţiul rezervat


numărului de caractere necesar. Totuşi putem specifica o lăţime
minimă a câmpului, folosind funcţia width() al cărui prototip este
următorul:
 int width(int w);
 w – este lăţimea câmpului, iar valoarea înapoiată este
anterioară a câmpului.
 Dacă o valoare utilizează un spaţiu mai mic decât cel
specificat, câmpul este completat cu caracterul curent de inserat
(implicit acesta este „spaţiu”).
UTILIZAREA FUNCŢIILOR WIDTH()
ŞI PRECISION()
 Dacă, totuşi mărimea valorii depăşeşte lăţimea
minimă a câmpului, câmpul va fi suprascris şi
valorile nu vor fi trunchiate.

 La afişarea unei valori în format de virgulă mobilă, se


folosesc (în mod implicit) şase cifre după punct;
totuşi, putem fixa acest număr dacă apelăm funcţia:
precision () al cărei prototip este:
 int precision (int p);
 Aici precizia este stabilită la valoarea dată de
parametrul p şi funcţia va înapoia vechea valoare.
UTILIZAREA FUNCŢIILOR
WIDTH() ŞI PRECISION()
 #include <iostream>
 using namespace std;

 void main( ) {

 cout.width( 20 );
 cout << cout.width( ) << endl;
 cout << cout.width( ) << endl;
 }
UTILIZAREA FUNCŢIILOR WIDTH()
ŞI PRECISION()
 Exemplu:
 #include <iostream>

 int main( )
 {
 using namespace std;
 float i = 31.31234F;

 cout.precision( 3 );
 cout << i << endl; // afiseaza 3 digiti semnificativi
 cout << fixed << i << endl; // afiseaza trei digiti dupa punct
 }
Supraîncărcarea operatorilor << şi >>
 Până acum s-a prezentat supraîncărcarea unor operatori în relaţie cu
anumite clase.
 Atunci când dorim sa afişăm datele unei clase, utilizarea lui cout şi a
operatorului de extragere << poate conduce la necesitatea scrierii unui
număr important de linii de program.
 Acelaşi lucru este valabil şi în situaţia în care dorim să introducem
datele unei clase prin utilizarea lui cin şi a operatorului de înserare >>.
 O alternativă la această problemă ar fi supraîncărcarea operatorilor de
înserare şi de extragere.
 Aceasta supraîncărcare permite să se realizeze o citire sau o scriere
cu anumite formatări sau în anumite configuraţii.
 Pentru streamul cout avem următoare secvenţă generală de
supraîncarcare a operatorului de inserare:
 ostream& operator <<(ostream &flux_atasat, tip_clasa obiect)
 {
 // corpul funcţiei de înserare
 return flux_atasat;
 }
Supraîncărcarea operatorilor << şi >>
 Funcţia returnează o referinţă de tipul ostream – o clasă pe care C++ o
derivează din clasa IOS şi care acceptă ieşirea. Primul parametru al
operatorului este fluxul în care se va însera, iar al doilea este obiectul
care va fi afişat în flux.
 Dacă operatorul << este supraîncărcat el poate fi utilizat astfel:
 tip_ clasa a,b,c;
 cout<<a<<b<<c;
 Funcţiile de înserare vor face aproximativ aceiaşi paşi pe care îi fac de
obicei, numai că îi vor face prin fluxul obiect şi nu direct prin cout, cerr
sau clog.
 Pentru supraîncărcarea operatorului de extragere >> care operează cu
streamul cin se va folosi structura:
 istream& operator>>(istream &flux_atasat, tip_clasa obiect)
 {
 // corpul funcţiei de extragere
 //se va lucra asupra streamului de intrare
 //se vor face formatarile streamului si va citi efectiv prin stream
 //se va returna obligatoriu fluxul atasat
 return flux_atasat;
 }
Supraîncărcarea operatorilor << şi >>
 Se observă că spre deosebire de funcţiile supraîncărcate, trebuie să
se transmită o referinţă spre obiectul din cadrul funcţiei de extragere
supraîncărcate.
 Funcţiile de extragere returnează o referinţă la un flux de tipul istream,
care este derivat din clasa flux de intrare IOS.
 Primul parametru este o referinţă la un flux (în general cin).

 La folosirea operatorului in program se va proceda astfel:


 tip_clasa a,b,c;
 cin>>a>>b>>c;
 Se observa că streamul cin este de tipul istream (stream de intrare –
Input stream).
 În plus se transmite adresa structurii prelucrate de stream pentru că
structura este modificată nu doar afişată ca la supraîncărcarea
operatorului de inserţie. În rest abordarea este la fel ca la inserţie.
 S-a numit operator de inserţie/înserare pe cel asociat cu streamul cout
deoarece inserează, adaugă informaţie în streamul cout respectiv la
ieşirea de tip display, şi extracţie deoarece extrage din streamul cin
date şi le plasează în câmpurile structurii proprii specificate.
Supraîncărcarea operatorilor << şi >>
 Exemplu de program
 #include <iostream.h>
 #include <iomanip.h>
 # include <conio.h>
 //Avem structura
 class persoana{
 public:
 char nume[25] ;
 char prenume[25] ;
 int varsta ;
 double salariu;
 char nr_telefon[15];
 }p;
Supraîncărcarea operatorilor << şi >>

 //Vom defini un operator de insertie


 ostream& operator<<(ostream &display, persoana p)
 {
 display<<"Numele "<<p.nume<<" "<<p.prenume<<endl;
 display<<"Are "<<p.varsta<<" ani."<<endl;
 display<<"Are un salariu de "<<p.salariu<<"RON "<<endl;
 display<<"O puteti apela la nr."<<p.nr_telefon<<endl;
 return display;
 }
Supraîncărcarea operatorilor << şi >>
 //Vom defini un operator de extractie
 istream& operator>>(istream &tastatura, persoana &p)
 {
 cout<<"Numele:";
 tastatura>>p.nume;
 cout<<"Prenumele:";
 tastatura>>p.prenume;
 cout<<"Varsta :";
 tastatura>>p.varsta;
 cout<<"Salariul actual [RON]:";
 tastatura>>p.salariu;
 cout<<"Nr. de telefon la care poate fi gasita:";
 tastatura>>p.nr_telefon;
 return tastatura;
 }
Supraîncărcarea operatorilor << şi >>
 void main()
 {
 persoana a;
 cin>>a;
 cout<<"Datele introduse despre persoana sunt:"<<endl<<a;
 getch();
 }
Definirea de manipulatori personalizaţi

 Atunci când dorim să realizăm rapid sau să grupăm sub o


singură comandă anumite opţiuni de formatare pe care le
folosim repetat sau pur şi simplu dorim să dăm un nume
sugestiv acestor opţiuni vom face apel la definirea
manipulatorilor.
 În anumite puncte structura de redefinire va fi asemănătoare
structurii de supraîncărcare, dar sunt şi element specifice.
 Pentru un manipulator de ieşire asociat funcţiei cout vom
folosi structura:
 ostream & nume_manipulator_out(ostream &stream_atasat)
 {
 //operatii de formatare
 stream_atasat.setf(..);
 //operatii de afisare
 stream_atasat<<…<<…;
 // in final obligatoriu vom returna streamul atasat
 return stream_atasat;
 }
Definirea de manipulatori personalizaţi
 In program îl vom folosi astfel:
 cout<<nume_manipulator_out<<...<<...;
 Pentru un manilator de intrare asociat functiei cin vom folosi
următoarea structură de declarare:
 istream & nume_manipulator_in(istream &stream_atasat)
 {
 //operatii de formatare
 //operatii de citire
 // in final in mod obligatoriu vom returna streamul atasat
 return stream_atasat;
 }
Definirea de manipulatori personalizaţi
 Vom apela manipulatorul scriind :
 cin>>nume_manipulator_in>>v1>>…>>vk ;
 Trebuie avut grijă să nu folosim un manipulator de iesire în locul
unuia de intrare şi invers pentru că manipulatorii lucrează cu
tipuri de streamuri diferite.
 Putem crea manipulatori parametrizaţi prin simpla adăugare în
lista de parametri a funcţiei de noi parametri, de exemplu:
 ostream &nume_manipulator(ostream &stream_atasat,tip1
p1,tip2 p2,…tipn pn)
 {
 ….
 }
Definirea de manipulatori personalizaţi

 la apelare vom proceda astfel:


 tip1 a1;
 tip2 a2;
 ....
 tipn an;
 cout<<nume_manipulator(a1,a2,...an);

 Pentru manipulatorii de intrare se va proceda la fel.


Lucrul cu fişierele în C++
 După cum există o formatare pe bază de streamuri a intrărilor
şi ieşirilor există şi o modalitate de lucru cu fişierele bazată pe
streamuri.
 Astfel fiecărui fişier i se va asocia un stream în care fi se va
putea numai scrie şi citi, fie ambele.
 De asemenea există:
 o abordare secvenţială în lucrul cu fişierele (adică pentru a
citi secvenţa dorită trebuie să parcurgem prin citire tot ce
este înaintea ei)
 o abordare de acces aleatoriu (în care citim sau scriem în
orice moment exact secvenţa care ne interesează dacă în
schimb îi ştim poziţia precisă în fişier).
 Mai mult putem accesa fişierele în format text ca o colecţie de
şiruri de caractere sau în format binar ca o grupare de octeţi.
 Întotdeauna în lucrul cu fişierele vom avea obligatoriu două
elemente – o funcţie de deschidere a fişierului (open(…)) şi
funcţie de închidere fără parametri (close()).
Lucrul secvenţial cu fişierele
 Îl vom utiliza când lucrăm cu fişierele text şi nu avem nevoie de optimizări
fie pentru că fişierul este prea mic, fie pentru că optimizarea nu şi-ar avea
rost.
 Avem trei tipuri de streamuri de tip fişier:
 ifstream – pentru scriere în fişier;
 ofstream - pentru citire din fişier;
 fstream – pentru scriere şi citire din fişier;
 Deschidem streamul asociat fişierului cu funcţia open() ce are următorul
prototip:
 void open(const char *numefisier,int mod,int acces);
 În general vom avea nevoie doar de numele fişierului putând scrie doar:
 ofstream iesire;
 iesire.open(”test.txt ”);
 Datele ce vor fi scrise în fişier sunt scrise ca şi cum s-ar lucra cu cout numai
că datele nu vor fi afişate pe ecran ci scrise în fişier cu formatările specifice
streamului ieşire.
Lucrul secvenţial cu fişierele
 De exemplu:
 iesire<<” Salariu ”<<salariu_net<<” RON”;

 Dupa ce am terminat lucrul cu fişierul îl vom închide cu:
 iesire.close();
 La fel se va lucra şi cu ifstream, după cum se lucrează cu cin, pentru
a se citi nişte date din fişier.
Prelucrare binară a fişierelor
 Avem funcţiile membre asociate streamurilor fişier :
 get(char &ch) asociată ifstreamurilor;
 put(char ch) asociată ofstreamurilor.
 Pentru a citi un caracter din fişier vom avea secvenţa:
 ifstream intrare;
 intrare.open(”in.txt”,ios::in|ios::binary);
 char c;
 intrare.get(c);
 intrare.close();
 Pentru a scrie un caracter în fişier vom avea secvenţa:

 ofstream iesire;
 iesire.open(”aut.txt”,ios::out|ios::binary);
 iesire.put(’a’);
 iesire.close();
Prelucrare binară a fişierelor
 Pentru a scrie dintr-o zonă tampon în stream sau invers se folosesc
funcţiile write(…)şi read(…) cu următorul prototip:
 istream &read(unsigned char *buf,int ncitit);
 ostream &write(const unsigned char *buf,int nscrisi);
 read() va citi din stream ncitit octeţi şi-i va pune în zona de memorie
buf.
 write() va citi din buf nscris octeţi şi-i va pune în stream.
 La deschidere se va seta indicatorul de access ios :: binary.
 Dacă se doreşte de exemplu scriere unei structuri oarecare :
 Struct persoana p ;
 iesire.write((unsigned char*) &p,sizeof(struct persoana));
 La fel se va proceda şi la citire.
 Pentru a afla câte au fost citite cu read() se foloseşte funcţia membru
gcount(), un exemplu:
 intrare.read(…)
 cout<<intrare.gcount();// afiseaza numarul de caractere extrase din
stream la
 // ultima citire
Prelucrare binară a fişierelor
 Pentru a citi o linie dintr-un fişier text se foloseşte funcţia getline() cu
prototipul:
 istream &getline(char *buf,int nmaxcitit,char delimatator);
 Funcţia membru citeşte caractere din stream până când ori se
întâlneşte delimitatorul (care este implicit linie nouă) ori s-au citit
nmaxcitit caractere. Oricare din condiţii întâlnită prima determină oprire
citirii.
 Pentru a determina dacă s-a atins sfârşitul de fişier de foloseşte funcţia
membru eof() care este diferită de zero dacă da.(EOF = End Of File).
Mai întotdeauna se foloseşte valoarea negată a funcţiei într-o secvenţă
while când se parcurge cap coadă un fişier.
 Pentru a fi siguri că informaţia a fost scrisă din stream în fişier, pentru
descărcarea zonei de memorie a streamului în fişier se foloseşte funcţia
membru flush(). Aceasta poate fi folosită ca o măsură de siguranţă.
Prelucrare binară a fişierelor
 Mai avem funcţiile membre care ne dau poziţia curentă a
pointerului de fişier tellg() şi tellp() folosite împreună cu seekg() şi
seekp().
 Este indicat ca la accesul aleatoriu fişierele să fie deschise cu
indicatorul de acces ios::binary în plus la scrieri şi citiri în cadrul
aceluiaşi fişier să se folosească fstreamul.
 Toate referirile la istream sunt automat compatibile cu ifstream
prin mecanismul de moştenire, la fel şi pentru ostream cu
ofstream.
 Ca specificatori suplimentari utili în lucrul cu fişierele ar fi:
 ios::nocreate – dacă nu există fişierul va eşua deschiderea pentru
citire;
 ios::noreplace – dacă fişierul există acesta nu va fi suprascris,
evitându-se deschiderea;
 ios::app – se foloseşte pentru deschiderea spre adăugare la
sfârşitul fişierului (append).
Lucrul aleatoriu cu fişierele
 Se poate avea acces aleatoriu în fişier prin folosirea funcţiilor membre
de poziţionare seekg(…) şi seekp(…) care au următoarele prototipuri:

 istream &seekg(streamoff offset,seek_dir origine);
 ostream &seekp(streamoff offset,seek_dir origine);
 Prima poziţionează în streamul de intrare, cea de-a doua în streamul
de ieşire.
 Precizia de poziţionare este de un octet, poziţia precizându-se printr-o
valoare întreagă offset relativ la un punct de referinţă stabilit prin
origine.
 Origine poate avea una dintre cele trei valori – ios::beg (Poziţia este
faţă de începutul fişierului), ios::cur(Poziţia este faţă de poziţia curentă
a pointerului de fişier), ios::end(Poziţia este relativă faţă de sfârşitul
de fişier).
 De exemplu pentru fisierul deschis pentru scriere cu streamul iesire
de tip ofstream pentru a ne poziţiona la 10 octeţi faţă de început vom
scrie:
 iesire.seekp(10,ios::beg);
PROGRAMAREA ÎN VISUAL C++
 Visual C++ a devenit mult mai mult decât un simplu
compilator.
 Câteva din numărul mare de facilităţi oferite de Visual C++
care ne ajută să dezvoltăm aplicaţii rapide şi complete
folosind cele mai recente tehnologii Windows, sunt
următoarele:
 Sunt incluse clasele fundamentale Microsoft (M.F.C.), care
simplifică şi accelerează dezvoltarea aplicaţiilor Windows.
De asemeni sunt incluse editoare sofisticate de resurse în
scopul proiectării casetelor de dialog complexe, a
meniurilor, a barelor de instrumente, a imaginilor şi a altor
multe elemente ce compun aplicaţiile Windows actuale.
 Este oferit un excelent mediu de dezvoltare integrat, numit
Developer Studio, care prezintă forme grafice ale structurii
aplicaţiei pe măsură ce o dezvoltăm.
 Are un instrument pentru depanare integrat perfect, ce ne
permite să inspectăm în detaliu din cadrul unui program
aflat în execuţie.
Crearea unui proiect
 Visual C++ este un instrument potrivit pentru
dezvoltarea de programe cu interfaţă grafică.
 Visual Studio a purtat numele de Developer Studio
şi este posibil să se întâlnească şi acronimul IDE
(Integrated Deyelopment Environment - mediu
integrat de dezvoltare), folosit uneori ca şi referire
la Visual Studio.
 Fereastra Microsoft Visual C++ este afişată la
lansarea mediului Visual C++. Microsoft Visual C++
este numele dat interfeţei cu utilizatorul a lui Visual
C++, interfaţă afişată în figura următoare. Această
interfaţă reprezintă suprafaţa de lucru.
Crearea unui proiect
Fereastra interfeţei cu utilizatorul

 Pentru a începe o nouă aplicaţie trebuie să se creeze mai întâi un


proiect.
 Un proiect este folosit pentru administrarea tuturor elementelor care
compun un program Visual C++ şi care au ca rezultat o aplicaţie
Windows. Pentru a crea un nou proiect se selectează comanda New a
meniului File şi apoi Project si se va deschide fereastra New Project.
Fereastra interfeţei cu utilizatorul
 Pentru crearea unui proiect mai întâi trebuie să se specifice tipul
acestuia.
 Aici este afişată o listă cu toate tipurile de proiecte care se pot
crea.
 Pentru exemplul se selectează MFC Application din lista cu tipurile
de proiect.
 Selectarea acestei opţiuni înseamnă că proiectul va avea ca
rezultat un program executabil Windows standard.
 Orice proiect are nevoie de un nume. Acest nume se specifică în
caseta Name din caseta de dialog New Project.
 Pentru exemplul nostru, se va tasta ExempluPO în caseta Name
din cadrul casetei de dialog New Project.
 Caseta Location este folosită pentru precizarea directorului în care
vor fi plasate fişierele proiectului. În cazul exemplului de faţă nu
este nevoie să se modifice această locaţie.
Fereastra interfeţei cu utilizatorul
 Calea afişată iniţial în caseta Location depinde de opţiunile exprimate
la instalarea lui Visual C++.
 Pentru a modifica această locaţie, fie se editează calea explicită, fie se
efectuează un clic pe butonul aflat în partea dreaptă a casetei Location.
Locaţia implicită se bazează numele proiectului - în exemplul nostru,
c:\users\george\documents\visual studio 2015\Projects.
 După stabilirea opţiunilor din cadrul casetei de dialog New Project, se
efectuează un clic pe OK pentru a iniţia generarea proiectului.
 Acest proces va fi controlat de MFC AppWizard. Scopul acestuia este
să permită realizarea unui schelet de program care poate fi dezvoltat
ulterior.
 Acest lucru este realizat permiţând să se selecteze tipul de program
după care este folosită biblioteca MFC, pentru generarea fişierelor care
vor forma împreună un proiect Visual Studio.
 Caseta de dialog MFC AppWizard oferă trei opţiuni pentru tipul de
interfaţă a aplicaţiei.
 În cazul proiectului Exemplu PO se va utiliza o interfaţă de tip dialog.
Se selectează butonul de opţiune Dialog Based.
 Se poate, de asemenea, să selectaţi limba care va fi folosită pentru
resurse.
 Nu este necesar să se modifice conţinutul casetei combinate Language
în cazul programului ExempluPO.
Fereastra interfeţei cu utilizatorul

 Caseta de dialog MFC AppWizard – Pas 1 Next


Fereastra interfeţei cu utilizatorul
 Selectarea tipului aplicatiei – Dialog based
Fereastra interfeţei cu utilizatorul
 Acum s-a precizat toate informaţiile necesare pentru ca AppWizard să
poată crea proiectul.
 Se efectuează un clic pe butonul Finish. Se va afişa caseta de dialog New
Project Information, ilustrată în figura următoare.
Fereastra interfeţei cu utilizatorul

 AppWizard va prezenta această casetă de dialog pentru a


confirma detaliile proiectului pe care este gata să-l creeze.
 Se poate vedea aici numele claselor C++ din proiect şi numele
fişierelor care vor fi create.
 În lista Features se poate vedea, de asemenea, funcţionalitatea
figurată de AppWizard. Pentru a continua se efectuează un clic
pe OK în cadrul casetei de dialog New Project Information.
 AppWizard şi-a îndeplinit sarcina şi în Visual Studio este deschis
acum proiectul nou creat - ExempluPO.
 În acest moment, deşi nu s-a scris nici o linie de cod sursă C++,
se are la dispoziţie o aplicaţie Windows completă şi perfect
funcţională.
 Secţiunea afişată de către Visual Studio în partea stângă se
numeşte secţiunea spaţiului de lucru.
 După ce proiectul a fost creat, secţiunea spaţiului de lucru oferă
două pagini: ClassView, Solution Explorer
Fereastra interfeţei cu utilizatorul
 Aceste pagini permit accesarea oricărei componente a proiectului.
 Se poate modifica dimensiunea secţiunii spaţiului de lucru şi a altor
secţiuni care apar în Visual Studio prin efectuarea unui clic pe
marginea secţiunii şi deplasarea mouse-ului în timp ce se ţine butonul
apăsat.
 AppWizard este utilizat exclusiv pentru crearea noilor proiecte. Nu se
poate reveni la casetele de dialog cu opţiuni AppWizard în cadrul unui
proiect existent.
 Dacă se descoperă că s-a făcut o alegere greşită şi se doreşte reluarea
etapelor AppWizard, trebuie să se înlăture mai întâi proiectul existent.
 Pentru a înlătura un proiect, se şterge directorul acestuia. Spre
exemplu, pentru a relua crearea proiectului ExempluOP, se şterge
directorul
 c:\users\george\documents\visual studio 2015\Projects.
 Procesul de asamblare are ca rezultat fişierul executabil Windows
corespunzător proiectului. În cazul proiectului ExempluPO, acest fişier
va fi numit ExempluPO.exe. Odată generat acest fişier, se poate rula
din Visual Studio.
 Se poate crea fie o versiune pentru depanare, fie o versiune finală a
unui fişier executabil. „
Fereastra interfeţei cu utilizatorul
 În mod implicit este asamblată o versiune pentru depanare; se va
folosi această opţiune implicită în toate exemplele dacă nu se propune
explicit o altă variantă.
 Pentru programul ExempluPO nu este necesară modificarea
configuraţiei.
 În mod implicit, Visual Studio va genera o aplicaţie care conţine
informaţii pentru depanare.
 Aceste informaţii permit să se inspecteze codul executat şi să se
verifice valorile variabilelor.
 Înserarea informaţiilor pentru depanare duce, însă, la o creştere a
dimensiunii fişierului executabil şi la o scădere a performanţelor.
 Configuraţia pentru versiunea finală asamblează executabilul fără
informaţii pentru depanare, fiind folosită de regulă atunci când
aplicaţia este livrată către un client.
 Executabilele Visual C++ sunt fişiere Windows EXE standard
 Fişierul ExempluPO.exe este similar cu orice alt fişier executabil
Windows. Prin urmare, el poate fi executat din Explorer, sau puteţi să
creaţi o scurtătură la acesta şi să o plasaţi pe suprafaţa de lucru.
Fereastra interfeţei cu utilizatorul

 Fereastra ExempluPO
Efectuarea compilării şi a editării de legături
 Procesul de asamblare efectuează compilarea fişierelor C++
individuale dintr-un proiect, după care rezultatele sunt legate
împreună pentru a forma fişierul executabil.
 Pentru a asambla proiectul ExempluPO, se efectuează clic pe
butonul Build sau se selectează Build ExempluPO.exe din meniul
Build.
 ExempluPO.exe se află în subdirectorul /Debug din directorul
/ExempluPO al proiectului.
 Acest subdirector conţine, de asemenea, fişierele obiect ale
programelor din cadrul proiectului.
 Subdirectorul /Debug a fost creat din cauză că s-a ales o
configuraţie pentru depanare, în timp ce o configuraţie pentru
versiunea finală ar fi plasat fişierele într-un subdirector numit
/Release.
 Pagina Build a secţiunii Output înfăţişează informaţii privind
procesul de asamblare.
 În cazul în care codul sursă conţine erori, acestea sunt afişate în
cadrul paginii Build, ilustrată în figura următoare. Deoarece
AppWizard a generat întreg codul, nu ar trebui să apară erori.
Efectuarea compilării şi a editării de legături
 Executia proiectului ExempluPO –F5 sau Debug ->Start Debugging
Efectuarea compilării şi a editării de legături
 Fereastra aplicaţiei conţine două butoane, OK şi Cancel, şi afişează un text.
 Există, totodată, o bară de titlu care afişează o pictogramă asociată, numele
aplicaţiei şi un buton de închidere.
 Bara de titlu conţine şi un meniu de sistem şi poate fi utilizată pentru a
deplasa fereastra pe ecran prin efectuarea unui clic asupra ei şi menţinerea
butonului mouse-ului apăsat.
 Putem afişa informaţiile despre aplicaţie dacă se efectuează clic pe
imaginea MFC din colţul stânga sus al ferestrei ExempluPO şi se
selectează About ExempluPO din meniul de sistem care apare (figura
următoare).
Modificarea interfeţei aplicaţiei
 Elementele vizuale ale unui proiect se numesc resurse.
 Spre exemplu, casetele de dialog, pictogramele şi meniurile constituie
resurse.
 Numit sugestiv editor de resurse, acesta este instrumentul din Visual
Studio care se foloseşte pentru proiectarea resurselor de diferite tipuri
şi modificarea aspectului efectiv al aplicaţiei.
 Pentru a adăuga un nou buton, va trebui să se deschidă macheta
casetei de dialog.
 Pentru aceasta se parcurg următorii paşi:
 1. Se selectează pagina ResourceView a secţiunii spaţiului de lucru al
proiectului. Se va afişa lista cu resursele proiectului.
 2, Se expandează lista de resurse prin efectuarea unui clic pe semnul +
din stânga etichetei ExempluPO Resources şi se expandează catalogul
Dialog. Aşa cum se vede în figura următoare, apar doi identificatori de
dialog, IDD_ABOUTBOX ŞI IDD_EXEMPLUPO_DIALOG.
Modificarea interfeţei aplicaţiei
 3. Se efectuează un dublu clic pe identificatorul
IDD_EXEMPLUPO_DIALOG.
 În consecinţă va fi afişată macheta ferestrei dialog principale a aplicaţiei
ExempluPO, ca în figura următoare.
Modificarea interfeţei aplicaţiei
 La rularea programului, dialogul va apărea aşa cum apare în editorul
de resurse.
 Acum se poate modifica macheta dialogului prin intermediul
editorului de resurse.
 Pentru adăugarea unui buton în cadrul dialogului ExempluPO se
parcurg următorii paşi:
 1. Înainte de a adăuga butonul, se înlătură controlul etichetă TODO
care apare în centul machetei dialogului ExempluPO.
 Se efectuează un clic pe textul TODO: place dialog controls here; în
jurul textului este afişat un dreptunghi de formatare (figura
următoare).
 Se apasă tasta Delete. Controlul etichetă este înlăturat de pe
macheta dialogului.
Modificarea interfeţei aplicaţiei
 Ştergerea textului implicit din caseta de dialog
Modificarea interfeţei aplicaţiei
 2. Se selectează controlul buton din caseta cu
controale.
 Se deplasează mouse-ul deasupra machetei
dialogului.
 Aflat pe suprafaţa machetei, cursorul mouse-ului
devine o cruce pentru a indica poziţia în care va fi
plasat noul buton.
 Se plasează pointerul (crucea) departe de
butoanele OK şi Cancel şi apoi se efectuează un
clic cu mouse-ul. Astfel se va afişa un nou buton,
etichetat Buttonl, ilustrat în figura următoare.
Modificarea interfeţei aplicaţiei
 Adăugarea unui buton în cadrul casetei de dialog
Modificarea interfeţei aplicaţiei
 3. Pentru, a modifica eticheta butonului, trebuie ca acesta să fie selectat
(încadrat de un dreptunghi de formatare.
 Dacă butonul nu este selectat, se selectează prin efectuarea unui clic pe
suprafaţa sa. Tastaţi Confirma. Odată ce tastaţi, este afişată caseta de
dialog Push Button Properties.
 4. Se tastează IDC_CONFIRMA în cadrul casetei combinate ID din caseta
de dialog Push Button Properties, înlocuind textul implicit
IDC_BUTTON1. Astfel, identificatorul butonului are o semnificaţie mai
evidentă.

 Caseta de dialog Button Properties


 5. După închiderea casetei de dialog Button Properties, eticheta noului
buton din cadrul dialogului idd_ExempluPO__dialog va fi acum
CONFIRMA.
Asocierea de cod cu interfaţa
 Pentru a fi utilizat butonul trebuie să se scrie secvenţa de cod care de
fapt constă decât într-o singură linie.
 Pentru a asocia codul necesar unui buton se parcurg următorii paşi:
1. Se deschide dialogul ExempluPO în cadrul editorului de resurse.
2. Se efectuează un clic cu butonul drept (de la mouse) pe butonul
Confirma de pe suprafaţa dialogului, după care se selectează
opţiunea Events din meniul contextual afişat.Se va deschide
caseta de dialog New Windows Message and Event Handlers
corespunzătoare clasei dialog (figura următoare).
Asocierea de cod cu interfaţa
3. Se va selecta BN_CLICKED din lista New
Windows Messages/Events.
 Se observă că primul element din listă este
selectat în mod implicit.
4. Se efectuează un clic pe butonul Add and Edit. Se
va afişa caseta de dialog Add Member Function,
ilustrată în figura următoare.
 Aici se va da un nume funcţiei din program care va
fi apelată de fiecare dată când caseta de dialog
primeşte mesajul BN_CLICKED pentru butonul
CONFIRMA.
Asocierea de cod cu interfaţa
 Adăugare de cod pentru evenimentul de acţionare a butonului se
poate realiza si facand dublu clic pe butonul CONFIRMA.
Asocierea de cod cu interfaţa
 Funcţia este adăugată ca şi membru al clasei CExempluPODlg.
Această clasă a fost creată şi denumită în mod automat la
crearea proiectului de către AppWizard.

 Funcţia OnBnClickedConfirma poate fi completată cu următorul


cod
 void CExempluPODlg::OnBnClickedConfirma ()
 {
 // TODO: Add your control notification handler code here
 MessageBox(“Multumesc de ajutor!”);
 }

 Prin folosirea funcţiei predefinite MessageBox(), oricând se


efectuează un clic pe butonul Confirma va fi afişat într-o fereastră
mică mesajul “Multumesc de ajutor!”.
Asocierea de cod cu interfaţa
 Atunci când se aduce modificări unui proiect şi dorim să vedem
dacă acestea funcţionează corect, va trebui să se repete
procesul de asamblare şi rulare.
 Se efectuează un clic pe butonul Build sau se selectează Build
ExempluPO.exe din meniul Build sau se apasă F7.
 Astfel se va relua asamblarea fişierului executabil, fiind incluse
toate modificările aduse resurselor sau codului.
 Modificările sunt salvate automat la asamblarea proiectului.
 Visual Studio salvează automat orice fişier modificat înainte de a
începe asamblarea proiectului, astfel că nu mai trebuie să se
salveze fiecare fişier editat.
 Dacă în timpul compilării apar erori, acestea vor fi afişate în
pagina Build a secţiunii Output aşa. cum se vede în partea
inferioară a ferestrei Visual Studio ilustrată în figura următoare.
Asocierea de cod cu interfaţa
 Erorile sunt afişate în pagina build
Asocierea de cod cu interfaţa
 În continuare se efectuează un clic pe butonul Start Debugging sau se
apasă F5.
 Dialogul ExempluPO ar trebui să fie afişat ca în figura următoare.
Asocierea de cod cu interfaţa
 Dacă se efectuează un clic pe butonul Confirma va apare o
fereastră de mesaj, similară cu cea din figura următoare, care
afişează mesajul Multumesc de ajutor!.

 Dacă se efectuează un nou clic asupra butonului Confirma, se va


primi acelaşi mesaj. Aceasta se întâmplă deoarece la fiecare clic
asupra butonului programul accesează aceeaşi funcţie
OnConfirma().
Salvarea şi închiderea proiectului
 Se poate salva un fişier anume în orice moment prin efectuarea
unui clic pe butonul Save .
 Este posibil, în plus, să se salveze toate fişierele specificate
prin efectuarea unui clic pe butonul Save All .
 Salvarea unui proiect nu necesită nici o operaţie.
 Odată ce s-a terminat lucrul cu un proiect, este suficient să se
închidă. Pentru a închide un proiect se selectează Close
Workspace din meniul File sau pur şi simplu se închide Visual
Studio.
Deschiderea unui proiect existent
 Cea mai rapidă modalitate de a redeschide un proiect
este să se apeleze lista Recent Projects and Solutions.
 În acest scop, se efectuează un clic pe meniul File; apoi
se selectează proiectul dorit din cadrul listei Recent
Projects and Solutions.
 Pentru a deschide un proiect care nu figurează în lista
Recent Projects and Solutions, se selectează Open
Project/Solution din meniul File. Pe ecran este afişată
fereastra Open Project, înfăţişată în continuare.
 Se accesează directorul folosit pentru proiectul
ExempluPO. Se selectează din listă fişierul ExempluPO şi
se efectuează un clic pe Open.
 Indiferent de metoda utilizată, proiectul ar trebui să fie
acum deschis, cu titlul său afişat în bara de titlu a
ferestrei Developer Studio. Mediul de lucru va deschide
automat ultimul fişier sursă editat.
Deschiderea unui proiect existent
Deschiderea unui proiect existent
 Aplicaţia
Fereastra spaţiului de lucru ai proiectului

 Fereastra spaţiului de lucra al proiectului este o fereastră andocabilă.


 Există mai multe astfel de ferestre (fereastra Output este una dintre ele), unele
apărând în modul depanare.
 Pentru a comuta între modul liber şi modul andocabil pentru o fereastră, se
efectuează un dublu clic pe bara de titlu a respectivei ferestre.
 Fereastra spaţiului de lucru al proiectului poate fi închisă prin efectuarea unui
clic pe micul buton de închidere aflat în colţul dreapta sus.
 Redeschiderea ferestrei se realizează prin selectarea comenzii Workspace din
meniul View. Toate ferestrele andocabile au comportamente similare.
 Fereastra spaţiului de lucru al proiectului permite vizualizarea proiectul din mai
multe perspective.
 Atunci când este deschis un proiect, în partea inferioară a ferestrei spaţiului de
lucru sunt disponibile doua pagini: ClassView si ResourceView.
 Paginile din partea inferioară a ferestrei împart proiectul în componente logice.
 Se va efectua un clic pe o pagină pentru a vizualiza reprezentarea
corespunzătoare.
 Fiecare reprezentare afişează o structură arborescentă de elemente care
reprezintă componente ale proiectului.
Lucrul cu reprezentarea claselor
 Dacă se efectuează un clic pe eticheta de pagină ClassView va fi
afişată pagina ClassView (reprezentarea claselor).
 Această reprezentare afişează toate clasele folosite în cadrul
proiectului.
 AppWizard a creat aceste clase odată cu crearea iniţială a
proiectului.
 Fiecare element aflat la nivelul secundar (mai puţin elementul
Global) reprezintă o clasă şi afişează numele respectivei clase.
 La expandarea unei clase, fiecare element subordonat reprezintă
fie o funcţie tu, fie o variabilă membru a clasei. De exemplu, în
cadrul CExempluPODlg se poate vedea funcţia membru
OnConfirma().
 Pagina ClassView se dovedeşte de multe ori a fi cea mai utilizată.
De aici se poate accesa orice clasă, orice funcţie membru sau
orice variabilă din proiect.
 Efectuarea unui dublu clic asupra unui element va deschide
fişierul cu cod sursă corespunzător în fereastra editorului, având
cursorul plasat pe linia corespunzătoare elementului în cauză.
Lucrul cu reprezentarea claselor
 Selectarea paginii
ClassView
 Efectuarea unui dublu clic
pe numele unei clase
accesează definiţia clasei.
 Efectuarea unui dublu clic
pe o variabilă membru
accesează definiţia
variabilei.
 Efectuarea unui dublu clic
pe o funcţie membru
accesează începutul
definiţiei funcţiei din cadrul
fişierului care
implementează clasa.
Lucrul cu reprezentarea claselor
 Pe lângă posibilitatea de a naviga printre
clasele din proiect, secţiunea ClassView
oferă şi alte facilităţi prin intermediul
meniurilor contextuale.
 Un meniu contextual este afişat pe ecran
lângă cursorul mouse-ului la efectuarea
unui clic cu butonul drept asupra unui
element.
 Pentru a afişa meniul contextual pentru
un element din arborele de clase, se
selectează respectivul element cu
butonul drept al mouse-ului.
 Elementul în cauză va ii evidenţiat şi
alături de el va fi afişat meniul de
context.
 Meniul contextual afişat depinde de tipul
elementului selectat.
 Dacă efectuăm un clic pe numele clasei
CExempluPODlg se va afişa meniul
contextual al clasei
Lucrul cu reprezentarea claselor
 Meniul contextual permite efectuarea unor operaţii diverse asupra clasei
selectate.
 Selectarea opţiunii Go to Definition are acelaşi efect cu efectuarea unui
dublu clic pe numele clasei, şi anume accesarea fişierului sursă care
conţine definiţia clasei.
 Patru dintre opţiunile meniului sunt folosite pentru adăugarea de funcţii sau
variabile în cadrul clasei.
Lucrul cu reprezentarea
claselor
 Adaugarea unei variabile sau unei functii se face prin selectarea
optiunii ADD.
Lucrul cu reprezentarea claselor
 Adăugarea unei noi variabile
Lucrul cu reprezentarea
claselor

 Va trebui să se specifice tipul, numele şi modul de acces


pentru noua variabilă.
 Se va tasta int în caseta Variable Type şi m__numara în
caseta Variabile Declaration.
 Se va lăsa modul de acces să fie Public. Astfel se creează în
cadrul clasei CExempluPODlg o variabilă de tip întreg numită
m__numara.
 Această variabilă va fi utilizată pentru a reţine de câte ori s-a
efectuat clic asupra butonului Confirma. După introducerea
informaţiile necesare, se efectuează un clic pe OK.
Lucrul cu reprezentarea claselor
 Noua variabilă ar trebui să fie acum afişată în pagina ClassView
ca element subordonat clasei CExempluPODlg.
 În continuare se va efectua un dublu clic pe elementul
m_numara pentru deschiderea fereastrei editorului, cursorul
fiind plasat în linia de cod care a fost adăugată pentru definirea
noii variabile.
 Deoarece această variabilă va reţine de câte ori s-a efectuat clic
asupra butonului Confirma, ea va trebui să aibă valoarea iniţială
zero.
 Locul potrivit pentru iniţializarea variabilei este constructorul
clasei CExempluPODlg.
 Pentru a adăuga codul de iniţializare, se efectuează un clic pe
elementul corespunzător funcţiei membru constructor
CExempluPODlg (acesta fiind primul element subordonat clasei
CExempluPODlg).
 Fereastra editorului va conţine fişierul sursă corespunzător.
Pentru iniţializarea variabilei contor, se va adăuga prezentată în
continuare:
Lucrul cu reprezentarea claselor
 CExempluPODlg::CExempluPODlg(CWnd* pParent /*=NULL*/)
 : CDialog(CExempluPODlg::IDD, pParent)
 {
 //{{AFX_DATA_INIT(CExempluPODlg)
 // NOTE: the ClassWizard will add member
initialization here
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent
DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 m_numara=0;
 }
Lucrul cu reprezentarea claselor
 Variabila m_numara este iniţializată cu zero în constructorul clasei
casetă de dialog.
 Acum numărătoarea începe de la zero; mai departe va trebui să
realizăm incrementarea contorului la fiecare clic asupra butonului
Confirma.
 Se efectuează un dublu clic pe funcţia membru
OnBnClickedConfirma() a clasei CExempluPODlg, vizualizând codul
acesteia.
 Pentru a se incrementa variabila contor, se adauga m_numara++
coform secvenţei de cod următoare:
 void CExempluPODlg::OnBnClickedConfirma()
 {
 // TODO: Add your control notification handler code here
 MessageBox("Multumesc de ajutor!");
 m_numara++;
 }
Lucrul cu reprezentarea claselor
 OnConfirma() este o funcţie pentru tratarea mesajelor care este
apelată de fiecare dată când se efectuează un clic pe butonul
lDC_CONFIRMA.
 Pe lângă afişarea unui mesaj pentru utilizator, funcţia
incrementează o variabilă contor pentru a număra de câte ori a
fost apăsat butonul.
 Variabila contor va reţine numărul de clicuri.
 Următorul pas constă în crearea unei funcţii logice care va trata
situaţiile în care s-a făcut sau nu clic pe butonul Confirma.
 Pentru aceasta se efectuează un clic cu butonul drept pe numele
clasei CExempluPODlg pentru apela meniul contextual.
 Se selectează Add Member Function şi va fi afişată caseta de
dialog Add Member Function. Această casetă de dialog este
folosită pentru adăugarea unei funcţii membru într-o clasă.
Lucrul cu reprezentarea claselor
 Adăugarea unei funcţii membru într-o clasă

 Se va specifica tipul funcţiei BOOL în caseta Function Type şi


numele funcţiei Clicnumara în caseta Function Declaration.
 Dacă noua funcţie necesită parametri, aceştia pot fi introduşi de
asemenea în caseta Function Declaration.
 De asemenea ar trebui ca butonul de opţiune care stabileşte modul
de acces Public să fie selectat, iar casetele de validare Static şi
Virtual trebuie lăsate ambele invalidate. După terminarea operaţiilor
se efectuează clic pe OK.
Lucrul cu reprezentarea claselor
 Noua funcţie ar trebui să apară acum în secţiunea ClassView ca şi
element subordonat clasei CExempluPODlg.
 Corpul acestei funcţii este vizibil în fereastra editorului. În continuare
se adaugă liniile de cod.
 BOOL CExempluPODlg::clicnumara()
 { if (m_numara==0)
 { MessageBox("Nu ai confirmat", "Nu poti termina", MB_ICONSTOP);
 return FALSE; }
 if(m_numara>1)
 { CString str;
 str.Format("Ai confirmat de %d ori", m_numara);
 MessageBox(str);
 }
 else
 { MessageBox("S-a confirmat odata");
 }
 return TRUE;
 }
Lucrul cu reprezentarea claselor
 Funcţia realizată clicnumara este gata,
dar încă nu este folosită nicăieri în
program.
 Pentru a integra funcţia se va deschide
pagina ResourceView de la baza ferestrei
spaţiului de lucra a proiectului, ce fişează
o listă cu resursele din cadrul proiectului.
 Această reprezentare afişează toate
resursele folosite în proiect.
 O Funcţia MessageBox () are mai multe
forme.
 În acest caz este transmis indicatorul
mb_iconstop, ceea ce duce la afişarea
unui semn de stop alături de textul
mesajului.
 Funcţia Format () a clasei Cstring este
utilizată pentru a compune un mesaj
textual care este transmis apoi funcţiei
MessageBox ().
Resurse Visual C++
 Noţiunea de resursă cuprinde elementele vizuale ale unui proiect. De
pildă, casetele de dialog sunt resurse, la fel ca şi meniurile sau
pictogramele.
 Asemeni reprezentării claselor, reprezentarea resurselor afişează un
meniu contextual la efectuarea unui clic cu butonul drept asupra unui
element. Se va selcta Insert din meniul contextual ExempluPO
Resorces. Pe ecran va apărea caseta de dialog Insert Resource.
Resurse Visual C++
 Fereastra spaţiului de lucru al proiecrtului este o fereastră andocabilă.
 Secţiunea ClassView conţine structura de clase ale proiectului iar prin
acţionarea pătratului din faţa numelui unei clase, semnul + se
transformă în – şi are loc expandarea nodului respectiv fiind afişat un
nivel ce descinde din nodul ce conţine numele clasei şi care conţine
toate prototipurile funcţiilor membre ale clasei ca şi variabilele
membre.
 Fişierele dintr-un proiect VisualC++ se împart în :
 Fişiere header - sunt fişiere care conţin partea de implementare a
clasei. În interiorul clasei se vor afla doar declaraţiile metodelor(funcţii
membre ale clasei) şi de asemenea declaraţii ale variabilelor membre
ale clarei. Acestea mai pot conţine şi implementarea unora dintre
funcţiile membru, o astfel de implementare mai poartă numele de
implementare inline a metodelor. Aceste metode vor funcţiona în
momentul când vor fi apelare ca nişte macrouri, adică vor expanda şi
nu vor crea propria stivă în memorie.
 Fişiere sursă - sunt fişiere care includ fişierele header şi conţin
definiţia metodelor declarate în fişierele header.
 Fişiere resursă - sunt fişiere ce conţin resurse ale proiectului
ex:imagini.
Resurse Visual C++
 Secţiunea FileView conţine lista tuturor fişierelor aplicaţiei. Acestea sunt
afişate sub forma unui arbore cu patru noduri care se desprind din
rădăcină.
 Primul dintre acestea, Header Files, conţine fişierele header ale proiectului
şi prin expandarea sa va fi afişat încă un nivel ce conţine toate fişierele de
acest tip.
 Fişierele sursă se vor găsi in nodul cu numele Source File iar fişierele de
resurse se vor găsi în nodul Resource File. Mai există un nod a cărui
expandare va duce la afişarea tuturor fişierelor externe ca noduri fii ale
acestuia şi care are numele External Dependencies.
 Secţiunea ResourceView conţine lista cu resursele folosite în cadrul
proiectului.
 Resursa reprezintă un element vizual al unui proiect. De pildă casetele de
dialog ca şi meniurile sau pictogramele sunt resurse.
 Motivul pentru care resurse de genul meniurilor, al tabelelor de şiruri şi al
casetelor de dialog sunt despărţite de codul sursă este acela că se doreşte
posibilitatea de modificare a acestora independent de acesta.
 Astfel se înlesneşte foarte mult crearea de aplicaţii internaţionale. Spre
exemplu, toate şirurile dintr-o tabelă de şiruri pot fi traduse într-o a doua
limbă, fără a fi modificat codul sursă.
Tipuri de resurse
 Se pot vedea în această casetă diferitele tipuri de resurse care pot
fi utilizate într-un proiect Visual C++.
 O tabelă de acceleratori reprezintă o listă de asocieri între
combinaţii de taste şi comenzi din program.
 O denumire uzuală pentru accelerator este cea de combinaţie de
taste. O combinaţie de taste reprezintă o modalitate mai rapidă de
a executa o comanda decât selectarea acesteia dintr-un meniu.
 O resursă de tip bitmap este o imagine de o dimensiune oarecare
compusă din puncte. Fiecare punct poate avea o culoare distinctă.
Bitmap-urile sunt utilizate pentru afişarea imaginilor care apar pe
barele cu instrumente.
 Un cursor este o resursă de tip imagine. Cursoarele sunt folosite
în principal ca reprezentări ale indicatorului mouse-ului (cursorul
standard din Windows este o săgeata).
 Trăsătura distinctivă a unui cursor este prezenţa unui punct
senzitiv, care este folosit pentru a urmări poziţia acestuia pe ecran.
Tipuri de resurse
 O pictogramă este, de asemenea, o resursă de tip imagine. Proiectul
ExempluPO conţine o pictogramă care se numeşte IDR_MAINFRAME. Dacă
se efectuează un dublu clic pe elementul IDR_MAINFRAME în fereastra
editorului va fi deschisă pictogramă MFC standard.
 O resursă de tip dialog este o machetă de fereastră care poate conţine
celelalte tipuri de resurse, aşa cum sunt meniurile şi butoanele.
 O resursă de tip meniu conţine exact ceea ce sugerează numele său, şi
anume un meniu.
 De regulă, o aplicaţie include un meniu în partea superioară a ferestrei sale
principale (aşa cum este si cazul cu Developer Studio), însă pot exista mai
multe meniuri. De exemplu este posibilă adăugarea într-un proiect a unei
resurse de tip meniu şi utilizarea acesteia ca şi meniu de context.
 O resursă de tip tabelă de şiruri ar trebui să conţină toate şirurile de
caractere folosite într-o aplicaţie.
 Fiecare element are asociat un identificator unic, utilizat pentru a referi
şirul respectiv în cadrul codului sursă.
 Motivul pentru care toate şirurile sunt introduse într-o tabelă de şiruri şi nu
direct în fişierele sursă este înlesnirea traducerii în alte limbi.
 Dacă toate textele utilizate într-o aplicaţie se află într-o tabelă de şiruri, este
posibilă crearea unei a doua tabele intr-o altă limbă.
 După lansarea aplicaţiei este utilizată tabela de şiruri corespunzătoare.
Tipuri de resurse
 O resursă de tip bară cu instrumente conţine o mulţime de
butoane.
 De regulă, fiecare buton reprezintă o comandă de meniu. Pe
suprafaţa butoanelor pot fi desenate imagini sub formă de
bitmap-uri şi fiecare buton poate avea asociată o explicaţie care
va fi afişată atunci când mouse-ul se deplasează deasupra
butonului.
 O resursă de tip versiune conţine informaţii despre aplicaţii, ca
de pildă firma producătoare, numele produsului, un număr de
versiune şi aşa mai departe.
 Aceste informaţii se află într-un format standard care permite
accesarea lor din alte aplicaţii.
 Resurse noi pot fi adăugate în orice moment.
 La creare, fiecare resursă primeşte automat un nume unic. De
exemplu, o nouă machetă de dialog ar putea primi numele
IDD_DIALOG1.
Tipuri de resurse
 Caseta de dialog Resource Symbols
Tipuri de resurse
 Programatorii înlocuiesc de obicei numele generate automat cu
nume de resurse mai sugestive pentru contextul programului,
aşa cum s-a făcut când s-a locuit numele IDC_BUTTON1 cu
IDC_CONFIRMĂ.
 Pentru a afişa numele tuturor resurselor din proiect, se va
selecta Resource Syjmbols din meniul View.
 Va fi afişată caseta de dialog Resource Symbols.
 Se poate utiliza caseta de dialog Resource Symbols pentru a
identifica o resursă anume pe numelui său simbolic prin
selectarea numelui în cadrul listei şi efectuarea unui clic pe
butonul View Use.
 Fiecare resursă din cadrul proiectului poate fi editată prin
efectuarea unui dublu clic pe numele acesteia din secţiunea
ResourceView.
 Instrumentele şi opţiunile disponibile în fereastra editorului se
modifică în concordanţă cu tipul resursei editate.
Tipuri de resurse
1. Prin intermediul secţiunii Resource View se parcurg paşii următori:
2. Se efectuează dublu clic pe elementul IDD_ExempluPO_DIALOG
pentru a deschide macheta dialogului.
3. Se efectuează dublu clic pe butonul OK şi se afişează caseta de dialog
Add Member Function. Se acceptă numele implicit al funcţiei membru
OnOK. Se va afişa scheletul noii funcţii în fereastra editorului.
 Se edita funcţia OnOk conform secvenţei de cod următoare
 void CExempluPODlg::OnOK()
 {
 // TODO: Add extra validation here
 if(clicnumara()==TRUE)
 {

 CDialog::OnOK();
 }
 }
Tipuri de resurse
4. Se va efectua dublu clic pe elementul IDD_ExempluPO_DIALOG
pentru a deschide din nou macheta dialogului.
5. Se efectuează dublu clic pe butonul Cancel.
6. Se efectuează un clic pe OK pentru a acepta numele implicit al
funcţiei membru: OnCancel
7. Se editează funcţia implicită OnCancel conform secvenţei de cod
următoare
 void CExempluPODlg::OnCancel()
 {
 // TODO: Add extra cleanup here
 if (clicnumara()==TRUE)
 {
 CDialog::OnCancel();
 }
 }
Tipuri de resurse
 Acum aplicaţia poate fi asamblată şi rulată.
 Dacă se încearcă ieşirea din program fără confirmare este afişat
mesajul următor:

 Dacă se apasă butonul confirmă este afişat mesajul următor.


Tipuri de resurse
 După ce este apăsat butonul confirmă se poate ieşi din program şi
se afişează numărul de confirmări.

S-ar putea să vă placă și