Document, comentariu, eseu, bacalaureat, liceu si facultate
Top documenteAdmitereTesteUtileContact
      
    


 


Ultimele referate adaugate

Adauga referat - poti sa ne ajuti cu un referat?

Politica de confidentialitate



Ultimele referate descarcare de pe site
  CREDITUL IPOTECAR PENTRU INVESTITII IMOBILIARE (economie)
  Comertul cu amanuntul (economie)
  IDENTIFICAREA CRIMINALISTICA (drept)
  Mecanismul motor, Biela, organe mobile proiect (diverse)
  O scrisoare pierduta (romana)
  O scrisoare pierduta (romana)
  Ion DRUTA (romana)
  COMPORTAMENT PROSOCIAL-COMPORTAMENT ANTISOCIAL (psihologie)
  COMPORTAMENT PROSOCIAL-COMPORTAMENT ANTISOCIAL (psihologie)
  Starea civila (geografie)
 

Ultimele referate cautate in site
   domnisoara hus
   legume
    istoria unui galban
   metanol
   recapitulare
   profitul
   caract
   comentariu liric
   radiolocatia
   praslea cel voinic si merele da aur
 
despre:
 
Concepte de baza ale limbajului C++
Colt dreapta
Vizite: ? Nota: ? Ce reprezinta? Intrebari si raspunsuri
 
Modalitatile (tehnici, paradigme) de programare au evoluat de-a lungul anilor, reflectand trecerea de la programe de dimensiuni reduse la programe si aplicatii de dimensiuni foarte mari, pentru coordonarea carora sunt necesare tehnici evoluate. j3l4lk
Software-ul de dimensiuni mari, care nu poate fi realizat de o singura persoana, intra in categoria sistemelor complexe, alaturi de alte sisteme complexe din cele mai variate domenii, cum sunt organizarea materiei sau organizarile sociale.
Situatiile reale si experiente ale psihologilor au relevat limitele capacitatii umane in perceptia sistemelor complexe, adica imposibilitatea unei persoane de percepe si controla un numar mare de entitati de informatie simultan. De aceea, descompunerea si organizarea sistemelor complexe, in scopul de putea fi percepute, proiectate sau conduse este esentiala. Ordinea in sistemele complexe este introdusa in general printr-o organizare ierarhica, pe mai multe tipuri si nivele de ierarhie. In reprezentarea ierarhica a sistemelor complexe se evidentiaza doua tipuri de ierarhii: ierarhia structurala sau de compozitie si ierarhia de tip.
Ierarhia structurala este o ierarhie in care se poate afirma despre un obiect ca este o parte a altui obiect, mai complex. Exemple de astfel de descompuneri se pot da oricate, din orice domeniu. De exemplu, un calculator poate fi studiat prin descompunerea lui in subansamble componente: placa de baza, placa video, monitor, etc; la randul ei, placa de baza este compusa din placheta de circuit imprimat, procesor, memorie, etc. Aceasta este o ierarhie de tipul “este o parte din…”.
Pe de alta parte, fiecare obiect poate fi incadrat intr-o categorie (clasa, tip) mai larga, care contine mai multe obiecte care au proprietati comune. De exemplu, procesorul este de o componenta electronica; monitorul este un dispozitiv de afisare, etc. Aceasta ierarhie se refera la apartenenta obiectelor la o anumita clasa (sau tip - “este de tipul…”).
Este esential de a privi sistemele complexe din ambele perspective, studiindu-le atat din perspectiva ierarhiei structurale, deci a obiectelor care le compun, cat si a ierarhiei de tip, deci a claselor carora le apartin. La randul lor, clasele din care fac parte obiectele pot fi organizate sau studiate ca elemente componente ale unei ierarhii, prin care o clasa este considerata ca primitiva (parinte) a unei alte clase. Cele doua tipuri de ierarhii, ierarhia de clase si ierarhia de obiecte nu sunt independente, si, impreuna, pot sa reprezinte un sistem complex.
La fel ca oricare sistem complex, software-ul poate fi controlat prin descompunerea lui. Rolul descompunerii unui sistem in general (si al programelor in special) este de a permite intelegerea si manevrarea acestuia: sistemul este descompus in parti din ce in ce mai mici, fiecare dintre ele putand fi rafinata si dezvoltata independent. Principiul “divide-et-impera”, care se aplica in multe situatii, este util si in programare.




Se pot identifica doua tipuri de descompunere a programelor: descompunerea algoritmica si descompunerea orientata pe obiecte.
Descompunerea algoritmica permite abordarea structurata a programarii. Programul este impartit in module, in functie de actiunile pe care trebuie sa le efectueze, fiecare modul se imparte in elemente functionale (blocuri, proceduri, functii), intr-o structurare de sus in jos (top-down), care urmareste diagrma de trecere a datelor in cursul executiei.
Descompunerea orientata pe obiecte este o alternativa de descompunere prin care programul se descompune dupa obiectele care pot fi identificate, fiecare obiect avand asociate o multime de operatii care sunt apelate in cursul desfasurarii programului.
O problema nu poate fi abordata simultan prin ambele metode; se alege fie una, fie cealalta metoda. Care dintre ele este cea mai buna? Nu exista un raspuns absolut si universal valabil, dar experienta a dovedit ca pentru sisteme de dimensiuni mari, descompunerea orientata pe obiecte este mai eficienta, mai sigura si mai flexibila.

1.1 Tehnici de programare

Modul in care este abordata programarea din punct de vedere al descompunerii programelor defineste mai multe tehnici de programare (paradigme), care s-au dezvoltat si au evoluat odata cu evolutia sistemelor de calcul.

Programarea procedurala este prima modalitate de programare care a fost si este inca frecvent folosita. In programarea procedurala accentul se pune pe descompunerea programului in proceduri (functii) care sunt apelate in ordinea de desfasurare a algoritmului. Limbajele care suporta aceasta tehnica de programare prevad posibilitati de transfer a argumentelor catre functii si de returnare a valorilor rezultate. Limbajul Fortran a fost primul limbaj de programare procedurala. Au urmat Algol60, Algol68, Pascal, iar C este unul din ultimile inventii in acest domeniu.

Programarea modulara. In cursul evolutiei programarii procedurale accentul in proiectarea programelor s-a deplasat de la proiectarea procedurilor catre organizarea datelor, aceasta deplasare reflectand cresterea dimensiunilor programelor. O multime de proceduri corelate, impreuna cu datele pe care le manevreaza sunt organizate ca un modul. Tehnica de programare modulara decide descompunerea unui program in module, care incorporeaza o parte din datele programului si functiile care le manevreaza. Aceasta tehnica este cunoscuta ca tehnica de ascundere a datelor (data-hiding). In programarea modulara stilul de programare este in continuare procedural si nu exista o asociere stricta intre date si procedurile care opereaza asupra acestora, ci doar gruparea in module cu posibilitatea de a ascunde anumite informatii (date, nume de variabile, functii) definite intr-un modul, fata de celelate module.
Modularitatea si ascunderea informatiilor sunt caracteristici implicite in programarea orientata pe obiecte.

Programarea orientata pe obiecte reprezinta aplicarea in domeniul programarii a unei metode larg raspandite in tehnica, numita tehnologia orientata pe obiecte, care se bazeaza pe modelul obiect. Modelul obiect al unei aplicatii implica patru principii importante si anume:
• abstractizare;
• incapsularea;
• modularitate;
• ierarhie (mostenire).
In afara acestor principii, modelul obiect mai presupune: tipizare, concurenta si persistenta. Aproape nici unul dintre aceste principii nu este nou, dar utilizarea lor impreuna in modelul obiect, are un rol sinergetic, de potentare reciproca.
Primele aplicatii ale acestor principii au fost introduse in limbajul Simula, care a stat la baza dezvoltarii ulterioare si a altor limbaje care permit abordarea modelului obiect: Smaltalk, Object Pascal, C++, Clos, Ada, Eifel.
In momentul de fata, modelul obiect se dovedeste a fi un concept unificator in stiinta calculatoarelor in general, fiind aplicabil nu numai in programare, ci si in arhitectura calculatoarelor, in proiecatarea interfetelor utilizator, in baze de date.

