Sunteți pe pagina 1din 35

Lecia 1 Coninut - Un tur rapid al C++Builder; - Modul de scriere al aplicaiilor de consol Win32; - O introducere n limbajul C++; - Variabilele i tipurile

de date C++; - Introducere n utilizarea funciilor C++; - Utilizarea masivelor de date (vectori i matrici); 1. Un tur rapid al C++Builder Pentru moment, nu vom acorda dect o privire rapid mediului de dezvoltare C++Builder, urmnd ca n lecia a asea s examinm n detaliu acest IDE. Atunci cnd pornim pentru prima oar IDE-ul C++Builder ni se prezint mediul de lucru C+ +Builder n care este deschis o form nou, fr coninut, ca n figura 1.1. (forma este unul dintre elementele de interfa vizual, practic o fereastr de uz general pentru o aplicaie oarecare).

Figura 1.1 IDE-ul C++Builder este mprit n trei pri. Fereastra superioar poate fi considerat partea principal a IDE-ului. Pe lng meniul principal ea conine i bara de butoane cu cele mai folosite operaii n stnga i selectorul de componente utilizabile n dreapta. (vezi figura 1.2).

Figura 1.2.

Pentru o mai uoar regsire, componentele sunt mprite n tipuri de componente, fiecare tip avnd un tab n paleta de componente. Pentru a utiliza o component, este suficient s o selectm n palet dup care s dm click pe forma pe care dorim s amplasm componenta, la poziia dorit. O component este o bucat de cod software care va ndeplini n aplicaie o anume funcie predefinit (cum ar fi o etichet, un cmp de editare sau o list). Cea de-a doua parte a IDE-ului C++Builder este inspectorul de obiecte (Object Inspector) care este amplasat n mod implicit n stnga ecranului. Prin intermediul inspectorului de obiecte vom modifica proprietile componentelor i modul cum sunt tratate evenimentele referitoare la ele (interaciunile utilizatorului cu componenta respectiv). n inspectorul de obiecte apare ntotdeauna lista de proprieti a componentei curent selectate, dublat de lista de evenimente care pot afecta componenta respectiv, dar mai poate aprea (dac este selectat) i ierarhia de componente a aplicaiei. n dreapta inspectorului de obiecte este spaiul de lucru al C++Builder (cea de-a treia parte). Iniial n acest spaiu este afiat editorul de forme. Acesta este utilizat pentru a amplasa, muta sau dimensiona diverse componente ca parte a crerii formelor aplicaiei. n spatele editorului de forme se afl parial ascuns fereastra editorului de cod de program (locul n care vom scrie cod pentru programele noastre). S ncercm o prim aplicaie practic. n acest moment, C++Builder este pornit i avem la dispoziie o form fr coninut. n mod implicit, acest form este denumit Form1. Inspectorul de obiecte afieaz proprietile referitoare la ea. Selectai proprietatea Caption din lista de proprieti a formei i tastai un titlu pe care dorii s-l dai ferestrei de aplicaie reprezentate de Form1. Observai c pe msur ce tastai, titlul ferestrei este modificat (vei observa acest comportament i la alte componente). Pentru a rula aplicaia proaspt obinut putem apsa pe butonul Run de pe bara de unelte (cel pe care este desenat o sgeat verde) sau putem apela opiunea Run din meniul Run sau putem apsa tasta F9 (care este un shortcut ctre opiunea precedent). La folosirea oricreia din modalitile de mai sus, IDE-ul va rspunde prin afiarea unui ferestre de stare coninnd informaii referitoare la procesul de compilare, ca n figura 1.3. (procesul de obinere a codului executabil al aplicaiei).

Figura 1.3 Dupa scurt timp, fereastra de stare a compilarii, dispare, apare forma pe care am lucrat pana acum, de data aceasta fiind executata, iar titlul ei este cel pe care l-am introdus mai sus, vezi figura 1.4.

Figura 1.4 Revenim la modul editare inchizand aplicatia executata (click pe butonul de inchidere al formei). Pentru a putea adauga un prim element functional acestei forme vom adauga o eticheta cu un text oarecare pe forma noastra. Pentru aceasta, in Tab-ul Standard al paletei de componente, dam click pe componenta Label (butonul cu un A mare pe el). Dati din nou click pe forma, la pozitia la care doriti sa amplasati eticheta. Dupa amplasarea acesteia, observam ca ea apare in ierahia de obiecte ale aplicatiei (daca ierarhia este vizibila) si ca proprietatile etichetei sunt listate in Inspectorul de obiecte. Selectati proprietatea Caption si modificati-o pentru a modifica textul afisat de eticheta. Pentru a modifica si modul in care este afisat textul, dam dublu-click pe proprietatea Font din aceeasi lista (se va deschide o sublista cu proprietati suplimentare legate de aspectul si tipul fontului folosit). Cautati in sublista proprietatea Size (este curent setata la 8) si modificati-o la 24. Dupa ce confirmati noua dimensiune a fontului apasand Enter, ea va fi aplicata etichetei respective. Putem modifica si pozitia etichetei in mod simplu, dand click pe ea si tragand-o pe noua pozitie. Dupa toate aceste modificari putem rula din nou programul (cum am facut mai sus). Rezultatele vor fi asemanatoare cu cele din figura 1.5.

Figura 1.5 Pentru etapa urmatoare a acestei lectii vom inchide proiectul pe care am lucrat pana acum. Pentru aceasta vom apela optiunea Close All din meniul File (vom fi intrebati daca dorim sa salvam proiectul respectiv si daca da, sub ce nume si unde...). 2. O aplicatie de consola Win32 Pentru inceput vom incerca sa invatam elementele de baza ale limbajului C++. Programele de mici dimensiuni pe care le vom utiliza in acest scop sunt cel mai simplu de realizat ca programe de consola (programe care nu au nevoie de o interfata grafica Windows). E de remarcat ca programele de consola Win32 (se numeste asa pentru ca vorbim de o versiune de Windows pe 32 de biti ...) arata exact la fel cu cele de DOS (diferentele dintre ele neavand absolut nicio legatura cu aspectul). Din meniul File alegem optiunea New->Other. O fereastra de dialog va fi afisata si ea va contine tipurile de noi programe sau componente pe care le putem crea (colectia respectiva se numeste Object Repository) pe baza unor modele predefinite. Dublu click pe optiunea Console Wizard pentru a porni un nou proiect de aplicatie de consola. O fereastra de dialog continand optiunile de baza ale noii aplicatii de consola va fi afisata. Optiunile implicite (C++ code, console application) ne convin drept pentru care nu le vom schimba (vezi figura 1.6).

Figura 1.6

Observam ca spre deosebire de aplicatia precedenta nu mai avem la dispozitie nicio forma, ci numai editorul de cod, ca in figura 1.7.

Figura 1.7 Pe langa absenta editorului de forme vom observa si ca Inspectorul de obiecte nu afiseaza nimic (el este activ doar atunci cand exista componente vizuale la care sa se refere il putem chiar inchide atunci cand scriem aplicatii de consola, fiind inutil). Pentru a redeschide ulterior Inspectorul de obiecte putem apela optiunea Object inspector din meniul view sau putem apasa F11. La deschiderea noului proiect, codul afisat al aplicatiei este urmatorul: //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop //--------------------------------------------------------------------------#pragma argsused int main(int argc, char* argv[]) { return 0; } //--------------------------------------------------------------------------Programul respectiv nu face nimic, dar este un program valid. 3. O introducere n limbajul C++

Liniile care incep cu // sunt linii de comentarii (observati modul in care au fost folosite linii de comentarii pentru a imparti programul C++ in cele doua sectiuni majore, cea de declaratii si cea de cod direct executabil). Observati si faptul ca singura linie de cod executabila (cea care returneaza rezultatul functiei main) este terminata cu ; (regulile sunt aceleasi ca in C-ul simplu). De asemenea observati acoladele de la inceputul si sfarsitul functiei main (ele au rolul de a marca inceputul si sfarsitul codului unei functii sau al unei secvente de linii executabile). Este inclusa si o biblioteca de functii (vcl.h care contine definirea catorva functii si tipuri pentru lucrul cu componente vizuale, VCL = Visual Component Library) Putem adauga la acest schelet de program pus la dispozitie de C++Builder codul necesar pentru a ajunge la o aplicatie de consola completa. Una dintre cele mai utilizate biblioteci in aplicatiile de consola C++ este iostream.h. Ea se bazeaza pe utilizarea de streamuri pentru a efectua operatii de baza de intrare si iesire. Streamul cout este utilizat pentru a trimite date catre iesirea standard (in mod implicit monitorul). Streamul cin este utilizat pentru a prelua date de la intrarea standard (in mod implicit tastatura). Iostream implemenetaza doi operatori pentru a insera informatii intr-un stream (<<) si respectiv pentru a extrage informatii dintr-un stream (>>). Spre exemplu, pentru a afisa ceva intr-o aplicatie de consola am putea utiliza intr-un program urmatoarea linie de cod: cout << Bine ati venit!; Aceast linie de cod spune programului s insereze textul Bine ati venit! n streamul standard de ieire, adic pe ecranul monitorului. Observaie. cout nu poate fi utilizat dect n aplicaiile de consol. n aplicaiile cu interfa grafic Windows exist dou funcii standard pentru afiare de text: DrawText() i TextOut() (ele nu fac oricum obiectul acestei lecii). Pentru a folosi cout trebuie inclus biblioteca care l declar (#include<iostream.h>). Dac am uitat s facem acest lucru, la ncercarea de a rula aplicaia vom obine o eroare de compilare (Undefined symbol cout). Pentru a afla de unde provine o anumit funcie sau un anumit tip, putem da click pe numele funciei sau tipului i apsa F1. La apsarea tastei F1 va aprea textul de ajutor referitor la funcia sau tipul respectiv, incluznd fiierul bibliotec n care acesta a fost declarat. n iostream.h exist de asemenea elemente de modificare a modului n care un stream este tratat. Pentru moment, vom lucra cu endl, care desemneaz nceputul unei noi linii n streamul de ieire. Acum putem scrie o prim aplicaie care s afieze un mesaj. Urmrii listingul de mai jos: //--------------------------------------------------------------------------#include <vcl.h> #include <iostream.h> // am adugat aceast linie #pragma hdrstop //--------------------------------------------------------------------------#pragma argsused int main(int argc, char* argv[]) { cout << "Salutare!" << endl; // am adugat aceast linie return 0;

} //--------------------------------------------------------------------------Observaie. Spaiile inserate n text, att timp ct nu rup un cuvnt, nu au nicio influen. Spre exemplu bucata de cod urmatoare: int main(int argc, char **argv) { cout << Salutare!; return 0; } este acelai lucru cu: int main(int argc,char** argv){cout<<Salutare!;return 0;} Pentru a rula programul, folosim aceeai opiune ca mai devreme. La execuie va aprea o fereastr de consol i n ea va fi afiat mesajul dorit, dup care fereastra respectiv va fi nchis imediat. Acest lucru se datoreaz faptului c aplicaia i-a terminat execuia, iar fereastra de consol care a gzduit-o se va nchide imediat dup terminarea aplicaiei. Pentru a mpiedica acest lucru, mai adugm nc o linie de cod care s atepte apsarea unei taste. Vom utiliza funcia getch() din biblioteca conio.h (funcii de intrare-ieire pentru consol), precum n exemplul urmtor: //--------------------------------------------------------------------------#include <vcl.h> #include <iostream.h> #include <conio.h> // am adugat aceast linie #pragma hdrstop //--------------------------------------------------------------------------#pragma argsused int main(int argc, char* argv[]) { cout << "Salutare!" << endl; cout << "Apasati orice tasta pentru a continua..."; // am adugat aceast linie getch(); // am adugat aceast linie return 0; } //--------------------------------------------------------------------------De data aceasta aplicaia ruleaz, afieaz mesajul dorit i fereastra de consol rmne vizibil pn la apsarea unei taste. Acesta a fost un prim exemplu de aplicaie de consol. Mai departe vom ncerca s nelegem alte elemente ale limbajului C++. 4. Variabilele i tipurile de date C++; Pentru nceput, e bine s menionm c nu vom face o prezentare extensiv a limbajului C++. Pentru acest lucru, este necesar consultarea altor lucrri dedicate.

Variabile O variabil este o poriune de memorie, identificat printr-un nume i destinat stocrii datelor de un anumit tip. Variabilele sunt utilizate pentru manipularea datelor n memorie. Un exemplu de utilizarea a variabilelor intr-un program este urmtorul: int x; // variabila de tip intreg x = 100; // x contine acum valoarea 100 x += 50; // la valoarea lui x se adauga 50, devenind 150 int y = 150; // se declara si se initializeaza cu valoarea 150 variabila y x += y; // la valoarea lui x se adauga valoarea lui y, devenind 300 x++; // la valoarea lui x se adauga 1, devenind 301 Variabilele care sunt declarate, dar nu sunt iniializate, vor conine valoarea coninut pn atunci n zona de memorie respectiv (la iniializarea calculatorului, pn la utilizare, locaiile de memorie sunt iniializate cu 0, dup utilizare, o locaie de memorie este doar declarat liber, nu i reiniializat cu 0, drept pentru care la o reutilizare, ea va conine valoarea motenit de la utilizarea anterioar, chiar dac nu mai are aceeai semnificaie). Din acest motiv, nu este posibil s tim ce conine o variabil care a fost declarat, dar nu i iniializat. Un exemplu de fragment de cod defectuos din acest punct de vedere este urmtorul: int x; int y; x = y + 10; // gresit, pentru ca nu ma pot baza pe faptul ca y are valoarea 0 (sau orice alta valoare la care m-as astepta) Numele de variabile pot fi o combinaie de majuscule, minuscule, cifre i underscore (_). Nu pot conine alte caractere (caractere speciale i spaiu). Nu pot ncepe cu o cifr. Numele de variabil care ncep cu underscore sunt de obicei folosite pentru variabile cu destinaii speciale. Lungimea maxim a unui nume de variabil depinde de la compilator la compilator, dar implementrile standard au de obicei lungime maxim de 31 de caractere (ceea ce este oricum prea mult pentru un nume de variabil folosit curent). Tipuri de date C++ Un tip de date specifica modul in care informatia va fi stocata (reprezentata) in memorie, intr-o variabila. In C++ este necesara specificarea tipului de date care va fi utilizat la declararea unei variabile. Exemple de declaratii posibile intr-un program: int x1 = -1; int x = 1000; float y = 3.14; long z = 457000;

Aceasta specificare permite compilatorului sa faca verificari de tip la compilare si pe pracurusul rularii programului. Utilizari improprii ale tipurilor de date vor duce la aparitia de erori sau avertismente care pot fi analizate si corectate la timp. Anumite tipuri de date (cele numerice intregi) pot fi declarate ca fiind cu semn (signed pot contine si valori negative) sau fara semn (unsigned pot contine numai valori pozitive). Tabelul 1.1 specifica cateva tipuri de date folosite curent in C++ impreuna cu caracteristicile lor: Tip de date char unsigned char short unsigned short long unsigned long int unsigned int float double bool Memorie ocupata (in octeti) 1 1 2 2 4 4 4 4 4 8 1 Domeniu de valori -128 to 126 0 to 255 -32,768 to 32,767 0 to 65,535 -2,147,483,648 to 2,147,483,648 0 to 4,294,967,295 la fel ca long (atentie, difera de C-ul clasic) la fel ca unsigned long (idem) 1.2E-38 to 3.4E381 2.2E-308 to 1.8E3082 true sau false