Programarea orientata pe obiecte-POO- (object-oriented programming) este o metoda de programare in care programele sunt organizate ca si colectii de obiecte cooperante, fiecare dintre ele reprezentand o instanta a unei clase oarecare, iar clasele sunt membre ale unei ierarhii de clase, corelate intre ele prin relatii de mostenire.

Exista trei parti importante ale acestei definitii:
• Se folosesc obiecte, nu algoritmi ca unitati constructive de baza, obiectele fiind componente ale unei ierarhii structurale.
• Fiecare obiect este o instanta (un exemplar) al unei clase.
• Clasele sunt componente ale unei ierarhii de tip (“este de tipul…”), fiind corelate intre ele prin relatii de mostenire.
Daca lipseste una din aceste caracteristici, programarea nu se mai numeste orientata pe obiecte, ci programare prin abstactizarea datelor, deoarece o clasa este un tip de date abstract (sau programare bazata pe obiecte).
Un limbaj este considerat un limbaj de programare orientata pe obiecte daca satisface mai multe cerinte, ca de exemplu:
• Suporta obiecte (instante ale unor clase), clasele fiind tipuri definite de utilizator (numite si tipuri abstracte de date).
• Tipurile (clasele) pot mosteni atribute de la alte clase, numite clase de baza.
Daca un limbaj nu suporta direct mostenirea intre clase se numeste limbaj de programare bazat pe obiecte (object-based), cum este, de exemplu, limbajul Ada.
Principiile modelului obiect aplicate in programare, enuntate mai sus, vor fi prezentate pe scurt in continuare, detalierea lor fiind reluata in cursul expunerii, dupa descrierea suportului oferit de limbajul C++ fiecareia dintre acestea.
Abstractizarea inseamna identificarea similitudinilor intre diferite entitati, situatii sau procese din lumea reala si decizia de a se concentra atentia asupra acestor aspecte comune si ignorarea pentru inceput a celorlate aspecte. Abstractizarea denota caracteristicile esentiale ale unui obiect, care il deosebeste de toate celelalte feluri de obiecte.
Incapsularea este procesul de compartimentare a elementelor unei abstractizari in doua parti: structura si comportarea; incapsularea separa comportarea (accesata prin interfata) de structura, definita prin implementare. Incapsularea prevede granite intre diferite abstractizari, ceea ce conduce la o separare clara a acestora.
Modularizarea este procesul de partitionare a unui program in componente individuale (module) ceea ce permite reducerea complexitatii programului prin definirea unor granite bine stabilite si documentate in program. In practica programarii, modularitzarea consta in partitionarea programului in module care pot fi compilate separat, dar care au conexiuni cu alte module ale programului. Modulele servesc ca si containere in care sunt declarate clasele si obiectele programului.
Ierarhia este o modalitate de a ordona abstactizarile (tipurile abstacte de date).
Ierarhiile denota o relatie de tip. De exemplu, un trandafir este o floare (“un tip” de floare), algoritmul quicksort este un algoritm de sortare, etc. Ierarhiile definesc relatii intre clase prin care o clasa (clasa derivata) partajeaza structura sau comportarea definita in alta clasa (clasa de baza).
Tipizarea (typing). Tipul este o caracterizare precisa, structurala si comportamentala a unei colectii de entitati. Desi conceptul tipul este similar conceptului de clasa, tipizarea se refera la un element diferit al modelului obiect de cat cel la care se refera clasele. Tipizarea este o accentuare a clasei unui obiect, astfel incat obiecte de clase diferite nu pot fi intershimbate intre ele sau, cel mult, pot fi interschimbate intr-un mod foarte restrictiv. Din punct de vedere a tipizarii, exista limbaje puternic tipizate (ca de exemplu, Eiffel), in care nu este admisa nici o operatie asupra unui operand daca aceasta nu a fost exact prevazuta pentru obiectul respectiv. Alte limbaje, cum este Smalltalk, sunt limbaje netipizate, care admit la compilare orice fel de operatii asupra operanzilor, eroarea violarii de tip manifestandu-se in timpul executiei. Limbajul C++ este hibrid. El are tendinta de tipizare puternica, dar este posibila ignorarea sau inhibarea regulilor de tipizare. Desi nu face parte din principiile fundamentale ale modelului obiect, tipizarea aduce beneficii importante in progrmarea obiect orientata.
Concurenta permite ca mai multe obiecte diferite sa fie in executie in acelasi timp. Sistemele care implica concurenta sunt sisteme cu procesoare multiple, in care mai multe procese sau thread-uri (fire de executie) pot fi executate concurent pe procesoare diferite.
Persistenta. Un obiect in software ocupa un anumit spatiu in memorie si are o existenta intr-o perioada determinata de timp din timpul de executie al programului. De multe ori este necesar ca datele sa “supravietuiasca” programului (exemplul tipic fiind bazele de date), iar definirea de catre fiecare programator a modului cum sunt salvate datele pentru a fi pastrate dupa terminarea programului poate conduce catre scheme de memoare dintre cele mai diferite si greu de a fi utilizate interschimbabil. Prin conceptul de persistenta se introduce un mod unitar de salcare si restaurare a datelor continute de obiecte ale programului.

Modelul obiect in domeniul programarii implica, pe langa implementarea programului intr-un limbaj anume, etape premergatoare de analiza si proiectare care pregatesc structurarea efectiva a programului.

Analiza orientata pe obiecte este o metoda de analiza si examinare a unei aplicatii din perspectiva claselor si a obiectelor din domeniul problemei respective.

Proiectarea orientata pe obiecte este o metoda de proiectare a sistemelor care implica descompunerea orientata pe obiecte si asigura o modalitate de reprezentare atat statica cat si dinamica a modelului sistemului proiectat.

Produsele unei analize orientate pe obiecte servesc ca modele ale proiectarii orientate pe obiecte, iar rezultatele acesteia folosesc direct in programarea orientata pe obiecte. Ca suport al modelului final, orientat pe obiecte al unei aplicatii, programarea si limbajele orientate pe obiecte sunt acelea care se recomanda a fi studiate mai intai, pentru a beneficia de toate facilitatile si tehnicile puse la dispozitie prioectantilor, analistilor si programatorilor.

Dintre limbajele de programare orientate pe obiecte, limbajul C++ este unul dintre cele mai utilizate; compilatoare, biblioteci si instrumente de dezoltare a programelor C++ sunt disponibile atat pentru calculatoare personale cat si pentru cele mai dezvoltate sisteme si statii de lucru.
Limbajul C++ este o versiune extinsa a limbajului C, extensiile acestuia fiind elaborate de catre Biarne Stroustrup in anul 1980 in laboratoarele Bell din Murray Hill, New Jersey. Extensiile dezvoltate de Stroustrup pentru limbajul C++ permit programarea orientata pe obiecte, pastrand eficienta, flexibilitatea si conceptia de baza a limbajului C. Numele initial a fost “C cu clase”, numele de C++ fiindu-i atribuit in anul 1983.
Scopul pentru care a fost creat C++ este acelasi cu scopul pentru care este abordata in general programarea orientata pe obiecte: dezvoltarea si administrarea programelor foarte mari. Chiar daca necesitatea si superioritatea limbajului C++ este evidenta in cazul dezvoltarii programelor foarte mari, nu exista limitari in a fi folosit in orice fel de aplicatii, datorita faptului ca C++ este un limbaj tot atat de eficient ca si limbajul C.
De la aparitia sa, C++ a trecut prin trei revizii, in 1985, 1989 si ultima, prilejuita de definirea standardului ANSI pentru acest limbaj. O prima versiune a standardului a fost publicata in anul 1994, iar urmatoarea versiune este inca in lucru.