Observatie. Intre tipurile de date considerate a fi partial compatibile se pot face conversii. Spre exemplu se poate da o valoare fractionara unei variabile de tip intreg dar aceasta va retine numai partea intreaga a numarului respectiv: int x = 3.75; // va avea ca rezultat darea valorii 3 lui x C++ va face conversii implicite intre diferitele tipuri de date de cate ori este posibil. Un alt exemplu de conversie implicita (desi cu rezultate nedorite) este urmatorul: short result; long num1 = 200; long num2 = 200; result = num1 * num2; //rezultatul este teoretic 40000 dar short are valoarea maxima 32767 drept pentru care rezultatul va fi o valoare negativa, -25,536 (o ia de la inceput cu baleierea domeniului de short) Pentru a vedea practic ce se intampla intr-un astfel de caz putem incerca programul de mai jos: //--------------------------------------------------------------------------#include <vcl.h> #include <iostream.h> #include <conio.h>

#pragma hdrstop //--------------------------------------------------------------------------#pragma argsused int main(int argc, char* argv[]) { short x = 32767; //x ia valoarea 32767 care este maximul pentru tipul short cout << "x = " << x << endl; x++; //la valoarea lui x mai adaug 1, noua valoare a lui x va fi -32768 cout << "x = " << x << endl; getch(); return 0; } //--------------------------------------------------------------------------Desigur, pentru un program ideal construit ar trebui sa utilizam tipul de date cel mai potrivit pentru fiecare variabila dar in marea majoritate a aplicatiilor nu foarte pretentioase putem folosi int ca tip generic pentru numere intregi. In anumite cazuri compilatorul nu reuseste sa realizeze conversia automata intre doua tipuri de date diferite caz in care vom primi un mesaj de eroare de genul Cannot convert from X to Y (unde X si y sunt tipurile de date implicate). De asemenea putem primi, in locul unui mesaj de eroare un avertisment de tipul Conversion may lose significant digits (prin conversie se vor pierde cifre semnificative). In orice caz, o buna programare presupune obtinerea de programe care nu numai ca nu au erori (adica vor rula) dar si care nu vor avea avertismente (vor duce la rezultatele urmarite). Din acest punct de vedere, avertismentele, desi nu opresc executia programului, e bine sa fie tratate asemeni erorilor, adica eliminate. Operatori C++ Operatorii sunt utilizati pentru a manipula datele. Ei pot efectua calcule, verifica relatia intre doua valori, manipula variabile precum si alte operatii. In continuare prezentam lista celor mai cunoscuti operatori din C++ (tabelul 1.2): Operator Descriere Exemplu x = y + z; x = y - z; x = y * z; x = y / z; x = 10; x += 10; (same as x = x + 10;)

Operatori matematici + Adunare Scadere Inmultire / Impartire Operatori de atribuire = Atribuire Atribuire si adunare +=

-= *= \= &= |= Operatori logici && ||

Atribuire si scadere Atribuire si inmultire Atribuire si impartire Atribuire si SI la nivel de biti Atribuire si SAU la nivel de biti

x -= 10; x *= 10; x \= 10; x &= 0x02; x |= 0x02;

SI logic SAU logic

if (x && 0xFF) {...} if (x || 0xFF) {...} if (x == 10) {...} if (x != 10) {...} if (x < 10) {...} if (x > 10) {...} if (x <= 10) {...} if (x >= 10) {...} int x = *y; int* x = &y; x &= ~0x02; if (!valid) {...} x++; (same as x = x + 1;) x--;

Operatori de comparatie == Egal cu != Diferit de < Mai mic ca > Mai mare ca <= Mai mic sau egal cu >= Mai mare sau egal cu Operatori unari * Operator de indirectare & Operator de adresare ~ Negatie la nivel de biti ! Negatie logica Operator de incrementare ++ Operator de decrementare -Operatori de clase si structuri :: -> .

Precizare a tintei Apartenenta indirecta Apartenenta directa

MyClass::SomeFunction(); myClass->SomeFunction(); myClass.SomeFunction();

Dupa cum vedem, lista de operatori este destul de lunga. Deprinderea lor se va face incet, incet pe masura ca vom inainta in invatarea limbajului C++. O observatie interesanta se refera la operatorii de incrementare si decrementare al caror efect difera partial in functie de pozitia in care sunt aplicati (inainte sau dupa variabila) precum in portiunea de program urmatoare: int x = 10; cout << x = << x++ << endl;//il afiseaza pe x dupa care il incrementeaza cout << x = << x << endl;//il afiseaza din nou pe x cout << x = << ++x << endl;//il incrementeaza pe x inainte de a il afisa cout << x = x << endl; //il afiseaza din nou pe x

Efectul executiei codului intr-un program va fi: x = 10 x = 11 x = 12 x = 12 O alta observatie este faptul ca operatorii pot fi supraincarcati in C++. Aceasta este o tehnica ce permite ca un anume operator sa se comporte diferit in contexte diferite. Spre exemplu, pentru o clasa oarecare operatorul ++ poate fi supraincarcat de asa natura incat sa creasca valoarea variabile tinta nu cu 1 ci cu o valoare oarecate. 5. Introducere n utilizarea funciilor C++ Functiile sunt sectiuni de cod separate de functia main (main este functia principala a unui program C++, singura functie care este executata direct; toate celelalte functii sunt executate prin apelare directa sau indirecta din functia main). Ele sunt utilizate pentru a executa calcule sau operatiuni specifice in cadrul programului. Regulile pentru denumirea functiilor sunt aceleasi ca cele discutate mai devreme pentru denumirea variabilelor. Figura 1.7 arata structura unei functii:

Tipul returnat

Prototipul functiei Numele functiei int OFunctie (int x, int y) { int z = (x * y); return z; } Returnarea rezultatului

Lista de parametri a functiei Corpul functiei

Figura 1.7 Structura unei functii Un parametru este o valoare trimisa functiei si utilizata de aceasta ca element intr-un calcul, pentru a-si modifica functionarea sau pentru a-si preciza modul de lucru. Inainte ca o functie sa poata fi folosita ea trebuie declarata. Declaratia (prototipul) unei functii spune compilatorului cati parametri primeste functia, tipul fiecarui parametru precum si tipul de rezultat returnat de functia respectiva. Functia poate fi declarata inainte ca ea sa fie definita (sa ii fie descris si modul de functionare) urmand ca la definire prototipul functiei respective sa apara inca odata (vezi programul urmator). //--------------------------------------------------------------------------#include <vcl.h> #include <iostream.h> #include <conio.h> // am adugat aceast linie #pragma hdrstop int multiply(int, int); //prototipul unei functii