In general, limbajul C++ prevede mai multe facilitati si mai putine restrictii decat limbajul C, astfel incat majoritatea constructiilor din C sunt legale si au aceeasi semnificatie si in C++.
In acest capitol sunt prezentate unitar si concis conceptele de baza in programarea C++, atat cele care sunt preluate din limbajul C cat si cele nou introduse. Multe dintre ele sunt reluate si dezvoltate pe parcursul sectiunilor urmatoare.

Cel mai scurt program C++ este: main()A S
Acesta defineste o functie numita main (), care nu primeste nici un argument, nu executa nimic si nu returneaza nici o valoare.
Daca se doreste ca programul sa scrie un mesaj la consola (de tipul Hello, World!), pe langa utilizarea functiei obisnuite din limbajul C (functia printf()), in C++ se poate utiliza si o functie de scriere la iesirea standard (cout). Aceasta functie este functia operator de scriere << care este definita in fisierul antet iostream.h. Un astfel de program este urmatorul:

#include <iostream.h> void main()A cout << “Hello, World!”<< endl;
S

Prima operatie de scriere afiseaza la consola sirul Hello, World!, iar urmatoarea (endl) introduce caracterul de linie noua. Operatia de citire de la tastatura poate fi realizata in C++ printr-o instructiune care foloseste functia operator de citire >>. De exemplu, in instructiunile care urmeaza se citeste de la tastatura un numar intreg:

int i; cin >> i;

Desigur, functia scanf() de citire de la tastatura din limbajul C poate fi in continuare folosita, dar pe parcursul exemplificarilor se vor folosi mai mult aceste functii C++ de citire si de scriere la consola, iar descrierea detaliata a operatiilor de intrare-iesire din C++ este prezentata in sectiunea 6.

Un program C++ consta dintr-unul sau mai multe fisiere (files). Un fisier este o bucata de text care contine cod sursa C++ si comenzi de preprocesare si este translatat din punct de vedere conceptual in mai multe faze. Prima faza este faza de preprocesare care executa includerea altor fisiere si substituirea macro-urilor. Preprocesarea este controlata prin intermediul directivelor introduse prin linii care au primul caracter #. Rezultatul preprocesarii este secventa de entitati (token -; semne). O astfel de secventa de entitati, adica un fisier rezultat dupa preprocesare, se numesste unitate de translatare (translation unit).

1.2 Conventii lexicale

Exista cinci tipuri de entitati: identificatori (identifiers), cuvinte-cheie (keywords), literale (literals), operatori (operators) si separatori (separators). Caracterele: spatiu (blank), tabulatori orizontali si verticali (tabs), linie noua (new line), caractere de formatare (formfeeds) si comentariile, numite in ansamblu spatii albe (white spaces) sunt ignorate cu exceptia situatiei cand folosesc pentru separarea entitatilor. Un spatiu alb este necesar pentru separarea identificatorilor, a cuvintelor-cheie si a constantelor.

Comentariile din C, considerate intre perechile de caractere /* si */ sunt valabile la fel, fara posibilitatea de a fi incluse unele in altele (imbricate). Caracterele // marcheaza inceputul unui comentariu care dureaza pana la sfarsitul liniei.

Identificatori. Un identificator este o secventa de lungime oarecare de litere si cifre, cu conditia ca primul caracter sa fie litera sau caracterul de subliniere _ (underscore). Literele mici sunt diferite de literele mari corespunzatoare. Toate caracterele intr-un identificator sunt semnificative.

Cuvinte-cheie. Urmatorii identificatori sunt rezervati pentru a fi utilizati ca si cuvinte-cheie, si nu pot avea alta utilizare:

asm continuos float new signed try auto default for operator sizeof typedef break delete friend private static union case do goto protected struct unsigned catch double if public switch virtual char else inline register template void class enum int return this volatile const extern long short hrow while

In plus, identificatori care contin doua caractere de subliniere (underscore) sau incep cu un astfel de caracter sunt utilizati in implementarile C++ si a bibliotecilor si se recomanda sa fie evitati.

Literale (constante). Constantele se refera la valori fixe, pe care programul nu le poate modifica. Exita mai multe feluri de constante: constante intregi, constante caracter, constante reale si constante sir de caractere.
O constanta intreg este reprezentata ca o succesiune de cifre; ea este considerata in baza zecimala daca prima cifra este diferita de 0, in baza hexazecimala daca incepe cu 0x sau 0X, sau in baza octala, daca incepe cu 0 (si acesta nu este urmat de x sau X). Tipul unei constante intregi depinde de valoarea acesteia si este astfel stabilit incat sa poata cuprinde valoarea data.
O constanta caracter este compusa din unul sau mai multe caractere cuprinse intre ghilimele simple (de exemplu, ’x’). O constanta de un singur caracter este de tipul char. Constantele multicaracter au tipul intreg. Trebuie remarcata diferenta fata ce limbajul C, in care constantele caracter au tipul int.
O constanta reala (flotanta) este alcatuita dintr-o parte intreaga, punctul zecimal, o parte fractionara si optional, un exponent intreg cu semn precedat de caracterul e sau E. Fie partea intraga, fie partea fractionara, (dar nu amandoua) poate lipsi. Tipul constantei flotante este duble, daca nu contine un sufix care sa specifice explicit tipul (f sau F, pentru float; l sau L pentru long double).
O constanta sir de caractere este o secventa de caractere cuprinsa intre ghilimele duble si este de tipul vector de caractere. O constanta sir de caractere are clasa de memorare static si se initializeaza cu caracterele date, la care se adauga caracterul ‘\0’ (care are valoarea 0).
Este de asemenea posibil sa fie definite constante simbolice (constante cu nume). Acestea sunt prezentate in subsectiunea urmatoare.

1.3 Declaratii, definitii

Un nume (name) poate reprezenta un obiect, un tip, o enumeratie, o functie, o multime de functii, un membru al unei clase, o valoare sau o eticheta. Un nume este introdus in program printr-o declaratie (declaration). Un nume poate fi folosit numai intr-o zona a programului, denumita domeniul numelui (scope).
Un obiect (object) este o regiune de memorie, iar semnificatia valorilor care se afla memorate intr-un obiect depind de tipul lui. Orice obiect are o durata de viata (lifetime) care depinde de clasa de memorare careia ii apartine.
O declaratie (declaration) introduce unul sau mai multe nume intr-un program. Intr-o declaratie a unui nume se poate introduce, optional, o expresie de initialzare (initializator) pentru acel nume (de exemplu: int i = 1;)
O definitie (definition) stabileste entitatea la care se refera numele respectiv. Ea rezerva cantitatea necesara de memorie obiectului respectiv si executa initializarile corespunzatoare. O declaratie este si o definitie, cu exceptia urmatoarelor situatii:

• contine specificatorul extern fara o expresie de initializare sau corp al functiei;
• este o declaratie a unei functii fara specificarea corpului acesteia;
• este o declaratie a numelui unei clase;
• este o declaratie typedef;
• este o declaratie a unui membru de tip static al unei clase.

De exemplu, urmatoarele sunt definitii:

int a; extern const c = 1; int f(int x) Areturn x+1;S enum Aup, downS;

in timp ce urmatoarele sunt doar declaratii:

extern int a; extern const c; int f(int); struct S; typedef int Int;

Trebuie sa existe o singura definitie a fiecarui obiect, functie, clasa sau enumeratie folosita in program. Daca o functie nu este niciodata apelata sau daca numele unei clase nu este niciodata folosit intr-un mod care sa necesite definitia acesteia, ele pot sa nu fie definite. O declaratie poate fi repetata de mai multe ori in program, in timp ce definitiile nu pot fi repertate. De exemplu:

struct S; // corect, redeclarare struct S; // corect, redeclarare int a; int a; // eroare, redefinire

Domeniul de definitie (scope) al unui nume este zona din program in care numele este cunoscut si poate fi folosit. Dat fiind ca un nume este facut cunoscut printr-o declaratie, domeniile numelor se diferentiaza in functie de locul in care este introdusa declaratia in program. Exista patru categorii de domenii: local, functie, clasa si fisier.
Domeniul local: un nume declarat intr-un bloc (o secventa de instructiuni cuprinsa intre doua acolade) este local blocului si poate fi folosit numai in acel bloc, incepand din locul declaratiei si pana la sfarsitul bocului si in toate blocurile incluse dupa punctul de declaratie. Argumentele formale ale unei functii sunt tratate ca si cand ar fi declarate in blocul cel mai exterior al functiei repective.
Domeniul functie: un nume declarat intr-o functie poate fi folosit in functia respectiva, incepand din punctul de declaratie si pana la sfarsitul blocului in care se afla declaratia. Domeniul functie poate fi considerat un cay particula de domeniu local.
Domeniul clasa: Un nume al unui membru al unei clase este local clasei respective. Posibilitatile de utilizare al acestor tipuri de nume vor fi prezentate ulterior.
Domeniul fisier: Un nume declarat in afara oricarui bloc sau clasa are ca domeniu fisierul in care a fost declarat si poate fi utilizat din punctul declaratiei pana la sfarsitul fisierului. Numele cu domeniu fisier se numesc globale.

Domeniu de vizibilitate. Un nume este vizibil in intregul sau domeniu de definitie daca nu este redefinit intr-un bloc inclus in domeniul respectiv. Daca intr-un bloc interior domeniului unui nume se redefineste (sau se redeclara) acelasi nume, atunci numele initial (din blocul exterior) este partial ascuns, si anume in tot domeniul redeclararii. De exemplu:

void fv1()
A int i = 10; // definitie variabila i
A
// in acest bloc var. i din blocul exterior
// este ascunsa datorita redefinirii int i = 100; cout << i << endl; // afiseaza 100
S cout << i << endl; // afiseaza 10
S

Un nume cu domeniu fisier poate fi accesat intr-un domeniu in care este ascuns prin redefinire, daca se foloseste operatorul de rezolutie pentru nume globale (operatorul :: fara nici un nume in fata lui).
Redefinirea unui nume este admisa numai in domenii diferite. Daca unul din domenii este inclus in celalalt domeniu, atunci redefinirea provoaca ascunderea numelui din domeniul exterior in domeniul interior. Redefinirea in domenii identice produce eroare de compilare.

Durata de viata a obiectelor. Un obiect este creat atunci cand se intalneste definitia lui (care este unica) si este distrus (in mod automat) atunci cand se paraseste domeniul lui de definitie. Un obiect cu un nume global se creaza si se initializeaza o singura data si are durata de viata pana la terminarea programului. Obiectele locale se creaza de fiecare data cand executia programului ajunge in punctul de definire a acestora, cu exceptia variabilelor locale declarate de tip static.
O variabila (obiect) se declara de tip static prin prefixarea declaratiei acesteia cu cuvantul-cheie static. De exemplu, executia programului:

#include <iostream.h> int a = 0; // variabila globala, se initializeaza
// inainte de inceperea executiei void f()A int b = 1; // se creaza si se initializeaza
// la fiecare apel al functiei f() a++; b++; static int c = a; //se initializeaza o singura data
//la prima executie a instruct. c += 2; cout << “a = “<<a <<” b = “<< b<<” c =”<< c<<endl;
S

void main ()A for (int i=0;i<3;i++) f();
S

produce mesajele:

a = 1 b = 2 c = 3 a = 2 b = 2 c = 5 a = 3 b = 2 c = 7

O variabila (obiect) globala sau statica, care nu este initializata explicit, este initializata automat cu 0.
In afara acestui mod de creare a obiectelor, se mai pot crea obiecte in memoria libera (heap), a caror durata de viata este controlata explicit folosind functii sau operatori de alocare. Acest mod de creare a obiectelor este prezentat in subsectiunea 2.4.

Categorii de memorare. Exista patru specificatori de categorii de memorare a obiectelor: auto, static, register, extern.
Obiectele care sunt declarate automatice (folosind specificatorul auto la inceputul declaratiei) sunt obiecte locale (declarate intr-un bloc) care se initializeaza la fiecare invocare a blocului. Utilizarea acestui specificator este redundanta si rareori este folosita.
O declaratie register este o declaratie auto care mai indica in plus compilatorului faptul ca acel obiect este intens folosit si, ca urmare, compilatorul va incerca sa-i aloce spatiu de memorare intr-un registru al procesorului.
Un obiect global poate fi declarat o singura data intr-unul din fisierele programului. Pentru a fi cunoscut si in alte fisiere din program, in celelate fisiere se declara acel obiect folosind specificatorul extern.
Un obiect declarat folosind specificatorul static este memorat permanent si nu este initializat decat o singura data. Un astfel de obiect nu este cunoscut decat in interiorul fisierului sau functiei in care este declarata si nu poate fi declarat extern. Se pot remarca cele doua semnificatii ale specificatorului static: o semnificatie se refera la domeniul de vizibilitate, pe care il restrange la nivel de functie, respectiv fisier; cealalta semnificatie se refera la clasa de memorare si asigura o memorare permanenta a obiectului si o durata de viata egala cu durata de executie a programului.
Aceasta dubla actiune a specificatorului static diferentiaza comportamentul unui obiect declarat static dupa domeniul lui de definitie.
Astfel, un obiect global de tip static este memorat permanent, dar este cunoscut numai in fisierul in care a fost declarat. In aceasta situatie, specificatorul static are doar rolul de a restrange demeniul de vizibilitate al obiectului.
Pentru un obiect local specificatorul static are rolul de a modifica clasa de memorare: obiectul are domeniu de definitie local (este cunoscut numai in blocul in care a fost declarat), dar este memorat permanent si isi pastreaza valorile intre invocari succesive ale blocului respectiv.

1.4 Tipuri

Fiecare nume intr-un program C++ are un tip asociat lui, care determina ce operatii se pot aplica entitatii la care se refera acest nume.
Un nume folosit pentru a specifica tipul unui alt nume intr-o declaratie este un nume de tip. Singurele operatii care se pot aplica unui nume de tip sunt: sizeof, (care determina cantitatea de memorie necesara memorarii unuii obiect de acel tip) si new (operatia de alocare in memoria libera a unui obiect de tipul respectiv).

1.4.1 Tipuri fundamentale

In C++ sunt definite urmatoarele tipuri fundamentale:

• Tipuri de intreg, pentru definirea numerelor intregi de diferite dimensiuni (ca numar de octeti ocupati in memorie):

char 1 octet short int 2 octeti int 2 sau 4 octeti long 4 sau 8 octeti

• Tipuri de numere flotante, pentru definirea numerelor reale (reprezentate ca numere cu virgula flotanta):

float 4 octeti double 8 octeti long double 12 sau 16 octeti

Aceste tipuri sunt denumite impreuna tipuri aritmetice. Pentru tipurile intreg, exista variante de declaratie cu semn (signed) si fara semn (unsigned).

• Tipul void specifica o multime vida de valori. Nu se poate declara un obiect cu acest tip, dar acest tip poate fi utilizat in conversii de pointeri si ca tip de returnare a unei functii

1.4.2 Tipuri derivate

Se pot defini conceptual un numar infinit de tipuri derivate pornind de la tipurile fundamentale. Tipurile derivate sunt:

• tablouri de obiecte,
• pointeri la obiecte,
• referinte,
• functii,
• constante,
• clase, structuri, uniuni,
• pointeri la membrii claselor.

In continuare se vor prezenta primele cinci tipuri derivate, iar celelate vor fi introduse pe parcursul sectiunii urmatoare. Ca terminologie, clasele (impreuna cu structurile si uniunile) sunt denumite tipuri definite de utilizator (user-defined types), iar celelate tipuri sunt denumite tipuri predefinite (built-in types)

1.4.2.1 Tablouri de obiecte

Un tablou (array) de obiecte poate fi construit din obiecte dintr-un tip fundamental (cu exceptia tipului void), din pointeri, din enumeratii sau din alte tablouri. In traducere, pentru array se mai intalnesc termenii vector si matrice. In acest text sunt folositi termenii tablou (pentru array multidimensional) si vector (pentru array unidimensional).
Declaratia: T Daexpresiei introduce un tablou de obiecte de tipul T, cu numele D si cu un numar de elemente al tabloului dat de valoarea expresiei, care trebuie sa fie de tip constant intreg. Pentru valoarea N a acestei expresii, tabloul are N elemente, numerotate de la 0 la N-1.
Un tablou bidimensiunal se poate construi printr-o declaratie de forma:
T Dadim1iadim2i; si reprezinta dim1 tablouri unidimensionale, fiecare de dimensiune dim2. Elementele tabloului bidimensional se memoreaza cu valori succesive pentru indicele din dreapta astfel:
Da0ia0i, Da0ia1i, … Da0iadim2-1i,
Da1ia0i, Da1ia1i, … Da1iadim2-1i,……….
Dadim1-1ia0i, Dadim1-1ia1i,… Dadim1-1iadim2-1i.

Intr-un mod asemanator se pot construi tablouri multidimensionale, cu o limitare a numarului de dimensiuni care depinde de impelementare.

1.4.2.2 Pointeri


Pentru majoritatea tipurilor T, T* este un tip denumit “pointer la T”, adica o variabila de tipul T* memoreaza adresa unui obiect de tipul T.
Operatia fundamentala asupra unui pointer este operatia de dereferentiere (dereferencing), adica accesarea obiectului a carui adresa o reprezinta pointerul respectiv. Operatorul de dereferentiere este operatorul unar *. De exemplu:

char c1 = ‘a’; char* p1 = &c1; // p memoreaza adresa lui c1 char c2 = *p1; // dereferentiere, c2 = ‘a’;

Operatorul & este operatorul adresa, care se utilizeaza pentru a se obtine adresa unei variabile.
Tipul void* este folosit pentru a indica adresa unui obiect de tip necunoscut.
Asupra pointerilor sunt admise unele operatii aritmetice. Ca exemplu, se considera un vector de caractere dintre care ultimul este caracterul 0 (se mai numeste sir de caractere terminat cu 0). Pentru calculul numarului de caractere se pot folosi operatii cu pointeri astfel:

int strlen(char* p)A int i = 0;
while (*p++) i++; return i;
S

Functia strlen() returneaza numarul de caractere ale sirului, fara caracterul terminal 0, folosind operatia de incrementare a pointerului si operatia de dereferentiere pentru a testa valoarea caracterului. O alta implementare posibila a functiei este urmatoarea:

int strlen(char* p)A char* q = p;
while (*q++); return q-p-1;
S

In C++, ca si in limbajul C, pointerii si tablourile sunt puternic corelate. Un nume al unui tablou poate fi folosit ca un pointer la primul element al tabloului. De exemplu, se poate scrie:

char alphaai = “abcdef”; char* p = alpha; char* q = &alphaa0i;

Rezultatul aplicarii operatorilor aritmetici +, -, ++, -- asupra pointerilor depinde de tipul obiectului indicat. Atunci cand se aplica un operator aritmetic unui pointer p de tip T*, se considera ca p indica un element al unui tablou de obiecte de tip T; p+1 va indica urmatorul element al tabloului, iar p-1 va indica elementul precedent al tabloului. Acest lucru inseamna ca valoarea lui p+1 este cu sizeof(T) octeti mai mare decat valoarea lui p.
Pointeri la functii vor fi prezentati la paragraful de descriere a functiilor. Pointerii la membrii nestatici ai claselor nu sunt considerati pointeri la obiecte si vor fi prezentati in sectiunea urmatoare.

1.4.2.3 Referinte

O referinta (reference) este un nume alternativ al unui obiect. Utilizarea principala a referintelor este in specificarea argumentelor si a valorilor returnate de functii, in general si pentru supraincarcarea operatorilor in special. Notatia X& inseamna referinta la obiectul cu numele X. De exemplu:

int i = 1; int& r = i; // r si i se refera la aceeasi entitate int x = r; // x = 1 r++; // i = 2;

Implementarea obisnuita a unei referinte este printr-un pointer constant care este dereferentiat de fiecare data cand este utilizat.
Asa cum se poate observa, pentru definirea unei referinte se foloseste operatorul adresa &, dar difera tipul constructiei in care este folosit. De exemplu:

int a = 5; int* pi = &a; // & calculeaza adresa;
// pi este adresa lui a int& r = a; // & introduce o referinta;
// r este o referinta (alt nume) pt. a

O referinta este utilizata ca argument pentru o functie care poate sa modifice valoarea acestui argument. De exemplu:

void incr(int& x) Ax++;S void f()A int i = 1; incr(i); // i = 2;
S

O alta utilizare importanta a referintelor este pentru definirea functiilor care pot fi folosite atat ca membru drept cat si ca membru stang al unei expresii de asignare. De exemplu:

#include <iostream.h> int& fr(int vai, int i)A return vaii;
S void main()A int xai = A1,2,3,4S; fr(x,2) = 7; cout <<fr(x,0)<<fr(x,1)<<fr(x,2)<< fr(x,3)<<endl;
S

La executia acestui program se obtine mesajul:
1 2 7 4
Deoarece valoarea returnata de functie este referinta (numele) unui element al vectorului, acesta poate fi modificat prin folosirea functiei fr() ca membru stang al egalitatii.

1.4.2.4 Functii

Functiile sunt tipuri derivate si reprezinta una din cele mai importante caracteristici ale limbajelor C si C++. Forma generala de definire a unei functii este:

tip_returnat nume_func(tip1 arg1,tip2 arg2,……,tipn argn) A
//corpul functiei
S

Functia cu numele nume_func returneaza o valoare de tip tip_returnat si are un numar n de argumente formale declarate ca tip si nume in lista de argumente formale. Argumentele formale din declaratia unei functii se mai numesc si parametrii functiei. Daca o functia nu are argumente, atunci lista din parantezele rotunde este vida. Notatia din C: f(void) este redundanta.
O functie este un nume global, daca nu este declarata de tip static. O functie declarata static are domeniul de vizibilitate restrans la fisierul in care a fost definita.
Corpul functiei este propriu ei si nu poate fi accesat din afara acesteia (nici printr-o instructiune goto). Corpul unei functii este o instructiune compusa, adica o succesiune de instructiuni si declaratii incluse intre acolade. In corpul functiei se pot defini variabile, care sunt locale si se memoreaza in segmentul de stiva al programului. Daca nu sunt declarate de tip static, variabilele locale se creaza la fiecare apel al functiei si se distrug atunci cand este parasit blocul in care au fost definite. Nu se pot defini functii in interiorul unei functii. Argumentele formale ale unei functii sunt considerate variabile locale ale functiei, ca orice alta variabila definita in functia respectiva.
Daca o functie nu are de returnat nici o valoare, atunci tip_returnat din declaratia functiei este tipul void, si nu este necesara o instructiune de returnare (return) in functie. In toate celelalte cazuri, in corpul functiei trebuie sa fie prevazuta returnarea unei variabile de tipul tip_returnat, folosind instructiunea return. Daca in definitie nu este prevazut un tip_returnat, se considera implicit returnarea unei valori de tip intreg.