void showResult(int); //prototipul unei functii //--------------------------------------------------------------------------#pragma argsused int main(int argc, char* argv[]) { int x, y, result; cout << endl << "Introduceti prima valoare: "; cin >> x; cout << "Introduceti a doua valoare: "; cin >> y; result = multiply(x, y); showResult(result); cout << endl << endl << "Apasati orice tasta pentru a continua..."; getch(); return 0; } //--------------------------------------------------------------------------int multiply(int x, int y)//definitia primei functii; incepe cu prototipul functiei { return x * y; } void showResult(int res) //definitia celei de-a doua functii; incepe cu prototipul functiei { cout << "Rezultatul este: " << res << endl; } //--------------------------------------------------------------------------Programul cere doua numere de la utilizator, face inmultirea lor folosind functia multiply dupa care afiseaza rezultatul folosind functia showResult. O functie poate fi folosita in mai multe moduri diferite (putem transmite parametri unei functii prin valoare, prin referinta sau chiar ca rezultat al apelului unei alte functii). Folosind functiile din programul de mai sus putem ilustra acest concept: result = multiply(2, 5); // transmisie prin valoare result = multiply(x, y); // transmisie prin referinta showResult(multiply(x,y)); // valoare rezultata din apelul altei functii multiply(x, y); // executia unei functii cu ignorarea valorii returnate Observatie: Exista mai multe cazuri in care rezultatul unei functii poate fi ignorat (desi acest lucru pare gresit la prima vedere). Spre exemplu, atunci cand folosim functia getch() pentru a astepta apasarea unei taste oarecare, valoarea returnata de getch() va fi ignorata. Observatie: o functie se poate apela si pe ea insasi. Acest procedeu se numeste recursie si este folosita in rezolvarea mai multor tipuri de probleme. Reguli pentru lucrul cu functii: - O functie poate avea orice numar de parametri sau sa nu aibe parametri;

- Nu este obligatoriu ca functia sa returneze o valoare (se va pune void ca tip al rezultatului functiei); - Daca o functie are void ca tip returnat ea nu poate returna o valoare. Pentru orice alt tip indicat ca tip returnat, functia trebuie sa returneze o valoare; - O functie nu poate returna decat o singura valoare. Functia main() Un program C++ de consola trebuie sa aibe o functie main(). Aceasta functie serveste ca punct de inceput al programului. In programele Windows scrise in C++ exista o functie echivalenta numita WinMain(). Obs. La lucrul in C++Builder functia WinMain() este generata automat si scrisa in sectiunea de cod predefinit, programatorul nevazand-o in codul de program corespunzator formelor cu care lucreaza. main() este o functie normala, in sensul ca are exact aceeasi structura (vezi structura definitiei unei functii de mai sus). Ati vazut deja ca prototipul functiei main pentru aplicatii de consola Windows pe 32 de biti este urmatorul: int main(int argc, char* argv[]); Declarata in acest mod functia main() primeste doi parametri si returneaza o valoare intreaga. O diferenta fundamentala dintre functia main si toate celelalte functii este ca functia main nu este practic apelata de nimeni. Ea ruleaza automat atunci cand programul este executat. Tinand cont ca functia poate avea totusi parametri ca toate celelalte functii, se poate pune intrebarea: De la cine primeste acesti parametri? iar raspunsul corect este ca parametrii respectivi sunt parametrii care au fost dati in linie de comanda atunci cand a fost rulat programul. Desigur, putem rula un program fara nici un fel de parametri (si in marea majoritate a cazurilor asa se si intampla). In acest caz putem chiar specifica explicit ca nu vom folosi parametri: int main();//nu primeste parametri void main();//nu primeste parametri, nu returneaza rezultat argc, primul dintre cei doi parametri, contine numarul de parametri primiti in linie de comanda. Cel de-al doilea, argv, este un vector de stringuri de dimensiune neprecizata(va aminti ca putem lucra cu un string ca fiind un vector de caractere sau ca fiind un pointer la un caracter, cele doua fiind de fapt acelasi lucru) in care vor fi stocati parametrii primiti in linie de comanda la executarea programului. Spre exemplu, pentru un program fictiv numit copyx care va fi executat in linie de comanda in modul urmator: copyx c:\bc5\bin\grep.com d:\test\grep.com d cei doi parametri vor contine urmtoarele: argc va contine valoarea 4 (linia de comanda contine 4 stringuri, cu tot cu numele programului) argv[0] (primul string din argv) are valoarea copyx argv[1] (al doilea string din argv) are valoarea c:\bc5\bin\grep.com argv[2] (al treilea string din argv) are valoarea d:\test\grep.com argv[3] (al patrulea string din argv) are valoarea d

Putem realiza un mic program care sa ilustreze afirmatiile de mai sus. Programul va afisa numarul de parametri primiti (valoarea lui argc) si parametrii respectivi (valorile din argv): //--------------------------------------------------------------------------#include <vcl.h> #include <iostream.h> #include <conio.h> #pragma hdrstop //--------------------------------------------------------------------------#pragma argsused int main(int argc, char* argv[]) { cout << "argc = " << argc << endl; for (int i=0;i<argc;i++) cout << "Parametrul " << i << " este: " << argv[i] << endl; cout << endl << endl << "Apasati orice tasta pentru a continua..."; getch(); return 0; } //--------------------------------------------------------------------------Pentru a simula ca programul este rulat in linie de comanda si primeste niste parametri, inainte de executie ne vom duce in meniul Run, optiunea Parameters si vom introduce in linia Parameters cativa parametri (pentru programul nostru ei nu trebuie sa aibe nici o semnificatie vor fi doar listati, nu si folositi la ceva). Rezultatul ar trebui sa semene cu cel din figura 1.8:

Figura 1.8 Valoarea returnata de main poate fi folosita ca indicator al succesului executiei programului. In cele mai multe programe ea va ramane totusi nefolosita asa ca putem renunta la a returna vreo valoare din functia main: void main(); // nu returneaza nimic, nu primeste parametri void main(int argc, char* argv[]); //nu returneaza nimic 6. Utilizarea masivelor de date (vectori i matrici)

Un masiv de date este o colectie de date de acelasi tip, asezate succesiv intr-o zona continua de memorie. Vectorii si matricile sunt tipuri de masive de date. Spre exemplu la vectorul: int VectorulMeu[5]; compilatorul aloca memorie asa cum este ilustrat in figura 1.9. Pentru ca fiecare variabila de tip int ocupa 4 octeti in memorie, intregul vector va ocupa 20 de octeti: VectorulMeu[0] VectorulMeu[1] VectorulMeu[2] VectorulMeu[3] VectorulMeu[4] adresa de baza a adresa de baza adresa de baza adresa de baza adresa de baza vectorului +4 +8 + 12 + 16 Figura 1.9 Odata vectorul declarat, putem lucra cu fiecare element al vectorului in parte: VectorulMeu[0] = -200; VectorulMeu[1] = -100; VectorulMeu[2] = 0; VectorulMeu[3] = 100; VectorulMeu[4] = 200; Mai tarziu in program putem lucra cu aceste elemente ale vectorului ca si cu variabile independente: int result = VectorulMeu[3] + VectorulMeu[4]; // rezultatul va fi 300 Exista si o metoda de a declara vectorul si de a intializa valorile tuturor elementelor sale intr-o singura operatie: int VectorulMeu[5] = { -200, -100, 0, 100, 200 }; Daca se cunoaste exact numarul de componente si se foloseste metoda de mai sus pentru intializarea elementelor vectorului, nu mai e necesar nici macar sa precizam numarul de elemente al vectorului: int VectorulMeu[] = { -200, -100, 0, 100, 200 }; Matricile sunt masive multidimensionale. Spre exemplu pentru crearea unei matrici bidimensionale de intregi, declaratia ar putea arata asa: int MatriceaMea[3][5]; Aceasta declaratie aloca spatiu pentru 15 variabile intregi (15*4=60 de octeti). Accesarea elementelor matricii se face la fel cu accesarea elementelor unui vector cu deosebirea ca trebuie sa avem un index pentru fiecare dintre dimensiunile matricii: int x = MatriceaMea [1][1] + MatriceaMea [2][1]; Figura 1.10 ilustreaza cum arata matricea declarata mai sus in memorie:

MatriceaMea[0][] (linia 0) MatriceaMea[1][] (linia 1) MatriceaMea[2][] (linia 2)

MatriceaMea[][0] (coloana 0) adresa de baza a matricii adresa de baza + 20 adresa de baza + 40

MatriceaMea[][1] (coloana 1) adresa de baza + 4 adresa de baza + 24 adresa de baza + 44