Prototipurile functiilor. Pentru apelul unei functii este necesara cunoasterea definitiei sau a prototipului acesteia. Prototipul unei functii este de forma: tip_returnat nume_func(tip1 arg1,……., tipn argn);
Numele argumentelor formale sunt optionale in prototipul unei functii. Prototipurile permit compilatorului sa verifice tipurile argumentelor de apel si sa semnaleze eroare la conversii ilegale. Spre deosebire de limbajul C, unde este admisa si simpla declaratie a numelui functiei (fara tipurile argumentelor de apel), utilizarea prototipurilor este obligatorie in C++. De exemplu:

double f2(int, double); // prototip functie f2 double f2(int a, double f)A // definitie functie f3
/*.…….*/ double t = f/a; return t;
S void fp()A double r1 = f1(7, 8.9); // eroare,
// identificator nedeclarat double r2 = f2(7, 8.9); // corect, fol. prototipul char strai = "abcde"; double r3 = f3(7, str); // eroare de tip argument
S double f1(int a, double f)A
/*……..*/ double t = a + f; return t;
S double f2(int a, double f)A
/*.……..*/ double t = a*f; return t;
S

La compilare apare o eroare datorita apelului functiei f1(), care nu este definita, nici declarata prin prototip in domeniul functiei apelante fp() si o eroare datorat apelului functiei f3() cu un argument (argumentul al doilea) care nu poate fi convertit la tipul argumentului formal.

Transferul argumentelor functiilor. La apelul unei functii, argumentele reale (se mai numesc si efective) de apel initializeaza argumentele formale din declaratia functiei, in ordinea din declaratie. Argumentele unei functii se pot transfera in doua moduri: apelul prin valoare si apelul prin referinta.
In apelul prin valoare se copiaza valoarea argumentului real in argumentul formal corespunzator al functiei. In acest caz, modificarile efectuate asupra argumentului functiei nu modifica argumentul real.
In apelul prin referinta este accesata direct variabila din argumentul real transmis functiei, care poate fi deci modificata. Ca exemplificare, se presupune ca se doreste o functie swap() care sa realizeze intershimbul intre valorile a doua variabile. Daca nu se folosesc referinte, argumentele de apel ale functiei trebuie sa fie pointeri la variabilele respective, pentru a fi accesate si modificate. Functia cu argumente pointeri arata astfel:

void swap(int* x, int* y)A int t; t = *x; // dereferentiere
*x = *y;
*y = t;
S

Aceeasi functie swap(), folosind argumente de tip referinta, arata astfel:

void swap(int& x, int& y)A int t; t = x; x = y; y = t;
S

Se poate observa perfecta simetrie intre cele doua implementari si ca, in mod evident, referinta foloseste adresa variabilei pentru a o putea modifica (deci un pointer). Dar, in cazul referintelor, pointerul si defererentierea sunt ascunse, programatorul nu trebuie sa le introduca explicit, programul rezultat este mai concis si mai clar.
Referintele sunt deosebit de utile in apelul functiilor a caror argumente sunt obiecte de dimensiuni mari si copierea lor in argumentele formale (plasate in segmentul stiva al programului) ar fi foarte ineficienta.

Argumente implicite ale functiilor. Se intampla frecvent ca o functie sa aiba un numar mai mare de argumente decat sunt necesare in cazurile simple dar frecvente de apel. Daca nu este necesar sa fie transmisa intotdeauna valoarea reala a unui argument si acesta poate lua, de cele mai multe ori, o valoare implicita, atunci in declaratia functiei se prevede o expresie de initializare a acestui argument, iar din apel poate sa lipseasca valoarea argumentului corespunzator.
De exemplu, o functie pentru stabilirea datei calendaristice, care prevede valori implicite pentru argumentele luna si an:

struct dataA int zi; int luna; int an;
S g_data; void setdata(int zi, int luna=9, int an =1999)A g_data.zi = zi; g_data.luna = luna; g_data.an = an;
S void main()A setdata(15); // 15 9 1999 setdata(21,7); // 21 7 1999 setdata(20,1,2000); // 21 1 2000
S

Numai argumentele de la sfarsitul listei pot fi argumente implicite. De exemplu, este eronata urmatoarea declaratie:

void setdata(int zi, int luna=9, int an); // eroare

Pointeri la functii. Dat fiind ca o functie are o localizare in memorie, aceasta valoare poate fi atribuita unui pointer. Adresa unei functiei este punctul de intrare in functie si, de aceea, functia poate fi apelata folosind un pointer.
Tipul unui pointer la o functie se defineste folosind tipul valorii returnate si tipurile argumentelor formale ale functiei. Inainte de apelul unei functii prin pointer, trebuie sa fie definita valoarea pointerului folosind numele functiei. De exemplu:

float func1(int x, float y)A return x + y;
S float func2(int x, float y)A return x * y;
S void main()A float (*pf)(int, float); // definire tip pointer

pf = func1; // definire valoare pointer float z = (*pf)(3, 1.2f); // apel functie cout << z << endl; // afiseaza 4.2 pf = func2; // definire valoare pointer z = (*pf)(3, 1.2f); // apel functie cout << z << endl; // afiseaza 3.6
S

Desi din acest exemplu simplu nu reiese care ar putea fi avantajul folosirii apelului prin pointer a unei functii, exista totusi situatii cand apelul prin pointeri este mai avantajos. De exemplu, poate sa fie inlocuita o instructiune switch care selecteaza dintre mai multe apeluri de functii, cu un vector de functii care se pot apela prin pointerii corespunzatori.

Supraincarcarea functiilor. In limbajul C, fiecare functie definita in program trebuie sa aiba un nume diferit. In C++, mai multe functii pot avea acelasi nume in acelasi domeniu de definitie, daca se pot diferentia prin numarul sau tipul argumentelor de apel. Acest mecanism se numeste supraincarcarea functiilor (function overloading). In traducere, se mai intrebuinteaza si denumirile de suprapunere, redefinire, supradefinire; in textul de fata este preferat termenul de supraincarcare. Supraincarcarea se poate aplica atat functiilor cat si operatorilor; in sectiunea aceasta este prezentata supraincarcarea functiilor, iar supraincarcarea operatorilor este descrisa in sectiunea 4.
Daca in acelasi domeniu sunt definite mai multe functii cu acelasi nume, la fiecare apel se selecteaza functia corecta prin compararea tipurilor argumentelor reale de apel cu tipurile argumentelor formale ale functiei.
De exemplu,

double abs(double); int abs(int);

abs(1); // apeleaza abs(int) abs(1.0); // apeleza abs(double)

Acceptarea mai multor versiuni ale unei functii cu acelasi nume este conditionata de posibilitatea selectarii fara ambiguitate a uneia dintre acestea dupa tipul sau numarul argumentelor. Nu este admis ca functiile sa difere doar prin tipul returnat.
Doua functii declarate cu acelasi nume se refera la aceeasi functie daca sunt in acelasi domeniu si au numar si tipuri identice de argumente. O functie declarata local nu este in acelasi domeniu cu o functie cu domeniul la nivel de fisier. De exemplu:

int f(char*); void g()A extern f(int); f(“abcd”); // eroare, f(int) ascunde f(char*)
// deci nu exista f(char*) in acest domeniu
S

Situatii asemanatoare, de ascundere si nu de supraincarcare in domenii diferite vor mai fi prezentate in sectiunea 5, dedicata claselor derivate.
Selectia functiei la apel se bazeaza pe “cea mai buna potrivire a argumentelor” (best argument matching). Daca printre functiile supraincarcate exista o functie care are toate argumentele cu tipuri identice cu argumentele din apel, atunci aceasta functie prezinta cea mai buna potrivire a argumentelor si este selectata.
Se considera de exemplu functia supraincarcata de calcul a ridicarii la o putere a unui numar, functia power():

int power(int, int); long power(long,int); double power(double, int); double power(double, double);

In apelurile:

power(7, 8); // selecteaza power(int, int) power(5.6, 2); // selecteaza power(double, int) power(6.7, 2.5); // selecteaza power(double, double)

versiunea functiei power() este selectata pe baza coincidentei dintre argumentele de apel si argumentele formale.
In cazul in care nu exista o astfel de coincidenta, se fac conversii ale argumentelor efective (de apel) catre tipul argumentelor formale. Compilatorul incearca cea mai buna potrivire pentru fiecare argument in parte prin conversii pentru tipuri predefinite care sa nu conduca la trunchieri (pierderi de informatie). De exemplu:

long a = 100; int b = 10; float c = 2.3f; float d = 5.6f; double e = 7.0; double f = 2; power(a,b); // selecteaza power(long, int) power((int)a, b); // selecteaza power(int, int) power(c,a); // selecteaza power(double, int) power(c,d); // selecteaza power(double, double) power(e,d); // selecteaza power(double, double)

Daca prin astfel de conversii nu se poate stabili cea mai buna potrivire a argumentelor, atunci sunt incercate si conversii pentru tipuri definite de utilizatori. Apelul este acceptat numai daca selectia unei versiuni a functiei (pe baza criteriului de cea mai buna potrivire a argumentelor) este unica. Conversiile intre date de tipuri definite de utilizatori sunt prezentate in sectiunea 4, dedicata supraincarcarii operatorilor.

1.4.2.5 Constante simbolice

O constanta simbolica (sau constanta cu nume) este un nume a carui valoare nu poate fi modificata in cursul programului. In C++ exista trei modalitati de a defini constante simbolice:

• Orice valoare, de orice tip care poate primi un nume, poate fi folosita ca o constanta simbolica prin adaugarea cuvantului-cheie const in declaratia acesteia.

• Orice nume de functie sau de tablou este o constanta simbolica.
• O multime de constante intregi poate fi definita ca o enumeratie.

De exemplu, urmatoarele declaratii introduc constante simbolice prin folosirea cuvantului-cheie const:

const int val = 100; const double dai = A1.2, 2.8, 9.5S;

Deoarece constantele nu pot fi modificate, ele trebuie sa fie initializate in declaratie. Incercarea de modificare ulterioara este detectata ca eroare in timpul compilarii:

val++; // eroare d = 200; // eroare

Cuvantul-cheie const modifica tipul obiectului, restrictionand modul in care acesta poate fi folosit.
Un aspect mai aparte si intens folosit in programare, este acela de a declara pointeri la constante. Atunci cand se foloseste un pointer, sunt implicate doua obiecte: pointerul insusi si obiectul catre care indica pointerul.
Prin prefixarea declaratiei unui pointer cu cuvantul const, obiectul indicat este facut constant, nu pointerul insusi. De exemplu:

const char* pc = “abcd”;// pc este pointer la o constanta pca2i = ‘m’; // eroare, nu se poate modifica
// obiectul indicat pc = “ghij”; // corect, este modificata
// valoarea pointerului pc++; // corect

Pentru ca pointerul insusi sa fie constant, se foloseste operatorul *const:

char *const cp = “abcd”;// cp este pointer constant; cpa2i = ‘m’; // corect, modifica valoarea cp = ++; // eroare, pointer constant

Posibilitatea de declarare a pointerilor la constante este intens folosita in transmiterea argumentelor functiilor. Prin declararea unui argument de tip pointer la constanta, este interzisa modificarea de catre functie a obiectului indicat. De exemplu: char* strcpy(char* d, const char* s);
In aceasta functie sirul s nu poate fi modificat.
In mod asemanator, specificatorul const care insoteste un argument tip referinta la apelul unei functii, impiedica modificarea acestuia de catre functia respectiva.

Enumeratii. O alta metoda de a defini constante intregi este prin enumeratie. De exemplu, enumeratia:

enum A
INPUT,
OUTPUT,
INOUT,
S;

este echivalenta cu declararea urmatoarelor constante:

const INPUT = 0; const OUTPUT = 1; const INOUT = 2;

Valorile asignate implicit constantelor incep de la 0 si sunt in ordine crescatoare. Enumeratiile pot avea nume. De exemplu:

enum statesA good, bad, fail
S; void fe (states st )A if (st != good)A
//….
S
S

Un nume declarat de tipul unei enumeratii poate lua orice valoare particulara cuprinsa in enumeratie.
In sfarsit, este posibila initialzarea elementelor unei enumeratii:

enum statesA good = 0x00, bad = 0x01, fail = 0x10
S;
Valorile de initializare nu trebuie neaparat sa ia valori succesive.

1.4.2.6 Specificatorul typedef

Declaratiile care contin cuvantul-cheie typedef declara identificatori care pot fi folositi pentru denumirea tipurilor fundamentale sau derivate in domeniul de definitie al acestuia. O declaratie care contine specificatorul typedef nu introduce nume noi in program, ci realizeaza o echivalenta sintactica a unui nou nume cu un alt nume, fundamental sau derivat. De exemplu, in declaratiile:

typedef int KM, *PKM;
KM dist;
PKM pd;

KM este de tip intreg, iar pd este pointer la intreg.
O structura fara nume definita printr-un specificator typedef capata numele introdus de acesta:

typedef struct A /*……*/S S; //structura este denumita S.
S struct1;

Acesta este modul obisnuit de declaratie in C, unde numele unei structuri nu poate fi folosit ca un nume de tip fara sa fie insotit de cuvantul-cheie struct. Acest stil este admis si in C++, pentru a se asigura compatibilitatea. Dar stilul mai normal pentru C++ este de a declara o structura cu nume si fara typedef:

struct SCA/*...*/S;
SC struct2;

1.4.2.7 Specificatorul volatile

Specificatorul volatile indica faptul ca valoarea obiectului poate fi modificata pe alte cai decat cele declarate explicit in program. De exemplu, adresa unei variabile globale poate fi transmisa unei rutine de interfata a sistemului, care modifica valoarea acesteia, fara o instructiune explicita din program. Acest lucru este important, deoarece majoritatea compilatoarelor de C si C++ optimizeaza automat evaluarea expresiilor prin presupunearea ca o variabila ramane neschimbata atata timp cat nu apare in partea stanga a unei operatii de asignare. Specificatorul volatile impiedica aplicarea unor astfel de optimizari.

1.4.2.8 Clase, structuri, uniuni

Pe langa tipurile de date fundamentale ale limbajului, in C++ se pot defini tipuri de date noi prin definirea unor clase. Aceste tipuri se numesc tipuri definite de utilizator (user-defined types) si se pot utiliza intr-un mod asemanator utilizarii tipurilor predefinite. Aceste tipuri mai sunt denumite si tipuri de date abstracte (abstract data types), dar in aceasta lucrare s-a preferat termenul de tip definit de utilizator, asa cum il prefera autorul limbajului aStroustrup 94i. De exemplu, declaratia:

class XA
// corpul clasei X
// declaratii de date si functii membre
S;

este si o definitie a clasei X, care introduce un tip nou de date. Prin aceasta definitie se asociaza numele X cu entitatea definita in corpul clasei. Dupa definirea unui astfel de tip de date, se pot declara (defini) obiecte de tipul respectiv, la fel ca si variabilele (obiecte) de tipuri predefinite:
X obx1; // obiect obx1 de tipul X
Clasele, structurile si uniunile in C++, precum si pointeri la membrii claselor, vor fi prezentate detaliat in sectiunea urmatoare. In acest punct au fost introduse doar pentru precizarile legate de tipuri, declaratii si definitii.

1.5 Expresii si operatori