MatriceaMea[][2] (coloana 2) adresa de baza + 8 adresa de baza + 28 adresa de baza + 48

MatriceaMea[][3] (coloana 3) adresa de baza + 12 adresa de baza + 32 adresa de baza + 52

MatriceaMea[][4] (coloana 4) adresa de baza + 16 adresa de baza + 36 adresa de baza + 56

Figura 1.10 Obs. Trebuie sa fim atenti sa nu suprascriem memoria de dupa sfarsitul unui vector sau al unei matrici. C++ acceseaza direct memoria si nu verifica, inainte de a scrie intr-o anumita zona de memorie daca are de fapt acces la acea zona de memorie sau nu. Din acest motiv elemente de cod precum: VectorulMeu[5] = 150; sau MatriceaMea [3][2]=10; sau MatriceaMea [2][5]=-50; sau MatriceaMea [3][5]=72; desi sunt acceptate de compilator (nu vor duce la aparitia unui mesaj de eroare) vor duce de cele mai multe ori la o terminare fortata a programului (eroare Windows). In cazul in care nu se va ajunge la o iesire fortata din program, rezultatele vor fi oricum impredictibile. Erorile de acest tip sunt comun intalnite, in special la persoanele care au lucrat anterior intr-un limbaj (Ex. Pascal sau Fox) la care numaratoarea liniilor/coloanelor incepe de la 1 si nu de la 0 ca in cazul C-ului si la care ultima linie / coloana este data de numarul de linii/coloane. Mai mult, tipul acesta de eroare este cateodata dificil de diagnosticat (s-ar putea ca programul sa nu iasa fortat de la o o prima executie). Reguli pentru lucrul cu vectori/matrici: - vectorii/matricile incep de la indexul 0. - dimensiunile vectorilor/matricilor trebuie sa fie constante la compilare (adica sunt specificate fie prin precizarea numarului de elemente/linii/coloane fie prin initializarea tuturor elementelor cu valori date. O declaratie de genul: int x=10; int VectorulMeu[x]; va duce la o eroare de compilare. - atentie la scrierea zonelor de memorie de dupa sfarsitul unui masiv. - Masivele de mari dimensiuni e mai bine sa fie alocate dinamic (din heap) decat static (din stack) (vom reveni ceva mai tarziu asupra acestui subiect)

Lectia 2 Intructiunea conditionala if Instructiuni de ciclare: for, do, do-while Instructiunea switch Structuri

if
if este folosit pentru a testa o conditie si a executa apoi sectiunea de cod bazata pe valoarea de adevar (adevarat/fals) a respectivei conditii. Ex:
int x; cout << Introduceti un numar: ; cin >> x; if (x > 10) cout << Ati introdus un numar mai mare ca 10. << endl;

Se cere introducerea unui numar de la utilizator. Daca numarul este mai mare ca 10, expresia x>10 este adevarata si este afisat un mesaj, altfel nu se afiseaza nimic. Nota: Expresia if nu trebuie inchisa cu ; (simbolizeaza o instructiune vida). Daca if este urmat de ; compilatorul va interpreta intructiunea vida ca fiind cea care trebuie executata in cazul in care conditia este evaluate ca fiind adevarata. Ex: if (x==10) ; Functie(x); // in acest cax Functie(x) va fi executat indifferent de valoarea de adevar a conditiei. Pentru a conditiona executia mai multor linii de cod cu expresia if se folosesc accolade pentru incadrarea respectivelor linii.
if (x > 10) { cout << The number is greater than 10 << endl; DoSomethingWithNumber(x); }

Nota: C++ permite folosirea de cod prescurtat. Se poate folosi:


if (fisierData) ReadData();

in loc de forma:

if (fisierData == true) ReadData();

Expresia este evaluate la adevarata atata timp cat variabila contine orice valoare diferita de 0. Se poate testa o conditie falsa aplicand operatorul logic ! (NOT) unei variabile:
if (!fileGood) ReportError();

In anumite cazuri este necesara executia unui cod si in cazul in care conditia este falsa. In acest caz se foloseste expresia else:
if (x == 20) { Functie(x); } else { AltaFunctie(x); }

// in exemplu numai una din cele 2 functii va fi executata in functie de valoarea de adevar a conditiei Se pot folosi in acelasi timp mai multe conditii if:
if (x > 10) if (x < 20) cout << X este intre 10 si 20 << endl;

Sau se pot folosii conditii if-else imbricate:


if (x > 100) { y = 20; if (x > 200) { y = 40; if (x > 400) { y = 60; Functie(y); } } } else if (x < -100) { y = -20; if (x < -200) { y = -40; if (x < -400) { y = -60; Functie(y); } } }

Nota: Editorul C++Builder are o functie utila pentru potrivirea acoladelor. Pozitionati cursorul pe acoloda pentru care doriti sa gasiti corespondenta, si tastati ALT+[ sau ALT+], si cursorul se va pozitiona pe acolada cautata, indifferent daca este cea de inchidere sau deschidere. Daca o sectiune de cod contine mai mult de 3 if-uri imbricate care testeaza diferite valori alea aceeasi variabile, ati putea lua in considerare folosirea expresiei switch. Exista si o versiune scurta a instructiunii conditionale if else: Conditia: if (directia == EAST) lost = true; else (lost = false); Poate fi scrisa ca:

directia == EAST ? lost = true : lost = false;

Instructiuni de ciclare
Instructiunile de ciclare sunt folosite pentru parcurgerea unui vector, pentru a repeat o actiune de un anumit numar de ori, sau pentru a citi fisiere de pe disk. Toate instructiunile de ciclare au comune aceste caracteristici: - un punct de plecare - un corp de instructiuni inchis intre accolade care se executa de fiecare data - un punct de oprire - un test de determinare a conditiei de oprire - folosirea optionala a intructiunii break sau continue. In general intr-o instructiune de ciclare se evalueaza conditia de test, daca acesta conditie este indeplinita corpul de instructiuni este executat. Cand se termina de executat ultima instructiune se sare la inceput si se evalueaza din nou conditia, daca aceasta este adevarata se repeat executia corpului de instructiuni, daca este falsa se sare la executia urmatoarei linii de cod care urmeza dupa blocul de ciclare. Nota: In C++ Builder rulearea unui program se realizeaza cu Run de pe Speed Bar sau apasand F9. Daca aveti nevoie sa terminate un program rulat din IDE, selectati Run|Reset Process din meniu, sau apasati CTRL+F2. Instructiunea for:
for (initial; cond_expr; incrementare) { bloc instructiuni }

Instructiunea repeta executia blocului de instructiuni, cat timp expresia conditionala cond_expr este adevarata. Starea de inceput este initializarea initial, dupa executarea blocului de instructiuni starea este modificata cu ajutorul expresiei de incrementare incrementare. Ex:
for (int i=0;i<10;i++) { cout << Acesta este iteratia << i << endl; }

// codul se executa de 10 ori, I se incrementeaza cu o unitate


for (int i=10;i<10;i--) { cout << Acesta este iteratia << i << endl; }

// i se decrementeaza cu o unitate INtr-o instructiune for variabila initializata poate lua orice valoare doriti, conditia de test poate fi orice expresie valida in C++ care poate avea valoarea de adevar true (adevarata). Cateva exemple de conditii de test:
for (int i=0;i < 100;i++) {...} for (int i=1;i == numarDeElemente;i++) {...} for (int i=0;i <= AflaNumarElemente();i+=2) {...}

Intructiunea while Instructiunea while difera de for, continand numai o conditie de test, care este verificata la fiecare iteratie. Cat timp conditia este adevarata se executa cate o iteratie.
int x; while (x < 1000) { x = executaCalcul(); } // cat timp functia returneaza un numar mai mic ca 1000 se repeta iteratia

Se poate inclementa intructiunea while cu o variabila booleana ca si conditie de test, starea variabilei putand fi setate in interiorul ciclului.
bool done = false; while (!done) { //intructiuni code aici done = FunctieReturneazaBool(); //instructiuni cod }

Exemplu program:

1: #include <iostream.h> 2: #include <conio.h> 3: #pragma hdrstop 4: int main(int argv, char** argc) 5: { 6: cout << endl << Inceput program... << endl << endl; 7: int i = 6; 8: while (i-- > 0) { 9: cout << endl << Today I have << i; 10: cout << problems to worry about.; 11: } 12: cout << \b!\nYipee!; 13: cout << endl << endl << Apasati o tasta pentru continuare...; 14: getch(); 15: return 0; 16: }

Instructiunea do-wile Instuctiunea do-while este asemanatoare cu instructiunea while. Diferenta consta in locul unde se face evaluarea conditiei de test, daca while verifica expresia de iesire din ciclu la inceput, dowhile face verificarea la sfarsit dupa executia blocului de cod, astfel corpul de instructiuni se executa cel putin odata chiar daca expresia de test este falsa.
bool done = false; do { // some code done = SomeFunctionReturningABool(); // more code } while (!done)

Instructiunea goto Aceasta instructiune permite saltul in executia unui program, la o eticheta declarata in prealabil prin un nume_eticheta urmat de :.
bool done = false; startPoint: // executa instructiuni if (!done) goto(startPoint); // dupa salt, executare instructini...

Nota: Este recomandat ca acesta instructiune sa nu fie utilizata. In C++ ea poate fi inlocuita usor de instructiunile do-while sau while. Intructiunile continue si break Cele doua instructiuni ajuta la controlul executiei codului in instructiunile de ciclare. De exemplu, ati putea avea un ciclu in care nu doriti sa executati anomite instructiuni daca un anumit test este adevarat. In acest caz se va folosi continue pentru a face salt la inceputul ciclului si evitarea executiei oricarui cod de dupa continue din interiorul iteratiei.:
bool done = false; while (!done) { // instr cod bool error = Functioe(); if (error) continue; // sare la inceputul ciclului // alt cod ce se executa numai daca nu apare o eroare }

Instructiunea break este folosita pentru a opri executia unei instructiuni de ciclare, inainte de indeplinirea conditiilor de oprire normale ale instructiunii. De exemplu, la cautarea unui numar intr-un vector, prin oprirea executiei ciclului de cautare puteti obtine indexul vectorului unde este localizat respectivul numar:
int index = 0; int cautaNumar = 50; for (int i=0;i<numElemente;i++) { if (myArray[i] == cautaNumar) { index = i; break; } if (index) cout << Numar gasit la index << index << endl; else cout << Numarul nu a fost gasit in vector. << endl;

Instructiunea switch Instructiunea switch permite executarea unui bloc de instructiuni din mai multe posibilitati in fuctie de rezultatul evaluarii unei expresii. Evaluarea se poate face dupa o variabila, rezultatul apelului unei functii sau orice alta expresie C++ care poate fi evaluata. Ex: switch(cantitate) { case 0 : { fine = 0; break; }

case 10 : { fine = 20; break; } case 15 : { fine = 50; break; } case 20 : case 25 : case 30 : { fine = cantitate * 10; break; } default : { fine = Functie1(); jailTime = Functie2(); } } Intructiune switch contine mai multe parti: expresia al carui rezultat este evaluat cantitate, expresia case care testeaza rezultatul pentru egalitate (case 0 daca cantitate egal 0 ) si executa un cod in acest caz. Se foloseste break petru a iesi din instructiunea switch dupa executia blocului specific rezultatului, altfel s-ar putea executa si alt cod nedorit din switch. Putem avea si un cod default care se executa in caz ca nu a existat nici un caz potrivit. Folosirea lui default este optionala. In cazul un care dupa un caz nu avem un bloc de instructiuni, pentru acel caz/cazuri se executa primul bloc de intructiuni pana la intalnirea lui break. Vizibilitatea variabilelor Majoritatea variabilelor sunt locale, adica sunt vizibile numai in interiorul bloclui de cod in care sunt declarate. Ex: 1: #include <iostream.h>
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: #include <conio.h> #pragma hdrstop int x = 20; void CountLoops(int); int main(int, char**) { int x = 40; int i = 0; cout << In main program x = << x << endl; bool done = false; while (!done) { int x; cout << endl << Enter a number (-1 to exit): cin >> x;

16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:

} cout << Global x = << ::x << endl; cout << endl << Press any key to continue...; getch(); return 0; } void CountLoops(int x) { cout << , While loop has executed << x << times << endl; }

if (x != -1) { cout << endl << In while loop x = << x; CountLoops(++i); } else done = true;

In exemplu de mai sus varibila x este declarata de 4 ori. Daca din greseala o variabila este declarata de mai multe ori compilatorul va da un mesaj de eroare, in acest caz insa programul va rula pentru ca respectiva variabila, x, este vizibila numai in anumite blocuri. Declararea variabilei x in linia 13 este in interiorul cilcului while si este vizibila numai in acel bloc, lafel in linia 28 unde declararea este in interiorul unei functii si nu exista in afara ei. In cazul declaratiei de linia 8, este vizibil in interiorul functiei main si ar putea aparea confuzii cu folosirea lui x in ciclul while. In acest tip de situatii este folosita variabila cea mai apropiata de blocul de cod, adica cea din while. Declararea din linia 4 este exterioara oricarei functii, acea variabila este vizibila peste tot in program si este o variabila globala. Accesul la o variabila globala se face cu operatorul de rezolutie ::. Variabile externe O aplicatie are de obicei mai multe fisiere/module care contin codul sursa. O variabila globala declarata intr-un modul este vizibila in acel fisier insa nu este acesibila in celelalte module. Pentru a fi accesibila si in alte module o variabila globala trebuie declarata si in modulul in care se doreste ca ea sa fie accesibila. Declararea in module se realizeaza folosindu-se cuvantul cheie extern: extern int varGlobala; Structuri O structura este o colectie de campuri de date grupate intr-o singura unitate de memorie. Declararea unei structuri se face cu cuvantul cheie struct: struct mailingListRecord { char firstName[20]; char lastName[20]; char address[50]; char city[20];

char state[4]; int zip; bool aFriend; bool aFoe; }; Fiecare element al structurii este o data membra si se declara ca o variabila intr-un bloc de cod. Declararea unei structuri se termina cu ;. In momentul definirii structurii se pot declara si variabile (instante) prin inserarea numelui respectivelor variabile, separate de virgula, intre acolada de inchidere si ;. Pentru accesarea campurilor member dintr-o structura se foloseste operatorul ., care se pune intre numele variabilei si numele campului membru. Tablouri de structuri La fel ca si vectorii de tipuri fundamentale de date (int, char), se pot crea vectori de structuri. Declararea si folosirea unei vector de structuri: mailingListRecord listArray[5]; strcpy(listArray[0].firstName, Chuck); listArray[4].aFoe = true; // grrrrr!! // etc. Headere si fisiere sursa Fisierele sursa sunt fisiere in cod ASCII care contin cod sursa pentru un program. Declaratiile de clase si structuri, functii sunt deregula separate de restul codului unui program in fisiere numite header. Headere-le sunt fisiere cu extensia .h sau .hpp. Odata creat un header acesta se poate include in orice modul care foloseste respectivele definitii de clase sau structuri din header, cu ajutorul directivei #include: # include fisierHeader.h Exemplu de program care foloseste structuri:
Listing STRUCTUR.H. 1: #ifndef _STRUCTUR_H 2: #define _STRUCTUR.H 3: struct mailingListRecord { 4: char firstName[20]; 5: char lastName[20]; 6: char address[50]; 7: char city[20]; 8: char state[5]; 9: int zip; 10: }; 11: #endif

//programul principal: 1: #include <iostream.h> 2: #include <conio.h> 3: #include <stdlib.h> 4: #pragma hdrstop 5: #include structur.h

6: void displayRecord(int, mailingListRecord mlRec); 7: int main(int, char**) 8: { 9: // 10: // create an array of mailingListRecord structures 11: // 12: mailingListRecord listArray[3]; 13: cout << endl; 14: int index = 0; 15: // get three records 16: // 17: do { 18: cout << First Name: ; 19: cin.getline(listArray[index].firstName, 20: sizeof(listArray[index].firstName) - 1); 21: cout << Last Name: ; 22: cin.getline(listArray[index].lastName, 23: sizeof(listArray[index].lastName) - 1); 24: cout << Address: ; 25: cin.getline(listArray[index].address, 26: sizeof(listArray[index].address) - 1); 27: cout << City: ; 28: cin.getline(listArray[index].city, 29: sizeof(listArray[index].city) - 1); 30: cout << State: ; 31: cin.getline(listArray[index].state, 32: sizeof(listArray[index].state) - 1); 33: char buff[10]; 34: cout << Zip: ; 35: cin.getline(buff, sizeof(buff) - 1); 36: listArray[index].zip = atoi(buff); 37: index++; 38: cout << endl; 39: } 40: while (index < 3); 41: // 42: // clear the screen 43: // 44: clrscr(); 45: // 46: // display the three records 47: // 48: for (int i=0;i<3;i++) { 49: displayRecord(i, listArray[i]); 50: } 51: // 52: // ask the user to choose a record 53: // 54: cout << Choose a record: ; 55: char rec; 56: // 57: // be sure only 1, 2, or 3 was selected 58: // 59: do { 60: rec = getch(); 61: rec -= 49; 62: } while (rec < 0 || rec > 2);

63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88:

} void displayRecord(int num, mailingListRecord mlRec) { cout << Record << num + 1 << : << endl; cout << Name: << mlRec.firstName << ; cout << mlRec.lastName; cout << endl; cout << Address: << mlRec.address; cout << endl << ; cout << mlRec.city << , ; cout << mlRec.state << ; cout << mlRec.zip; cout << endl << endl; }

// // assign the selected record to a temporary variable // mailingListRecord temp = listArray[rec]; clrscr(); cout << endl; // // display the selected record // displayRecord(rec, temp); getch(); return 0;

Saptamana 4 Clase si programarea orientata pe obiecte


O clasa, asemanator cu o structura, este o colectie de date membre si functii specifice pentru realizarea unui anumit task. Putem spune ca o clasa incapsuleaza respectivul task.

Clase nivel de access Clasele pot avea trei nivele de acces: private, public si protected. Nivelul de acces controleaza modul in care utilizatorii au acces la o clasa. Orice clasa are o parte publica care este modalitatea de interactiune cu userii si o parte privata implementarea interna la care nu se permite accesul din exterior. Specificatorii de acces sunt utilizati in declararea unei clase: class Vehicle { public: bool haveKey; bool Start(); void SetGear(int gear); void Accelerate(int acceleration) void Break(int factor); void Turn(int direction); void ShutDown(); protected: void StartupProcedure(); private: void StartElectricalSystem(); void StartEngine(); int currentGear; bool started; int speed; }; Membrii unei clase care au specificatorul de acces protected pot fi accesati doar din clasele derivate nu direct de catre utilizatorii clasei. Daca nu se specifica nici un nivel de acces membrii clasei sunt setati default private. Constructori Constructorul este o functie a unei clase care se apeleaza automat cand se instantiaza o clasa. Constructorul este folosit pentru initializarea oricarei variabile membre a clasei, alocarea memoriei pentru clasa sau orice alt task de initializare. In momentul in care nu se specifica un constructor compilatorul C++Builder va crea automat un constructor implicit. Constructorul are acelasi nume cu clasa.
class Vehicle { public: Vehicle(); // constructor bool haveKey; bool Start(); void SetGear(int gear); void Accelerate(int acceleration); void Break(int factor); void Turn(int direction); void ShutDown(); protected: void StartupProcedure(); private: void StartElectricalSystem(); void StartEngine(); int currentGear; bool started;

int speed; };

Observati ca un constructor nu are un tip returnat, un constructor nu returneaza nici o valoare. O clasa poate avea mai multi constructori. De exemplu putem avea o clasa cu un constructor fara parametrii - constructor implicit si un constructor cu parametrii care initializaeaza anumite variabile membre cu valori specifice. Ex : class Rect {
public: Rect(); Rect(int _left, int _top, int _bottom, int _right); int GetWidth(); int GetHeight(); void SetRect(int _left, int _top, int _bottom, int _right); private: int left; int top; int bottom; int right; };

Definitia constructorilor este:


Rect::Rect() { left = 0; top = 0; bottom = 0; right = 0; } Rect::Rect(int _left, int _top, int _bottom, int _right) { left = _left; top = _top; bottom = _bottom; right = _right; }

Nota : Instantierea este procesul de creere a unui obiect, instanta a unei clase. Apelarea unui constructor se face la instantierea unei clase. Pentru clasa definita anterior putem avea doua moduri de instantiere, cu constructorul implicit si cu cel cu parametrii:
Rect rect1; // object created using default constructor Rect rect2(0, 0, 100, 100); // created using 2nd constructor

Liste de initializare C++ permite initializarea datelor member ale unei clase intr-o lista de initializare. Exemplul de folosire pentru cei doi constructori definiti anterior este:
Rect::Rect() : left(0), top(0), bottom(0), right(0) { } Rect::Rect(int _left, int _top, int _right , int _bottom) : left(_left), top(_top), bottom(_bottom), right(_right) { }

Observati ca lista de initializare este precedata de un bloc de acolade. De asemenea fiecare variabila din lista este urmata de , exceptie facand ultima variabila.

Destructori Destructorul este o functie speciala, care se apeleaza automat la distrugerea unui obiect. Poate fi considerat inversul constructorului si este folosit la eliberarea memoriei alocate obiectului distrus. Un destructor nu returneaza nici o valoare si nu are nici parametrii. Numele destructorului este numele clasei precedat de simbolul tilda (~). Ex : class Rect {
public: Rect(); Rect(int _left, int _top, int _bottom, int _right); ~Rect(); // destructor added int GetWidth(); int GetHeight(); void SetRect(int _left, int _top, int _bottom, int _right); private: int left; int top; int bottom; int right; char* text; // new class member added }; Rect::Rect() : left(0), top(0), bottom(0), right(0) { text = new char[256]; strcpy(text, Any Colour You Like); } // code omitted Rect::~Rect() { delete[] text; }

Destructorul acestei clase elibereaza memoria alocata unui vector de caractere text. Date membre Atributele unei clase sunt variabile definite in interiorul unei clase, si care au definite specificatori de access. Datele membre ale unei clas esunt accesibile in toate functiile clasei indiferent de specificatorii de acces. In exteriorul unei clase sunt vizibile numai datele declarate public, cele private si protected neputand fi accesate. Pentru accesul la datele membre private ale unei clase se folosest functii publice ale unei clase pentru setarea si returnarea datelor membre. Un exemple de functii de setare si returnare:
int Rect::GetLeft() { return left; } void Rect::SetLeft(int newLeft) { left = newLeft; } TRect rect; int x = rect.GetLeft();

Pentru utilizare folosim: Functii member

Functiile membre sunt functii care apartin unei clase. Apelul lor se poate face doar din interiorul clasei sau printr-o instanta a clasei. Ele au acces la toti membrii clasei membr indifferent de specificatorii de acces.

Functiile membre au specificatori de acces in functie de modul de utilizare. Functiile publice sunt o interfata a clasei cu exteriorul, prin ele se pot accesa date ale clasei. Functiile private sunt folosite intern (ex. Functii de initializare a datelor membre care pot fi apelate de constructori). Declarearea functiilor membre se poate face in doua feluri. Cu definirea functiei in exteriorul clasei, caz in care se foloseste cuvantul cheie inline si numele functiei este precedat de numele clasei si operatorul de rezolutie:
ClassName { public: ReturnType FunctionName(); }; inline ReturnType ClassName::FunctionName() { statements } ClassName { public: ReturnType FunctionName() { statements } };

Sau in interiorul clasei:

Pointerul this Toate clasele au o variabila membru ascunsa, pointerul this, un pointer la instanta clasei respective in memorie. Cand se instantiaza o clasa, pointerul this este automat initializat cu adresa respectivei clase in memorie. Ex:
void __fastcall TMyForm::Button1Click(TObject *Sender) { TButton* button = new TButton(this); button->Parent = this; button->Caption = New Button; button->Left = 100; button->Top = 100; button->Show(); // more code } // se asigneaza proprietatii Parent a butnoului pointerul this

Mostenire Una din cele mai importante insusiri ale unei clase C++ este posibilitatea de extindere prin mostenire. Mostenirea inseamna crearea unei noi clase pornind de la o clasa de baza prin adaugarea de noi functionalitati. Clasa de la care se pleaca se numeste clasa de baza iar clasa nou obtinuta se numeste clasa derivata. La definirea unei clase derivate se pune dupa numele clasei : si numele clasei de baza:
class MilitaryPlane : public Airplane { public: MilitaryPlane(char* name, int _type); virtual int GetStatus(char* statusString); protected: virtual void TakeOff(); virtual void Land() virtual void Attack(); virtual void SetMission(); private: Mission theMission; };

Folosirea cuvantului cheie virtual in fata declararii unei functii, defineste o functie virtuala. O functie virtuala este o functie care va fi apelata automat daca o functie cu acest nume exista in clasa derivata. Intr-o clasa derivate, se poate inlocui definitia unei functii existente in clasa de baza. Acest procedura poarta denumirea de suprascriere a unei functii. Suprascrierea se foloseste pentru a modifica actiunile functiei din clasa de baza sau pentru a-i mari functionalitatea. La suprascriere se foloseste exact acelasi antet al functiei din clasa de baza. Ex: void MilitaryPlane::TakeOff(int dir)
{ // new code goes here } //cazul in care se inlocuieste total codul

Daca se doreste imbunatatirea functiei prin suprascriere atunci in declarare se va apela functia din clasa de baza:
void MilitaryPlane::TakeOff(int dir) { Airplane::TakeOff(dir); // new code goes here }

Operatorul de rezolutie se foloseste numai in cazul in care avem functii din clasa de baza si derivate cu acelasi nume si antet, orice alta functie publica sau protejata din clasa de baza poate fi apelata direct. La derivarea unei clase trebuie sa apelati constructorul claselor de baza ca sa fiti sigur ca toate clasele parinte sunt initializate corect.
MilitaryPlane:: MilitaryPlane(char* _name) : Airplane(_name, MILITARY) // call base class { // body of constructor }

Exemplu de clase derivate:

Mostenire multipla Derivarea unei clase din doua sau mai multe clase de baza se numeste mostenire multipla.
class Fighter : public MilitaryPlane, public Armaments { public: Fighter(char* name); private: // other stuff };

La definire clasele de baza sunt scrise separate prin virgula, de asemenea la apelul constructorului clasei derivate se apeleaza si toti constructorii din clasele de baza. Exemplu de mostenire multipla:

Lucrul cu fisiere I/O Atunci cand doriti sa realizati aplicatii care sa citeasca sau sa scrie in fisiere veti apela la fluxuri de I/O. Lucrul cu fluxuri de I/O in C++Builder se realizeaza prin intermediul a 3 clase: - ofstream se ocupa de iesiri - ifstream se ocupa de intrari - fstream atat iesiri cat si intrari Fluxuri de intrare
1: #include <condefs.h> 2: #include <stdio.h> 3: #include <stdlib.h> 4: #include <iostream.h> 5: #include <fstream.h> 6: #include <conio.h> 7: #pragma hdrstop 8: 9: int main(int argc, char **argv) 10: { 11: char buff[80]; 12: ifstream infile; 13: infile.open(readfile.cpp); 14: if (!infile) return 0; 15: while (!infile.eof()) { 16: infile.getline(buff, sizeof(buff)); 17: cout << buff << endl; 18: } 19: infile.close(); 20: cout << endl << Press any key to continue...; 21: getch(); 22: return 0;

23: }

Citirea dintr-un fisier se face prin instantierea clasei ifstream (obiectul infile), deschiderea fisierului cu metoda open asociata clasei si inchiderea prin metoda close.Pentru a se citi o linie se foloseste functia getline si verificarea ajungerii la sfarsitul fisierului se face cu eof(). Nota: calea fisierului la deschidere se da folosind backslash dublu, iar initializarea instantei clasei ifstream si deschiderea fisierului se pot face si intr-o singura linie:
ifstream infile(c:\\windows\\win.ini);

La citirea unor variabile dintr0un fisier se poate folosi si operatorul de extractie (>>) care se opreste la intalnirea unui spatiu.
ifstream infile(somefil.dat); while (!infile.eof()) { int x; infile >> x; // read number from file and assign it to x cout << x << endl; }

Fluxuri de iesire La scrirea intr-un fisier procedura este asemanatoare cu citirea. De acesta data se initializeaza clasea ofstream si se foloseste operatorul de insertie (<<) pentru scrierea efectiva.
1: #include <condefs.h> 2: #include <stdio.h> 3: #include <stdlib.h> 4: #include <iostream.h> 5: #include <fstream.h> 6: #include <conio.h> 7: 8: #pragma hdrstop 9: 10: int main(int argc, char **argv) 11: { 12: char buff[81]; 13: cout << Creating File... << endl; 14: ofstream outfile(test.dat); 15: if (!outfile) return 0; 16: cout << Writing File... << endl; 17: for (int i=0;i<10;i++) { 18: outfile << This is line # << i + 1 << endl; 19: } 20: outfile.close(); 21: cout << Opening File for Input... << endl; 22: ifstream infile(test.dat); 23: if (!infile) return 0; 24: cout << Reading File... << endl << endl; 25: while (!infile.eof()) { 26: infile.getline(buff, sizeof(buff)); 27: cout << buff << endl; 28: } 29: infile.close(); 30: cout << endl << Press any key to continue...; 31: getch(); 32: return 0; 33: }

Moduri deschidere fisiere In momentul folosirii fisierele pot fi deschise in mai multe feluri. In mod implicit deschiderea unui fiser cu clasa ofstream este in modul creare fiser. Daca fisierul deschis exista acesta se va suprascrie. Pentru a specifica modul adaugare la deschidere va trebui specificat unul din modurile de deschidere (open_mode) ale clasei ios.
ofstream outfile(test.dat, ios::app);

specificatori open_mode ai clasei ios:

app - deschidere pt adaugare ate cautarea sfarsitului fisierului cand se dechide in deschidere pentru citire, implicit pentru clasa istream out deschidere pentru scriere , implicit pentru clasa ostream binary - deschidere in mod binary trunc deschide un fisier si sterge continutul nocreate fisierul nu va fi creat daca nu exista noreplace similar cu nocreate Puteti specifica in acelasi timp mai multe moduri de deschiderea a fisierelor,
ofstream outfile(test.dat, ios::app | ios::binary);

ceea ce inseamna deschidere in mod binary si adaugare la sfarsitul fisierului.