O expresie este o secventa de operatori si operanzi care specifica executarea unor calcule. O expresie poate produce un rezultat sau efecte laterale (side effects).
In C++ operatorii pot fi supraincarcati, adica li se poate atribui un anumit mod de operare atunci cand se aplica tipurilor definite de utilizator (clase). Operatorii supraincarcati urmeaza aceleasi reguli sintactice ca si operatorii normali, dar operatiile efectuate pot sa difere de ale acestora. Supraincarcarea operatorilor nu poate modifica regulile de aplicare ale acestora asupra tipurilor pentru care ei sunt definiti in limbaj.
Ordinea de evaluare a unei subexpresii este determinata de precedenta (precedence) si gruparea operatorilor. Regulile matematice obisnuite de asociativitate si comutativitate se aplica pentru acei operatori care sunt in mod real asociativi sau comutativi.
O expresie care se refera la un obiect sau functie este denumita valoare stanga (left value, prescurtat lvalue). Aceasta denumire provine din faptul ca o astfel de valoare poate fi folosita ca membru stang al unei expresii de asignare: E1 = E2. Operandul E1 trebuie sa fie expresie lvalue. In expresii, unii operatori produc expresii lvalue, altii necesita expresii lvalue. O expresie lvalue este modificabila daca nu este numele unei functii, numele unui tablou sau constanta.

1.5.1 Operatori specifici C++

Majoritatea operatorilor C++ sunt preluati din limbajul C, cu aceeasi sintaxa si reguli de operare. In plus fata de operatorii C, in C++ mai sunt introdusi urmatorii operatori:

• operatorul de rezolutie (::),
• operatorul de lansare exceptie (throw),
• operatorii de alocare-eliberare dinamica a memoriei new si delete.

Operatorul de lansare exceptie (throw) este descris in sectiunea 8. Ceilalti operatori sunt descrisi in continuare.

1.5.1.1 Operatorul de rezolutie

Operatorul de rezolutie (::) este folosit pentru modificarea domeniului de vizibilitate al unui nume. Pentru acest operator (scope resolution operator), in traduceri se mai intalnesc termenii de operator de domeniu sau operator de acces. Operatorul de rezolutie permite folosirea unui identificator intr-un bloc in care el nu este vizibil. Daca operatorul de rezolutie nu este precedat de nici un nume de clasa, atunci este accesat numele global care urmeaza acestui operator. De exemplu:

int g = 10; int f()A int g = 20; return ::g;
S void main()A cout << f() << endl; // afiseaza 10
S

In acest exemplu operatorul de rezolutie a fost folosit pentru a accesa variabila globala g, ascunsa de variabila locala cu acelasi nume din functie. Deoarece utilizarea cea mai extinsa a operatorului de rezolutie este legata de utilizarea claselor, el va fi reluat pe parcursul sectiunilor urmatoare.

1.5.1.2 Operatorii de alocare-eliberare dinamica a memoriei.

In limbajul C se pot aloca dinamic zone de memorie in memoria libera (heap) folosind functii de biblioteca (de exemplu, malloc(), calloc(), realloc()) si se pot elibera folosind functia free(). La aceste posibilitati, care se pastreaza in continuare in C++, se adauga posibilitatea folosirii operatorilor de alocare si eliberare dinamica a memoriei, new si delete. Acesti operatori unari prezinta avantaje substantiale fata de functiile de alocare din C si de aceea sunt in mod evident preferati in programele scrise in C++.
Pentru alocarea unei singure date (obiect), operatorul new are urmatoarea forma generala: tip_data* p = new tip_data(initializare); unde tip_data este un tip de date predefinit sau definit de utilizator (clasa), p este pointerul (adresa de inceput) a zonei alocate in memoria heap, returnat la executia operatorului new, iar initializare este o expresie care depinde de tipul datei si permite initializarea zonei de memorie alocate. Daca alocarea nu este posibila, pointerul returnat este NULL.
Forma de utilizare a operatorului new pentru alocarea unui vector de date (tablou unidimensional) de dimensiune dim, este urmatoarea: tip_data* p = new tip_dataadimi;
La alocarea unui vector nu se poate transmite o expresie de initializare a zonei de memorie alocata.
Operatorul delete elibereaza o zona din memoria heap. El poate avea una din urmatoarele forme: delete p; delete aip;
Prima forma se utilizeaza pentru eliberarea unei zone de memorie ocupata de o singura data (obiect), nu un vector. Pointerul p este un pointer la o zona de memorie alocata anterior printr-un operator new. Operatorul delete trebuie sa fie folosit doar cu un pointer valid, alocat numai cu new si care nu a fost modificat sau nu a mai fost eliberata zona de memorie mai inainte (cu un alt operator delete sau prin apelul unei functii free()). Folosirea operatorului delete cu un pointer invalid este o operatie cu rezultat nedefinit, cel mai adesea producand erori de executie grave.
Cea de-a doua forma a operatorului deleteai se foloseste pentru eliberarea unei zone de memorie ocupata de un vector de date. Pentru tipurile de date predefinite ale limbajului, se poate folosi si prima forma pentru eliberarea unui vector, dar, in cazul obiectelor de tipuri definite de utilizator, acest lucru nu mai este valabil. Aceasta situatie va fi detaliata in sectiunea urmatoare.
Cateva exemple de utilizare a operatorilor new si delete:

int *pi = new int(3); // alocare int si initializare double *pd = new double; // alocare double neinitializat char *pc1 = new chara12i; // vector de 12 caractere char *pc2 = new chara20i; // vector de 20 caractere delete pi; delete pd; delete pc1; delete aipc2;

In legatura cu existenta celor doua modalitati de alocare dinamica, prin operatorii new-delete sau prin functiile de biblioteca malloc-free, fara sa fie o regula precisa, combinarea acestora este bine sa fie evitata, deoarece nu exista garantia compatibilitatii intre ele.

1.5.2 Precedenta operatorilor

In tabelul urmator sunt prezentati concis operatorii din limbajul C++ grupati in ordinea precedentei lor. In fiecare compartiment sunt trecuti operatorii cu aceeasi precedenta. Un operator dat are o precedenta mai ridicata decat un altul dintr-un compartiment aflat mai jos in tabel. Operatorii se aplica in ordinea precedentei lor. De exemplu, a+b*c inseamna a+(b*c), deoarece inmultirea (*) are o precedenta mai ridicata decat adunarea (+).

Operatori C++
:: operator rezolutie nume_clasa::membru
:: nume global ::nume
. selectie membru obiect.membru
-> selectie membru pointer->membru
ai indexare pointeraexpri
() apel functie expr (lista_expr)
() conversie explicita tip(list_expr) sizeof dimensiune obiect sizeof expr sizeof dimensiune tip sizeof (tip)
++ post incrementare lvalue++
++ pre incrementare ++lvalue
-- post decrementare lvalue- -- pre decrementare --lvalue
I complement Iexpr
! negatie !expr
- minus unar -expr
+ plus unar +expr
& adresa &lvalue
* derefentiere *expr new alocare new tip delete eliberare(dezalocare) delete pointer deleteai eliberare tablou deleteaipointer
() conversie cast (tip)expr
.* selectie membru obiect.*pointer_la_membru
->* selectie membru pointer->*pointer_la_membru
* inmultire expr * expr
/ impartire expr / expr
% modulo expr % expr
+ adunare expr + expr
- scadere expr - expr
<< depl. logica stanga expr << expr

Colt dreapta
Creeaza cont
Comentarii:

Nu ai gasit ce cautai? Crezi ca ceva ne lipseste? Lasa-ti comentariul si incercam sa te ajutam.
Esti satisfacut de calitarea acestui document, eseu, cometariu? Apreciem aprecierile voastre.

Nume (obligatoriu):

Email (obligatoriu, nu va fi publicat):

Site URL (optional):


Comentariile tale: (NO HTML)


Noteaza documentul:
In prezent fisierul este notat cu: ? (media unui numar de ? de note primite).

2345678910

 
Copyright© 2005 - 2024 | Trimite document | Harta site | Adauga in favorite
Colt dreapta