PROGRAMAREA ORIENTATĂ PE OBIECTE
ÎNDRUMAR DE LABORATOR
Liviu Şerbănescu UNIVERSITATEA HYPERION
LISTA LUCRĂRILOR
1. Iniţiere într-un mediu de programare. Structura unui program C++. 2. Noţiunea de clasă şi obiect. Operatori specifici C++. 3. Clase şi moşteniri. Clase de bază virtuale 4. Constructori şi destructori 5. Modificatorii şi specificatorii de acces 6. Date şi funcţii de tip friend şi statice 7. Polimorfism, funcţii virtuale 8. Supraîncărcarea operatorilor 9. Fluxuri de intrare/ieşire.Obiecte standard 10. Fluxuri de intrare/ieşire.Operatii de intrare/iesire cu fisiere 11. Tratarea excepţiilor 12. Utilizarea claselor wxWidgets (I) 13. Utilizarea claselor wxWidgets (II) 14. Teste.
LISTA LUCRĂRILOR
1. Iniţiere într-un mediu de programare. Structura unui program C++. 2. Noţiunea de clasă şi obiect. Operatori specifici C++. 3. Clase şi moşteniri. Clase de bază virtuale 4. Constructori şi destructori 5. Modificatorii şi specificatorii de acces 6. Date şi funcţii de tip friend şi statice 7. Polimorfism, funcţii virtuale 8. Supraîncărcarea operatorilor 9. Fluxuri de intrare/ieşire.Obiecte standard 10. Fluxuri de intrare/ieşire.Operatii de intrare/iesire cu fisiere 11. Tratarea excepţiilor 12. Utilizarea claselor wxWidgets (I) 13. Utilizarea claselor wxWidgets (II) 14. Teste.
LABORATORUL NR.1 INIŢIERE ÎNTR-UN MEDIU DE PROGRAMARE. STRUCTURA UNUI PROGRAM C++ Scop:
1. Familiarizarea cu mediul integrat CodeLite. 2. Înţelegerea structurii unui program scris în limbajul C++. 3. Înţelegerea bibliotecilor ce utilizează programarea orientată o rientată pe obiecte.
Consideraţii teoretice:
Mediul integrat - OpenSource - CodeLite Un spaţiu de lucru ( workspace ) detine un numar de proiecte, de exemplu, acestea pot avea legătură l egătură unele cualtele sau nu Crearea unui spaţiu de lucru se realizează prin selectarea " "Workspace "Workspace | Create new Workspace"" Un proiect (project) poate avea va rezultat în urma compilării şi apoi a link-editării un executabil, o bibliotecă dinamică (* .DLL), o bibliotecă statică(*.LIB), etc. Proiectul în sine conţine toate informaţiile necesare pentru a produce o aplicaţie de un anumit tip (aplicaţie consolă, aplicaţie grafică ce utilizează un anumit set de controale vizuale, aplicaţie cu obiecte grafice, etc). Fişierul ce conţine informaţii despre spaţiul de lucru se numeşte
.workspace Fişierul ce conţine informaţii despre proiect este . prj Pentru crearea unui proiect nou se va utiliza opţiunea GUI (Graphics User Interface).
Structura unui program C++
Un programC++ cuprinde următoarele elemente pricipale: ✗
operatori (aritmetici, logici, etc)
✗
instrucţiuni (de decizie, de parcurgere a unei bucle, etc)
✗
funcţii (apelate din cadrul bibliotecilor sau definite de utilizator)
✗
variabile şi constante
✗
funcţia main()
Textul unui program poate fi scris într-un fişier sau în mai multe fişiere. Un program va avea o singură funcţie main() indiferent dacă este scris într-un singur fisier sau în mai multe fişiere. Programul compilat şi linkeditat va incepe întodeauna prin lansarea în execuţie a instrucţiunilor şi funcţiilor din cadrul lui main(). Prin ieşirea din funcţia main() se încheie şi execuţia programului.
Desfăşurarea lucrării:
1. Lansarea Lansarea mediului mediului CodeLite, CodeLite, şi studier studierea ea principale principalelor lor componente componente ale interfe interfeţei ţei acestuia 2. Crearea Crearea unor unor spaţi spaţiii de lucru lucru 3. Crearea Crearea unui unui proiect proiect pentru pentru aplicaţie aplicaţie consolă consolă 4. Compilarea Compilarea unui unui exemplu. exemplu. Modifica Modificarea rea setărilor setărilor implicite implicite de compilare compilare.. 5. Executarea Executarea separată separată aLink-edit aLink-editării ării pentru pentru o aplicaţie. aplicaţie. Modificarre Modificarreaa setărilor setărilor implicite pentru link-editare 6. Adăuga Adăugarea rea bibl bibliote iotecil cilor or cu clas clase. e. 7. Recomp Recompila ilarea rea (avân (având d şi bibliot biblioteci eci cu clase clase)) 8. Reli Relink nked edita itarea rea .
LABORATORUL NR.2 NOŢIUNEA DE CLASĂ ŞI OBIECT. OPERATORI SPECIFICI C++ Scop:
1. Înţelegerea noţiunilor de clasă şi obiect 2. Înţelegerea operatorilor specifici C++ Consideraţii teoretice:
CONCEPTE FUNDAMENTALE Ideea de baza de la care pleaca programarea orientata obiect este de a grupa structurile de date cu operatiile care prelucreaza respectivele date. Un asemenea ansamblu poarta denumirea de obiect sau clasa (tipul datei). Proiectarea de programe utilizand clase se numeste programare orientat pe obiecte (OOP- Object Oriented Programming). Notiuni fundamentale: Datele (membrii) şi funcţiile (membrele / metodele) unei clase
Datele sunt reprezentate prin declarațiile variabilelor din cadrul clasei. În cadrul unei clase pot fi declarate inclusiv variabile de tip structură sau de tip clasă. Date + Metode = Obiect sau Clasă (tipul datei) Principiul încapsulării (ascunderea informaţiei ce stă la baza realizării clasei): accesul la datele membre se poate face numai prin intermediul setului de metode asociat. Obiectul este caracterizat complet prin metodele asociate. O parte din metode vor fi utilizate de cel ce utilizează clasa în cadrul aplica țiilor, iar altă parte va fi invizibilă pentru utlizatorul final (atât codul cât și apelul acestora). Conform principiului încapsulării utilizatorul nu are acces la date ci numai la metodele pe care dezvoltatorul clasei le-a lăsat pentru a putea fi apelate. Operatorii specifici C++
OPERATORUL
SIMBOLU L
FORMA
Operaţia realizată - accesează variabilele globale chiar dacă au acelaşi nume cu cele locale - accesează membrii/membrele claselor - întoarce valoarea (OB valoare) - întoarce valoarea (OB pointer) alocă memorie. ex ptr. un vector de 10 întregi: new int[10], întoarce NULL în caz de eşec altfel întoarce adresa alocată eliberează zona de memorie
rezoluţie / indicator acces
::
::a ::f()
valoare valoare
.* ->*
OB.*a OB->*a
new
new
new tip
delete
delete
delete a delete a[]
this
this
this/ *this
arată adresa obiectului curent (în care ne aflăm) iar *this este valoarea obiectului curent
Desfăşurarea lucrării:
1. Se execută exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.3 CLASE ŞI MOŞTENIRI. CLASE DE BAZĂ VIRTUALE Scop:
1. Înţegerea moştenirii claselor 2. Utilizarea funcţiilor şi a claselor de bază virtuale Consideraţii teoretice:
Procedeul de derivare permite definirea unei clase noi, numită clasă derivată, care moşteneşte propietăţile (membri + membre) unei clase deja definite, numită clasă de bază, pe care le completează cu propietăţi (membri+membre) noi. Clasa de bază nu este afectată şi nu trebuie recompilată, declaraţia (fişierul header) şi codul obiect (fişier obj / dll/ lib) ale clasei de bază sunt suficiente pentru crearea unei clase derivate. Dintr-o clasă (numită clasă de bază) pot fi derivate mai multe clase, iar fiecare clasă derivată poate servi ca bază pentru alte clase derivate. Astfel se realizează o ierarhie de clase. Pornind de la clase simple şi generale, fiecare nivel al ierarhiei acumulează caracteristicile (membri +membre) claselor "părinte" (bază) şi le adaugă un anumit grad de specializare. În cazul în care o clasă moşteneşte proprietăţile mai multor clase avem moştenire multiplă. Sintaxa declaraţia clasei derivate în cazul unei singure clase de bază: class nume_clasa_derivata : modificator_acces nume_clasă_baza iar în cazul mai multor clase de bază (moştenire multiplă): class nume_clasa_derivata : modificator_acces nume_clasă_baza_1 [<, modificator_acces nume_clasă_baza_n >]
Funcţiile constructor, destructor şi mecanismul de moştenire Clasa de bază, clasa derivată, sau ambele, pot avea funcţii constructor şi/sau destructor. Când o clasă de bază şi una derivată conţin atât funcţii constructor cât şi destructor, cele constructor sunt executate în ordinea derivării iar funcţiile destructor sunt executate în ordine inversă. Adică duncţia constructor din clasa de bază este executată înaintea celei din clasa derivată iar destructorul unei clase derivate este executat înaintea celui din clasa de bază. Când se explicitează costructorul din clasa derivată trebuie să se specifice care din constructorii clasei de bază este apelat ( constructorii diferă între ei - în momentul declarării - prin numărul şi tipul argumentelor) De asemenea, primele argumente din constructorul clasei derivate trebuie să coincidă cu argumentele constructorului ales din clasa de bază. Sintaxa este: nume_clasă_derivată::nume_clasă_derivată(lista_argumente_1,lista_argumente_2):nume_clas a_baza (lista_argumente_1v) { corpul constructorului } unde: lista_agumente_1 este lista de argumente a constructorului bazei (tipuri +variabile), lista_agumente_1v este lista de argumente a constructorului bazei (variabile) iar lista_agumente_2 este lista de argumente a suplimentară, specifică constructorului clasei derivate (tipuri +variabile) iar în cazul moştenirii multiple sintaxa este: nume_clasă_derivată::nume_clasă_derivată (lista_argumente_1, lista_argumente_2):nume_clasa_baza_1(lista_argumente_11v)[<, nume_clasa_baza_n(lista_argumente_n1v) >] { corpul constructorului } unde lista_argumente_n1v sunt incluse în lista_argumente_1v
Clase de bază virtuale Presupunem ca avem o clasă BAZA şi două clase ce derivă din BAZA, numite DER1 şi DER2. Apoi din DER1 şi DER2 derivăm o altă clasă denumită DER12 . Deci, clasa DER12 moşteneşte de două ori clasa BAZA, o dată prin DER1 şi o dată prin DER2. Acest lucru determină o ambiguitate când clasa DER12 vrea să aibă acces la datele din clasa BAZA. (de ex. pot fi date din clasa BAZA, modificate în cadrul clasei DER1
sau modificate în cadrul clasei DER2 - atât DER1 cât şi DER2 au câte o copie a clasei BAZA). Pentru a rezolva această ambiguitate, C++ include un mecanism prin care doar o copie a clasei BAZA va fi inclusă în clasa DER12. Acesta constă în declararea clasei BAZA ca fiind clasa de bază virtuală. Se utilizează cuvântul cheie virtual înaintea modificatorului de acces. (ex: class DER1: virtual public BAZA {}; class DER2: virtual public BAZA {}; class DER12: public DER1, public DER2 {}; #include #include //mostenire de tip - diamant class A{ int a1,a2; public: A() {a1=0;a2=0;} A(int a1_,int a2_) {a1=a1_;a2=a2_;} void afis() {std::cout<<"/n a1="<>m;//astapta o tasta return 0; } // cuvantul cheie virtual permite eliminarea duplicatelor clasei A
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.4 CONSTRUCTORI ŞI DESTRUCTORI
Scop:
1. Utilizarea constructorilor 2. Utilizarea destructorilor 3. Înţegerea ordinii de apel a constructorilor 4. Înţelegerea ordinii de apel a destructorilor Consideraţii teoretice: CONSTRUCTORI:
Constructorul se apelează automat la crearea fiecărui obiect al clasei, creare de tip static, automatic sau dinamic; Funcţia constructor are acelaşi nume cu al clasei (case sensitive); O clasă poate avea mai mulţi constructuri, ei se deosebesc prin numărul şi tipul argumentelor; In cazul în care nu se scrie nici un constructor se va apela automat un constructor, fără argumente şi de tip public. Dacă utilizatorul declară cel puţin un constructor atunci compilatorul nu mai generează acest constructor implicit; Există şi un constructor implicit de copiere ce iniţializează obiectul curent cu datele (membrii) din alt obiect de acelaşi tip (aparţinând aceleiaşi clase) El are forma nume_clasă(nume_clasa &)şi poate fi redefinit; Constructorii nu întorc valori; Constructorii sunt apelaţi automat după ce se se alocă memorie (automatic sau static) pentru obiectele membru (date membru /membrii)
DESTRUCTORI:
Destructorul este apelat automat când obiectul respectiv îşi încetează existenţa în memorie. Destructorul are acelaşi nume cu al clasei şi se declară cu operatorul ~ inainte; Utilizatorul nu va putea apela explicit destructorul unei clase; Destructorul nu preia şi nu întoarce valori; O clasă are un singur destructor; In cazul în care nu este declarat nici un destructor se va apela unul implicit; Destructorii sunt apelaţi automat înaintea eliberării memoriei alocată automatic sau static pentru datele membru.
Explicitarea funcţiilor membre (inclusiv a constructorilor şi destructorilor) se poate face fie în interiorul declaraţiei clasei, fie în exteriorul clasei prin utilizarea operatorului rezoluţie " :: ". Funcţiile din cadrul unei clase se pot clasifica în: - constructori; - destructori; - funcţii normale de acces; - funcţii de tip prieten ( friend ); - funcţii virtuale; - funcţii statice;
- funcţii de tipul operator. Exemplu: #include #include using namespace std; class A3 { public: int a1; protected: int a2; private: int a3; public: A3(int a1_) { a1=a1_;a2=0;a3=0;//cout<<"\n constructor A3(a1)<
class B3:protected A3 {int b3; protected: int b2; public: int b1; B3(int a1_, int b1_):A3(a1_) {b1=b1_;b2=0;b3=0; //cout<<"\n constructor B3(a1,b1)<
Exemplu: #include #include #include using namespace std;
class A{ protected: char *sir; unsigned long dim; public: A(unsigned long dim1); A(char *); void prel(); void afis(); ~A(); }; A::A(unsigned long dim1) { dim=dim1; if((sir=new char[dim])==NULL) cout<<"Memorie insuficienta"; memset(sir,0,dim*sizeof(char)); } A::A(char* sir1) { strcpy(sir,sir1); dim=strlen(sir); } A::~A() { if(sir) delete[] sir; } void A::prel() { //cin>>sir; scanf("%s",this->sir); } void A::afis() { cout<<"\n Sirul este:"<
class A1:public A { char *sir_ord_cresc; public: A1(unsigned long dim1):A(dim1) { sir_ord_cresc = new char[dim]; } A1(char * sir1):A(sir1) {sir_ord_cresc = new char[dim];} bool cauta_caracter(char x) { for(int i=0;i
if(sir_ord_cresc[i-1]>sir_ord_cresc[i]) { sir_ord_cresc[i-1]=sir_ord_cresc[i-1]^sir_ord_cresc[i]; sir_ord_cresc[i]=sir_ord_cresc[i-1]^sir_ord_cresc[i]; sir_ord_cresc[i-1]=sir_ord_cresc[i-1]^sir_ord_cresc[i]; ordonat=false; } }while(!ordonat); } /*void afis() { cout<<"\n Sirul ordonat este:"<>m; return 0; }
Desfăşurarea lucrării:
1. Se rulează exemplul din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.5 MODIFICATORII ŞI SPECIFICATORII DE ACCES Scop:
1. Înţelegerea noţiunilor de privite, protected şi public 2. Utilizarea modificatorilor de acces în cadrul constructorilor 3. Utilizarea specificatorilor de acces. 4. Înţelegerea drepturilor de acces în condiţiile în care avem atât modificatori de acces cât şi specificatori de acces Consideraţii teoretice
Datele (membrii) şi membrele (funcţiile) din interiorul unei clase pot avea următorii specificatori de acces: - public: datele/membrele pot fi accesate de oriunde, chiar si din afara clasei; - protected: datele/membrele dintr-o clasă de bază pot fi vazute în interiorul claselor derivate dar nu şi în afara acestora; - private: datele/membrele dintr-o clasă nu sunt văzute decât în interiorul clasei. Implicit toate datele şi metodele din cadrul unei clase sunt private. Daca constructorii nu ar fi declaraţi cu specificatorul de acces public nu am putea avea obiecte de tipul clasei respective în afara clasei.
Modificatorii de acces Specificatorul de acces din clasa de bază private protected public private protected public
Modificator de acces private private private public public public
Exemplu //main.h
class P_ABC { protected: char *sir_c,tip; long *sir_l; double *sir_d; short dim; P_ABC(short dim1, char tip1); //'c' , 'l', 'd' ~P_ABC();
Accesul moştenit Accesul din exterior de clasa derivată inaccesibil private private inaccesibil protected public
inaccesibil inaccesibil inaccesibil inaccesibil inaccesibil accesibil
virtual void afisare()=0; virtual void citire()=0; //functii virtuale pure ==> clasa de baza virtuala ==> NU se pot instanta direct obiecte ale acestei clase };
class A : protected P_ABC { protected: //se pot apela in clasele derivate char *sir; public: //se pot apela in afara clasei si in afara ierarhiei de clase A(short dim1); A(char*); ~A(); char* obtine_sir(); void afisare(); void citire(); };
class B : public P_ABC { protected: long *sir; public: B(short dim1); long* obtine_sir(); void afisare(); void setare(int i, long val) {sir[i]=val;} void citire();
};
class Z { int x,y; protected: Z(int x1,int y1) {x=x1;y=y1;} }; //mostenire multipla class AZ: public A, protected Z
{ public: AZ(short dim1,char valinit_c); };
/ / mai n. cpp
#include #include #include #include using namespace std; P_ABC::P_ABC(short dim1,char tip1) { dim=dim1; sir_c=NULL;sir_d=NULL;sir_l=NULL; tip=tip1; if(tip=='c') sir_c=new char[dim+1]; // +1 ptr. terminatorul de sir '/0' if(tip=='l') sir_l=new long[dim]; if(tip=='d') sir_d=new double[dim]; // if(sir_c==NULL &&) {cout<<"Memorie insuficienta";return;} } P_ABC::~P_ABC() { if(sir_c) delete[] sir_c; if(sir_l) delete[] sir_l; if(sir_d) delete[] sir_d; } A::A(short dim1):P_ABC(dim1,'c') { //preia dimensiunea sirului //dim=dim1; //aloca memorie ptr. sir // sir = new char[dim+1]; // +1 ptr. terminatorul de sir '/0' // if(sir==NULL) {cout<<"Memorie insuficienta";return;} // echivalent cu: if(!(sir= new char[dim])) {{cout<<"Memorie insuficienta";return;} sir=sir_c; } A::A(char* sir1):P_ABC(strlen(sir1),'c') { //dim=strlen(sir1); //if(!(sir= new char[dim])) {cout<<"Memorie insuficienta";return;} sir=sir_c; //strcpy(sir,sir1); for(int i=0;i
void A::citire() { cin>>sir;} B::B(short dim1):P_ABC(dim1,'l') {sir=sir_l;} long* B::obtine_sir() {return sir;} void B::afisare() {cout<<"\n Sirul din clasa B este:"<>sir[0];} /*AB::AB(char valinit_c, long valinit_l):A(5),B(9) { for(int i=0;i
}*/ AZ::AZ(short dim1,char valinit_c):A(dim1),Z(2,3) { for(int i=0;i
int main(int argc, char **argv) { A *s2,s1("abcd"); B *s3; //P_ABC d(4,'c'); eroare : clasa de baza abstracta -- nu se vor instantia obiecte s2=new A("1234"); s1.afisare(); s2->afisare(); s3=new B(2); //s3->citire(); s3->setare(0,45); s3->afisare(); AZ t(5,'k'); t.afisare(); int m; cin>>m; //asteapta o tasta return 0; }
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.6 DATE ŞI FUNCŢII DE TIP FRIEND ŞI STATICE Scop:
1. Înţelegerea tipului de dată friend pentru o clasă 2. Înţelegerea tipului de dată static pentru membrii unei clase 3. Utilizarea instanţierii claselor cu metode statice Consideraţii teoretice:
Funcţii de tipul "prieten" (friend) O funcţie de tip friend (prieten) este o funcţie care nu este membră a clasei şi are acces la toţi membrii clasei. În interiorul clasei, ea se declară prin scrierea cuvântului cheie friend înaintea declararaţiei propiu-zise a funcţiei. O clasă ale cărei funcţii sunt, în totalitate, friend pentru altă clasă se numesţe clasă prietenă a acelei clase. O funcţie prieten, este o funcţie declarată în afara clasei (nu aparţine clasei) şi căreia i se dă acces la toate datele din cadrul clasei. În interiorul clasei este declarată cu cuvântul cheie friend în faţă. Adresa obiectului curent este dată de operatorul this. MEMBRII STATICI Un tip aparte de membri ai unei clase sunt membrii statici . Atat functiile membru cat si datele membru (atributele) unei clase pot fi declarate static. Variabile Membru Statice Daca declaratia unei variabile membru este precedata de cuvantul-cheie static, atunci va exista o copie unica a acelei variabile care va fi folosita in comun de catre toate obiectele instantiate din clasa respectiva. Spre deosebire de variabilele membru obisnuite, pentru variabilele statice nu sunt create copii individuale ale acestora pentru fiecare obiect in parte. Accesarea unei variabile statice se face folosind numele clasei si operatorul de specificare a domeniului ("::"). Cand se declară o data membru ca fiind static intr-o clasa, ea nu este înca alocată. Prin declarare nu se aloca memorie, acest lucru se realizează în exteriorul clasei. Pentru a defini o variabila membru statica, aceasta trebuie prevazuta cu o definire globala undeva in afara clasei. Variabilele statice (ca si functiile membru statice de altfel) pot fi utilizate indiferent daca exista sau nu instante ale clasei respective. De aceea, initializarea unei variabile statice NU poate cadea in sarcina constructorilor clasei (constructorii, se stie, se executa doar la momentul generarii unei instante). Constructorii pot, insa, sa modifice valorile variabilelor statice (de exemplu, pentru a contoriza numarul instantelor unei clase, create la executia unui program). Variabilele membru statice sunt folosite cel mai adesea pentru a asigura controlul accesului la o resursa comuna (ex. scrierea intr-un fisier). Acest tip de variabile se mai folosesc si pentru a stoca informatii comune unei intregi clase de obiecte. Functii Membru Statice Si functiile membru pot fi declarate ca statice. In C++ o functie membru statica se comporta asemanator cu o functie globala al carei domeniu este delimitat de clasa in care este definita. Operatorul "this" Cuvântul cheie this arată adresa obiectului curent (în care ne aflăm) iar *this este valoarea obiectului curent.
//functii friend #include #include class A {int a1; friend void aduna(A& x1, A& x2); public: A() {a1=0;} A(int a1_) {a1=a1_;} }; void aduna(A& x1, A& x2) { int rez; rez=x1.a1 +x2.a1; std::cout<<"\n x1.a1+x2.a1="<>m; return 0; } //variabile de tip static #include #include // definim variabila cnt pentru a contoriza numarul de obiecte de tip A existente class A { int a1; public: static int cnt; A() {a1=0; cnt++;} A(int a1_) {a1=a1_;cnt++;} ~A() {cnt--;} static void afis() {std::cout<<"\n nr.obiecte:"<>m; return 0; }
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.7 POLIMORFISM, FUNCŢII VIRTUALE Scop:
1. Înţelegerea noţiunii de polimorfism 2. Utilizarea funcşiilor virtuale Consideraţii teoretice:
Funcţiile virtuale sunt folosite pentru implementarea obiectelor polimorfice. Obiectele polimorfice se careacterizează prin faptul că folosind aceeaşi formă de apel pentru funcţiile membre realizăm operaţii diferite. Funcţiile viruale implementează filozofia "o singură interfaţă, mai multe metode", care pune în evidenţă "poli morfism-ul"
Variabile de tip pointer care punctează la clasele derivate Presupunem două clase, denumite:BAZA şi DERIVATA, unde clasa DERIVATA moşteneşte clasa BAZA. În aceste condiţii, următoarele instrucţiuni sunt valabile: BAZA *p; // pointer-ul care punctează la clasa baza BAZA OB_TIP_BAZA; //un obiect de tip BAZA DERIVATA OB_TIP_DER; // un obiect de tip DERIVATA // pointer-ul p poate puncta (prelua adresa) la obiecte de tip BAZA p=&OB_TIP_BAZA; // p preia adresa lui OB_TIP_BAZA // p poate puncta la obiecte derivate p=&OB_TIP_DER; // p preia adresa lui OB_TIP_DER Un pointer al clasei de bază poate puncta la un obiect din clasa derivată, fără a genera vreo eroare, invers nu este valabil. Prin acest pointer putem avea acces doar la membrii clasei derivate care au fost moşteniţi de la clasa de bază. Funcţii virtuale O funcţie virtuală este o funcţie membră a unei clase, care se declară în interiorul unei clase de bază şi se redefineşte (modifică) în clasele derivate. Pentru a crea o funcţie virtuală, trebuie să utilizăm cuvântul cheie virtual, înainte de declaraţia funcţiei. La nivelul fiecărei clase funcţiile virtuale împlementează cod specific clasei respective, însă ele au acelaşi nume, aceeaşi listă de parametrii şi întorc aceelaşi tip de dată. Când un pointer al clasei de bază punctează la o funcţie virtuală din clasa derivată, şi aceasta este apelată prin intermediul acestui pointer, compilatorul determină care versiune (care din codurile/ care explicitare) a funcţiei trebuie apelată, ţinând cont de tipul obiectului (care clasă) la care punctează acel pointer. Adică tipul obiectului (clasa ) la care punctează determină versiunea funcţiei virtuale care va fi executată. O funcţie virtuală poate fi declarată şi numai formal, ea nerealizând nimic concret, ea fiind declarată doar pentru ca în clasele derivate să fie declarată şi explicitată. O astfel de funcţie virtuală, fără cod/explicitare se numeşte funcţie virtuală pură. Sintaxa pentru o funcţie virtuală pură este: virtual tip nume_funcţie(listă_de_parametri)=0; O clasă ce conţine o funcţie virtuală pură se numeşte clasă abstractă. Clasele abstracte sunt utilizate doar pentru a fi moştenite. Nu se pot intanţia obiecte pentru clase abstracte. //polimorfism #include #include using namespace std;
class Patrulater { protected: double laturi[4]; public: Patrulater(double l1=0.0, double l2=0.0, double l3=0.0, double l4=0.0) {laturi[0] = l1; laturi[1] = l2; laturi[2] = l3; laturi[3] = l4; } virtual double perimetru() { return laturi[0]+ laturi[1]+laturi[2]+laturi[3]; } virtual double arie() {}; }; class Dreptunghi : public Patrulater { public: Dreptunghi(double l1=0.0, double l2=0.0) : Patrulater(l1,l2,l1,l2) {} double perimetru() { return 2*(laturi[0]+laturi[1]); } double arie() { return laturi[0]* laturi[1]; } }; class Patrat : public Patrulater { public: Patrat(double l1 = 0.0) : Patrulater(l1,l1,l1,l1) {} double perimetru() { return 4*laturi[0]; } double arie() { return laturi[0]*laturi[0]; } }; // *colectie[] === **colectie, prima scriere este sugestiva ptr. vector de pointeri void CalculeazaPerimetre(Patrulater *colectie[]) {// for-ul se executa atata timp cat elem != NULL // elem este un pointer de parcurgere de tip Patrulater // la fiecare iteratie se trece la adresa urmatoare for(Patrulater *elem = *colectie; elem ; elem = *(++colectie)) printf("\n %f", (*elem).perimetru());// sau printf("\n %f", elem->perimetru()); } //se procedeaza idem si pentru arie void afis_si_calc_perim(Patrulater *figuri_geom[]) { for(int i=0;figuri_geom[i]!=NULL;i++) { double perim; perim = figuri_geom[i]->perimetru(); cout<<"\n "<
int main(int argc, char **argv) { Patrulater *colectiePatrulatere[10];//vector cu 10 adrese la obiecte de tip Patrulater int i = 0; colectiePatrulatere[i++] = new Patrat(6.5); colectiePatrulatere[i++] = new Dreptunghi(6.0,7.5); colectiePatrulatere[i++] = new Patrulater(2.0,3,1,5.2); colectiePatrulatere[i++] = new Dreptunghi(2.0,1.4); colectiePatrulatere[i++] = new Dreptunghi(2.0,7.3); colectiePatrulatere[i++] = 0; //CalculeazaPerimetre(colectiePatrulatere);
//sau afis_si_calc_perim(colectiePatrulatere); int m;cin>>m; return 0; }
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.8 SUPRAÎNCĂRCAREA OPERATORILOR Scop:
1. Utilizarea supraîncărcarii operatorilor prin utilizarea funcţiilor friend 2. Utilizarea supraîncărcarii operatorilor fără a utiliza funcţiile friend Consideraţii teoretice:
Supraîncărcarea operatorilor (overloading-ul) presupune redefinirea operatorilor cu ajutorul funcţiei de tipul operator. Restricţii privind supraîncărcarea operatorilor: - nu pot fi supraîncărcaţi decât operatorii existenţi; - operatorii: " . "," .* "," :: " , " ?: " şi " sizeof " nu pot fi supraîncărcaţi; - operatorii binari vor fi supraîncărcaţi doar ca operatori binari; - operatorii unari vor fi supraîncărcaţi doar ca operatori unari; - se păstrează precedenţa operatorilor operator (nu exista posibilitatea de a determina, de exemplu, ca "+" sa fie prioritar fata de "/"); Nu este posibila definirea unui operator care sa ia ca parametri exclusiv pointeri (exceptand operatorii: = & ,). - Nu se poate modifica numarul operanzilor preluati de un operator (dar se poate ignora unul din parametri). - Un operator trebuie ori sa fie membru al unei clase, ori sa aiba cel putin un parametru de tip clasa. De la aceasta regula fac exceptie doar operatorii new si delete; - pentru operatorii : " = "," [] ", " () "," -> " funcţia operator trebuie să fie membră nestatică a clasei. a)Pentru operatorul binar "op" avem: ( op poate fi unul din operatorii din lista cu operatori C++) Funcţia Sintaxa formei de apel externe Sintaxa formei interne (canonice) de apel membră a clasei obiect1 op obiect2 obiect1.operator op (obiect 2) nemembră obiect1 op obiect2 operator op (obiect1, obiect2) b)Pentru operatorul unar "op" avem: Funcţia Sintaxa formei de apel externe op obiect1 membră a clasei obiect1 op op obiect1 nemembră obiect1 op
Sintaxa formei interne (canonice) de apel obiect1.operator op () obiect1.operator op () operator op (obiect1) operator op (obiect1)
#include #include //supaincarcarea operatorilor class VECT { double v[3]; public: //constructor declarat şi explicitat în interiorul declaraţiei clasei VECT()
{ v[0]=0; v[1]=0; v[2]=0;} ~VECT(){}//desctructor //declaraţie constructor cu 3 argumente VECT(double x1,double x2,double x3); //VECT(VECT&);//constructor de copiere //operatorul atribuire VECT operator=(VECT); //ADUNAREA C=A+B friend VECT operator+(VECT,VECT); //C=operator+(A,B); --- C=A+B VECT operator^(VECT); //C=B.operator^(A); --- C=B+A ( B --- this)
//ADUNAREA A+=B VECT operator +=(VECT); //void operator *=(VECT); friend VECT operator ^=(VECT&,VECT&); //friend void operator |=(VECT&,VECT&); //X=-X VECT operator-(); //sau friend VECT operator!(VECT); //double& operator[](int); //friend bool operator==(VECT,VECT); void afiseaza(); }; // explicitare constructor VECT::VECT(double x,double y, double z) { v[0]=x;v[1]=y;v[2]=z; } //explicitare constructor copiere //VECT::VECT(VECT &w) //{ v[0]=w.v[0]; v[1]=w.v[1]; v[2]=w.v[2];} void VECT::afiseaza() { printf("\n Valorile: v[0]=%f,\n v[1]=%f,\n v[2]=%f",v[0],v[1],v[2]); } //operatoru de atribuire X = Y VECT VECT::operator=(VECT w) { v[0]=w.v[0];v[1]=w.v[1];v[2]=w.v[2]; return *this; } // X = W1 + W2 , operator + este funcţie externă clasei VECT operator+(VECT w1,VECT w2) { VECT elem; elem.v[0]=w1.v[0]+w2.v[0]; elem.v[1]=w1.v[1]+w2.v[1]; elem.v[2]=w1.v[2]+ w2.v[2]; return elem; } // X = W1 ^ W2 , operator ^ este membră a clasei şi o vom utiliza, DE //EXEMPLU pentru efectuarea ADUNAREA (adica de fapt X=W1+W2)
//unde W1 este obiectul curent (*this) VECT VECT::operator^(VECT w) // w=W2 { VECT elem; elem.v[0]=v[0] + w.v[0]; elem.v[1]=v[1] + w.v[1]; elem.v[2]=v[2] + w.v[2]; return elem; } //X+=Y VECT VECT::operator+=(VECT w) { v[0]=v[0] + w.v[0]; v[1]=v[1] + w.v[1]; v[2]=v[2] + w.v[2]; return *this; } /* void VECT::operator*=(VECT w) { v[0]=v[0] + w.v[0]; v[1]=v[1] + w.v[1]; v[2]=v[2] + w.v[2]; }*/ VECT operator^=(VECT &w1, VECT& w2) { w1.v[0]=w1.v[0]+w2.v[0]; w1.v[1]=w1.v[1]+w2.v[1]; w1.v[2]=w1.v[2]+ w2.v[2]; return w1; } /* void operator|=(VECT &w1, VECT& w2) { w1.v[0]=w1.v[0]+w2.v[0]; w1.v[1]=w1.v[1]+w2.v[1]; w1.v[2]=w1.v[2]+ w2.v[2]; }*/
// X = -X VECT VECT:: operator-() { VECT elem(-v[0],-v[1],-v[2]); return elem; } VECT operator!(VECT u) { VECT elem(-u.v[0],-u.v[1],-u.v[2]); return elem; } int main(int argc, char **argv) { //vf. atribuire /* VECT x(1,2,3),y;
y=x; y.afiseaza(); */ //vf adunare + si atribuire // VECT x(1,2,3),y(10,11,12),z; // z=x+y; //sau // z=operator+(x,y); // z.afiseaza(); //vf. adunare ^ si atribuire // VECT x(100,200,300),y(10,11,12),z; //z=x^y; //sau //z=x.operator ^(y); //z.afiseaza(); //vf operator unar /*VECT s(3,-6,9); s=-s; s.afiseaza();int m; std::cin>>m; return 0; */ /*VECT s(3,-6,9); s=!s; s.afiseaza(); int m; std::cin>>m; return 0; VECT x(1,2,3),y(10,11,12); //x^=y; //x|=y; x+=y; x.afiseaza(); // y.afiseaza(); int m; std::cin>>m;return 0; } Exemplu: #include #include
//supaincarcarea operatorilor class VECT { double v[3]; public: //constructor declarat şi explicitat în interiorul declaraţiei clasei VECT() { v[0]=0; v[1]=0; v[2]=0;} ~VECT(){}//desctructor //declaraţie constructor cu 3 argumente VECT(double x1,double x2,double x3); //VECT(VECT&);//constructor de copiere //operatorul atribuire VECT operator=(VECT); //operator indexare double& operator[](int); //supraincarcarea operatorului "identic"
*/
friend bool operator==(VECT,VECT); bool operator<(VECT);//semnificatie schimbata in identic bool operator<=(VECT&);//semnificatie schimbata in identic void afiseaza(); }; // explicitare constructor VECT::VECT(double x,double y, double z) { v[0]=x;v[1]=y;v[2]=z; } //explicitare constructor copiere //VECT::VECT(VECT &w) //{ v[0]=w.v[0]; v[1]=w.v[1]; v[2]=w.v[2];} void VECT::afiseaza() { printf("\n Valorile: v[0]=%f,\n v[1]=%f,\n v[2]=%f",v[0],v[1],v[2]); } //operatoru de atribuire X = Y VECT VECT::operator=(VECT w) { v[0]=w.v[0];v[1]=w.v[1];v[2]=w.v[2]; return *this; } bool VECT::operator<(VECT A) { if(v[0]==A.v[0] && v[1]==A.v[1] && v[2]==A.v[2]) //this.v[0] este echivalent cu v[0] return true; return false; } bool VECT::operator<=(VECT& A) { if(v[0]==A.v[0] && v[1]==A.v[1] && v[2]==A.v[2]) return true; return false; }
bool operator==(VECT A, VECT B) {if(A.v[0]==B.v[0] && A.v[1]==B.v[1] && A.v[2]==B.v[2]) return true; return false; } double& VECT::operator[](int i) { return v[i]; }
int main(int argc, char **argv) { VECT x(10,11,12),y(10,11,12); // x.afiseaza(); bool b; // b=operator==(x,y); // b=x==y;
// b=x.operator<(y); // b=x>m;return 0; }
Exemplu: #include #include #include
//supaincarcarea operatorilor class VECT { double v[3]; public: //constructor declarat şi explicitat în interiorul declaraţiei clasei VECT() { v[0]=0; v[1]=0; v[2]=0;} ~VECT(){}//desctructor //declaraţie constructor cu 3 argumente VECT(double x1,double x2,double x3); //VECT(VECT&);//constructor de copiere //operatorul atribuire VECT operator=(VECT); //operator indexare char* operator[](int); void afiseaza(); }; // explicitare constructor VECT::VECT(double x,double y, double z) { v[0]=x;v[1]=y;v[2]=z; } //explicitare constructor copiere //VECT::VECT(VECT &w) //{ v[0]=w.v[0]; v[1]=w.v[1]; v[2]=w.v[2];} void VECT::afiseaza() { printf("\n Valorile: v[0]=%f,\n v[1]=%f,\n v[2]=%f",v[0],v[1],v[2]); } //operatorul de atribuire X = Y VECT VECT::operator=(VECT w) { v[0]=w.v[0];v[1]=w.v[1];v[2]=w.v[2]; return *this; } char* VECT::operator[](int i) {char* den;
den=new char[10]; switch(i) { case 1: strcpy(den,"luni");break; case 2: strcpy(den, "marti");break; case 4: strcpy(den,"joi");break; default: strcpy(den,"zi inc."); } return den; }
int main(int argc, char **argv) { VECT x(10,11,12),y(10,11,12); // x.afiseaza(); bool b; char *zi; zi=x[10]; printf("Denumirea:1:%s",zi); int m; std::cin>>m;return 0; }
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.9 FLUXURI DE INTRARE/IEŞIRE. OBIECTE STANDARD
Scop:
1. Înţelegerea noţiunii de flux I/O 2. Utilizarea obiectelor standard din cadrul claselor I/O Consideraţii teoretice: Stream-urile au in principal rolul de a abstractiza operatiile de intrare- iesire. Ele ofera metode de scriere si citire a datelor independente de dispozitivul I/O si chiar independente de platforma. Stream-urile incapsuleaza (ascund) problemele specifice dispozitivului cu care se lucreaza, sub libraria standard iostream. In C++ stream-urile au fost implementate utilizand clase, dupa cum urmeaza: clasa streambuf gestioneaza buffer-ele. • clasa ios este clasa de baza pentru clasele de stream-uri de intrare si de iesire. Clasa • ios are ca variabila membru un obiect de tip streambuf . • clasele istream si ostream sunt derivate din ios clasa iostream este derivata din istream si ostream si ofera metode pentru lucrul cu • dispozitivul standard de intrare/iesire . clasa fstream ofera metode pentru operatii cu fisiere. •
Obiecte standard
Cand un program C++ care include initializate automat patru obiecte: • • •
iostream.h
este lansat in executie, sunt create si
gestioneaza intrarea de la intrarea standard (tastatura). cout gestioneaza iesirea catre iesirea standard (ecranul). cerr gestioneaza iesirea catre dispozitivul standard de eroare (ecranul), neutilizand buffer-e. cin
Exemplu: #include #include #include using namespace std; class A{ static int d; int m; double t; public:
A(){m=11; } void afis() { //umple spatiul liber pana la dimensiunea data de setw(dim) cu caracterul specificat cout<
} }; int A::d=8; //se declara ca variabila globala int main(int argc, char **argv) { A x; x.afis(); //std::cout<<"TEST"; //int m; std::cin>>m; // pe post de asteapta o tasta }
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.10 FLUXURI DE INTRARE/IEŞIRE. OPERATII DE INTRARE/IESIRE CU FISIERE Scop:
Realizarea operaţiilor cu fişiere utilizând fluxurile I/O Consideraţii teoretice: Lucrul cu fisiere se face prin intermediul clasei ifstream pentru citire respectiv ofstream pentru scriere. Pentru a le utiliza, aplicatiile trebuie sa includa fstream.h. Clasele ofstream si ifstream sunt derivate din clasa iostream, ca urmare toti operatorii si toate functiile descrise mai sus sunt mostenite si de aceasta clasa. Exemplu: #include #include #include #include using namespace std; // FISIERE TEXT class A{ public: int scrie_in_Fisier(char* numefis) { ofstream fis1(numefis); //deschidere fişier text.txt //ofstream fis1(numefis,ios::app|ios::out); //adauga, la sfarsit, fara trunchiere fisier if (!fis1){ cout<<"Eroare la dechiderea fişierului!\n"; return 1;} fis1<<"A111 B222 "; fis1<<"ABCD "; fis1<<15<<" "<<13; fis1.close(); } int citeste_din_Fisier(char* numefis) { char a[3][100]; int b[3]; ifstream fis2(numefis); //deschiderea fis. ptr. citire if (!fis2){cout<<"Eroare la deschiderea fis. ptr. citire!\n";return 1;} fis2>>a[0]>>a[1]>>a[2]>>b[0]>>b[1]; cout<<"a[0]:"<
int main(int argc, char **argv) { A x; x.scrie_in_Fisier("test24.txt");
x.citeste_din_Fisier("test24.txt"); return 0; }
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.11 TRATAREA EXCEPŢIILOR Scop:
Implementarea metodelor de control a posibilelor erori din cadrul unei aplicaţii Consideraţii teoretice:
În timpul executării unui program pot apărea situaţii în care sunt generate erori datorate de multe ori depăşirii puterii de reprezentare a numerelor, de operaţii nepermise, de contori în afara limitelor admise, etc. Ca urmare este necesară anticiparea unor posibile excepţii, de multe ori provenite de la preluarea incorectă a datelor. C + + oferă trei cuvinte cheie pentru a gestiona o excepţie: try , catch şi throw. Cuvântul cheie try este urmat de blocul ce se execută şi care poate genera o eroare în execuţie try { bloc ce se execută în mod normal } Acest cuvânt cheie permite aplicaţiei să anticipeze un comportament anormal şi va încerca să se ocupe de ea. catch { bloc ce se execută în cazul în care apare o excepţie/eroare }
Acest cuvânt cheie este urmat, între acolade, de blocul ce se execută în cazul unei excepţii/erori throw transmite excepţia, în vederea tratării acesteia, către sistemul de operare. Ex: #include using namespace std; int main() { int a,b,c; cout << "a= "; cin >> a; cout << "b= ";cin >> b;
try { if( b==0 )
throw; c = a / b; } catch() { cout<<”b este zero”; } cout << "\n"; return 0; }
C ele trei puncte din argumentul catch semnifică faptul că vor fi tratate toate excepţiile.
Pentru particularizarea tratării erorii, putem proceda ca în exemplul următor: #include int main()
{ int a,b,c; cout << "a= "; cin >> a; try { cout << "b= "; cin >> b; if(b == 0) throw "b este ZERO !"; c = a / b; } catch(const char* Message) { cout << "Error: " << Message; } cout << "\n"; return 0; }
În cazul în care sunt tratate mai multe excepţii putem avea: try { // codul ce poate contine exceptii/erori } catch(Arg1) { //tratarea primei excetii } catch(Arg2) { //tratarea urmatoarei exceptii }
Deosebirea între argumente se va face prin tipurile acestora Ex: #include int main() { int a,b,c; cout << "a= "; cin >> a; try { cout << "b= "; cin >> b; if(b == 0) throw "b este ZERO !"; if(b == 1) throw 1; if(b == 2) throw '2'; c=a/b+a/(b-1)+a/(b-2); catch(const char* Message) { cout << "Error: b=0”; } catch(const int Message) { cout << "Error:b=1”; } catch(const char Message) { cout << "Error: b=2"; } cout << "\n"; return 0; }
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.12 UTILIZAREA CLASELOR WXWIDGETS (I) Scop: Familiarizarea cu uneltele de dezvoltare a interfeţelor grafice Consideraţii teoretice:
Clasele wxWidgets se constituie într-un se de instrumente C++ ce permit crearea de interfaţe grafice GUI (Graphical User Interface) în C++. Aceste clase sunt open source şi cross-platform. aplicaţiile wxWidgets pot rula pe toate sub toate sistemele de operare reprezentative: Linux, Windows, Unix si Mac. Proiectul a fost demarat de către Julian inteligente în 1992. Clasa wxString este utilizată pentru lucrul cu şirurile de caractere. #include int main(int argc, char **argv) { wxString str1 = wxT("Un"); wxString str2 = wxT("prim"); wxString str3 = wxT("exemplu."); wxString str = str1 + wxT(" ") + str2 + wxT(" ") + str3; wxPuts(str); }
Formatarea şirurilor #include int main(int argc, char **argv) { int a = 10; wxString str; str.Printf(wxT("a= %d\n",a); wxPuts(str); wxPrintf(wxT("Şirul are lungimea de %d caractere.\n"), str.Len()); }
Clasa wxFile este utilizată pentru lucrul cu fişiere #include int main(int argc, char **argv) { wxString str = wxT("Un sir de caractere.\n"); wxFile file; file.Create(wxT("numefisier"), true); if (file.IsOpened()) wxPuts(wxT("Fisierul este deschis")); file.Write(str); file.Close(); if (!file.IsOpened()) wxPuts(wxT("Fisierul NU este deschis")); }
Desfăşurarea lucrării:
1. Se rulează exemplele din secţiunea teoretică 2. Se continuă cu exemplele corespunzătoare din secţiunea TESTE
LABORATORUL NR.13 UTILIZAREA CLASELOR WXWIDGETS (II) Scop: Familiarizarea cu uneltele de dezvoltare a interfeţelor grafice Consideraţii teoretice:
În vederea realizării interfeţelor grafice este necesară utilizarea metodelor (din cadrul claselor date) ce asigură gestiunea evenimentelor la nivel de aplicaţie. Ex:Realizarea unui mic formular utilizând wxFormBuilder gui.h --wxWidgets license (www.wxwidgets.org) - - fişier generat de wxFormBuilder -
necesar înţegerii
structurii claselor #ifndef __gui__ #define __gui__ #include #include #include #include #include #include #include #include #include #include // Class MainDialogBase class MainDialogBase : public wxDialog { private: protected: wxStaticLine* m_staticLine; wxStdDialogButtonSizer* m_sdbSizer; wxButton* m_sdbSizerOK; wxButton* m_sdbSizerCancel; virtual void OnCloseDialog( wxCloseEvent& event ) { event.Skip(); } virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); } virtual void OnOKClick( wxCommandEvent& event ) { event.Skip(); } public: MainDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("wxMiniApp"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 400,300 ), long style = wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE ); ~MainDialogBase(); }; #endif //__gui__
gui.cpp - wxWidgets license (www.wxwidgets.org) -- fişier
generat de wxFormBuilder - necesar înţegerii
structurii claselor #include "gui.h" MainDialogBase::MainDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, co nst wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) { this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize ); wxBoxSizer* mainSizer; mainSizer = new wxBoxSizer( wxVERTICAL ); mainSizer->Add( 0, 0, 1, wxEXPAND, 5 ); m_staticLine = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); mainSizer->Add( m_staticLine, 0, wxEXPAND | wxALL, 5 ); m_sdbSizer = new wxStdDialogButtonSizer(); m_sdbSizerOK = new wxButton( this, wxID_OK ); m_sdbSizer->AddButton( m_sdbSizerOK ); m_sdbSizerCancel = new wxButton( this, wxID_CANCEL ); m_sdbSizer->AddButton( m_sdbSizerCancel ); m_sdbSizer->Realize(); mainSizer->Add( m_sdbSizer, 0, wxALIGN_RIGHT|wxBOTTOM|wxRIGHT, 5 ); this->SetSizer( mainSizer ); this->Layout(); this->Centre( wxBOTH ); // conectarea handler-ului de evenimentelor this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogBase::OnCloseDialog ) ); m_sdbSizerCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogBase::OnCancelClick ), NULL, this ); m_sdbSizerOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogBase::OnOKClick ), NULL, this ); } MainDialogBase::~MainDialogBase() {// Eliberarea handler-ului de evenimente this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogBase::OnCloseDialog ) ); m_sdbSizerCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogBase::OnCancelClick ), NULL, this ); m_sdbSizerOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogBase::OnOKClick ), NULL, this ); }
main.h #ifndef __main__ #define __main__ // main wxWidgets header file #include // gui cl asses generated by wxFormBuilder #include "gui.h" class MainApp : public wxApp { public: virtual bool OnInit(); }; DECLARE_APP(MainApp) class MainDialog : public MainDialogBase { public: MainDialog( wxWindow *parent );
virtual ~MainDialog(); protected: virtual void OnCloseDialog( wxCloseEvent& event ); virtual void OnOKClick( wxCommandEvent& event ); virtual void OnCancelClick( wxCommandEvent& event ); }; #endif //__main__
main.cpp #include "main.h" IMPLEMENT_APP(MainApp); bool MainApp::OnInit() { SetTopWindow( new MainDialog( NULL ) ); GetTopWindow()->Show(); return true; } MainDialog::MainDialog(wxWindow *parent) : MainDialogBase( parent ) { } MainDialog::~MainDialog() { } void MainDialog::OnCloseDialog(wxCloseEvent& event) { Destroy(); } void MainDialog::OnOKClick(wxCommandEvent& event) { Destroy(); } void MainDialog::OnCancelClick(wxCommandEvent& event) { Destroy(); }
Desfăşurarea lucrării:
1. Se lansează wxFormBuilder şi se construieşte interfaţa 2. Se lansează CodeLite şi se adaugă metodele ce reprezintă răspunsul la evenimente 3. Se compilează şi link-editează
LABORATORUL NR.14 TESTE Scop: Testarea cunoştinţelor TEST#1
Se dau următoarele clase: #include #include #include class A1 {int x1; protected:char *numevar; protected: int s1,y1; public: int t1; A1() {numevar=new char[100];strcpy(numevar,"N/A"); afis("CONSTRUCTOR_0"); } A1(char *numevar1) {numevar=new char[100]; strcpy(numevar,numevar1); afis("CONSTRUCTOR1"); } A1(char *numevar1,int x11, int y11) {numevar=new char[100]; strcpy(numevar,numevar1); afis("CONSTRUCTOR2"); } ~A1() {afis("DESTRUCTOR");delete[] numevar;} virtual void afis(char *str); private: void calc(); }; void A1::afis(char *str) {std::cout<<"A1#numevar:"<
void C3::afis(char *str) {std::cout<<"C3#numevar:"<afis("d[0]"); d[1]->afis("d[1]"); d[2]->afis("d[2]"); // return 0; } 3.1. Este posiblil asignarea „d[0]=&w2”? Dar invers (w2=*d[0])? Explicaţi! 3.2. Este posiblil asignarea „d[1]=&g2”? Dar invers (g2=*d[1])? Explicaţi! 3.3. Este posiblil asignarea „d[2]=&m2”? Dar invers (m2=*d[2])? Explicaţi! 3.4. Este posiblil asignarea „e[0]=w2”;? Dar invers? Explicaţi! 3.5. Este posiblil asignarea „e[1]=g2”;? Dar invers?Explicaţi! 3.6. Este posiblil asignarea „e[2]=m2”;? Dar invers?Explicaţi! 4. Se dă o clasă ce con ține coordonatele x,y ale
unui 4.1. două 4.2.
punct într-un plan. Să se supraîncarce: conține coordonatele punctului Un operator pentru calculul distan ț ei dintre distanței dintre cele două puncte. puncte. Un operator ce întoarce un nou obiect ce
la
jumătatea
TEST #2 Se dau următoarele clase: #include #include #include class A1 {int x1; protected:char *numevar; protected: int s1,y1; public: int t1; A1() {numevar=new char[100];strcpy(numevar,"N/A"); afis("CONSTRUCTOR_0"); } A1(char *numevar1) {numevar=new char[100]; strcpy(numevar,numevar1); afis("CONSTRUCTOR1"); } A1(char *numevar1,int x11, int y11) {numevar=new char[100]; strcpy(numevar,numevar1); afis("CONSTRUCTOR2"); } ~A1() {afis("DESTRUCTOR");delete[] numevar;} virtual void afis(char *str); private: void calc(); };
//1. Ce se afişează în urma execuţiei ? int main(int argc, char* argv[]) {B2 a1("a1"),b2[2]; {A1 c3,d4("d4",5,4); {C3 f5("f5"); B2 *g6=new C3("g6",21,17,19);delete g6; } } getchar(); return 0; } 2. Modifica ți clasele astfel încât să contorizeze numărul obiectelor ce au utilizat la instanțiere constructori cu un singur parametru. Adăugaţi codul necesar și în afara clasei.
void A1::afis(char *str) {std::cout<<"A1#numevar:"<
3.Se dă: int main(int argc, char* argv[]) { A1 w2("d1",5,4),*d[3],e[3]; B2 g2("g2",21,17,19); C3 m2("m2",101,32,54); // d[0]=&w2; d[1]=&g2; d[2]=&m2; // e[0]=w2; e[1]=g2; e[2]=m2; // d[0]->afis("d[0]"); d[1]->afis("d[1]"); d[2]->afis("d[2]"); // return 0; } 3.1. Este posiblil asignarea „d[0]=&w2”? Dar invers (w2=*d[0])? Explicaţi! 3.2. Este posiblil asignarea „d[1]=&g2”? Dar invers (g2=*d[1])? Explicaţi! 3.3. Este posiblil asignarea „d[2]=&m2”? Dar invers (m2=*d[2])? Explicaţi! 3.4. Este posiblil asignarea „e[0]=w2”;? Dar invers? Explicaţi! 3.5. Este posiblil asignarea „e[1]=g2”;? Dar invers?Explicaţi! 3.6. Este posiblil asignarea „e[2]=m2”;? Dar invers?Explicaţi! 4. Se dă o clasă ce con ține coordonatele x,y ale vârfurilor unui dreptunghi. Să se supraîncarce: 4.1. Un operator pentru calculul ariei de intersecție a două obiecte. 4.2. Un operator ce întoarce un nou obiect ce conține vârfurile drepunghiului rezultat în urma intersecției a două obiecte.
TEST #3 strcpy(numevar,numevar1); s3=s33;afis("CONSTRUCTOR_2"); } ~C3() {afis("DESTRUCTOR");delete[] numevar;} void afis(char *str); };
Se dau următoarele clase: #include #include #include class A1 {int x1; char *numevar; protected: int s1,y1; public: int t1; A1() {numevar=new char[100];strcpy(numevar,"N/A"); afis("CONSTRUCTOR_0");} A1(char *numevar1) {numevar=new char[100]; strcpy(numevar,numevar1); afis("CONSTRUCTOR1");} A1(char *numevar1,int x11, int y11) {numevar=new char[100]; strcpy(numevar,numevar1); afis("CONSTRUCTOR2");} ~A1() {afis("DESTRUCTOR");delete[] numevar;} virtual void afis(char *str); private: void calc(); }; void A1::afis(char *str) {std::cout<<"A1#numevar:"<
void C3::afis(char *str) {std::cout<<"C3#numevar:"<
int main(int argc, char* argv[]) {C3 *t01; {A1 y1("y1"),d2[2],r3("r3",5,4); B2 g4("g4"),*s5; C3 q6("q6"); s5=new B2("s5",21,17,19); t01=new C3("t01",101,32,54); delete s5; } delete t01; getchar(); return 0; }
R
2. Adăugaţi câte un contor pentru numărul de obiecte instanţiate, pentru fiecare clasă în parte (adăugaţi direct pe codul scris şi rescrieţi numai metodele modificate). Afişaţi acest număr în cadrul constructorilor şi destructorilor.
void B2::afis(char *str) {std::cout<<"B2#numevar:"<
3.Se dă: int main(int argc, char* argv[]) { A1 w2("d1",5,4),d[3]; B2 g2("g2",21,17,19); C3 m2("m2",101,32,54); d[0]=w2; d[1]=g2;// 4.1 d[2]=m2; //4.2 d[0].afis("d[0]");//4.3 d[1].afis("d[1]");//4.3 d[2].afis("d[2]");//4.3 getch(); return 0; } 3.1. Este posiblil asignarea „d[1]=g2”;? Explicaţi! 3.2. Este posiblil asignarea „d[2]=m2”;? Explicaţi! 3.3. În cazul în care este posibilă asignarea ce se afişează în urma apelului metodei afis(“d[i]”) , i=0,1 sau 2 ? Explicaţi! 4. Sa se scrie o clasa ce contine un operator supraîncarcat pentru operatia de concatenarea a doi vectori cu numere de tip double si un operator supaincarcat pentru operatia de ordonare crescatoare a elementelor vectorului.
TEST #4
Se dau următoarele clase: #include #include #include
//1. Ce se afişează în urma execuţiei ?
int main(int argc, char* argv[]) {C3 *a1, b2[2]; {A1 c3("c3"),*d4[2],e5("e5",5,4); {B2 f6("f6");} class A1 C3 g7("g7"); {int x1; protected:char *numevar; B2 *h8=new B2("s5",21,17,19);delete h8; protected: int s1,y1; b2=new C3("b2",101,32,54); public: int t1; } A1() delete b2; {numevar=new char[100];strcpy(numevar,"N/A"); getchar(); afis("CONSTRUCTOR_0"); return 0; } } A1(char *numevar1) R {numevar=new char[100]; strcpy(numevar,numevar1); 2. Modificați clasa A1 astfel încât la fiecare afis("CONSTRUCTOR1"); apel al vreunui constructor sau al destructorului } să afișeze numărul total al obiectelor A1(char *numevar1,int x11, int y11) instanțiate. Adăugaţi codul necesar și în afara {numevar=new char[100]; clasei. strcpy(numevar,numevar1); afis("CONSTRUCTOR2"); } 3.Se dă: ~A1() {afis("DESTRUCTOR");delete[] numevar;} int main(int argc, char* argv[]) virtual void afis(char *str); { private: A1 w2("d1",5,4),*d[3],e[3]; void calc(); B2 g2("g2",21,17,19); }; C3 m2("m2",101,32,54); //........................... void A1::afis(char *str) d[0]=&w2; d[1]=&g2; d[2]=&m2; {std::cout<<"A1#numevar:"<afis("d[0]"); { int x2,y2,x1,y1,s1,t1; d[1]->afis("d[1]"); d[2]->afis("d[2]"); protected: int s2,t2; //.................................... public: return 0; B2():A1() } {afis("CONSTRUCTOR_0"); } B2(char *numevar1):A1(numevar1) 3.1. Este posiblil asignarea „d[0]=&w2”? Dar {afis("CONSTRUCTOR_1"); } invers (w2=*d[0])? Explicaţi! B2(char *numevar1,int x11,int y11,int s22): A1(numevar1,x11,y11) { s2=s22;afis("CONSTRUCTOR_2"); } 3.2. Este posiblil asignarea „d[1]=&g2”? Dar ~B2() {afis("DESTRUCTOR");} invers (g2=*d[1])? Explicaţi! void afis(char *str); }; 3.3. Este posiblil asignarea „d[2]=&m2”? Dar invers (m2=*d[2])? Explicaţi! void B2::afis(char *str) {std::cout<<"B2#numevar:"<
TEST #5 ~C3() {afis("DESTRUCTOR");} void afis(char *str); };
Se dau următoarele clase: #include #include #include class A1 {int x1; protected:char *numevar; protected: int s1,y1; public: int t1; A1() {numevar=new char[100];strcpy(numevar,"N/A"); afis("CONSTRUCTOR_0"); } A1(char *numevar1) {numevar=new char[100]; strcpy(numevar,numevar1); afis("CONSTRUCTOR1"); } A1(char *numevar1,int x11, int y11) {numevar=new char[100]; strcpy(numevar,numevar1); afis("CONSTRUCTOR2"); } ~A1() {afis("DESTRUCTOR");delete[] numevar;} virtual void afis(char *str); private: void calc(); }; void A1::afis(char *str) {std::cout<<"A1#numevar:"<
void C3::afis(char *str) {std::cout<<"C3#numevar:"<
int main(int argc, char* argv[]) {A1 a1,*b2;*c3[3]; {B2 d4("d4”,2,4); {C3 e5("e5");} B2 *b2=new B2("s5",21,17,19); } } delete b2; getchar(); return 0; }
R
int main(int argc, char* argv[]) { A1 w2("d1",5,4),e[3]; B2 g2("g2",21,17,19); C3 m2("m2",101,32,54); return 0; } 2.1.Explicaţi dacă sunt sa nu posibile urmăroarele asignări: 1. e[0].s1=5;.............................. R:
................................... .............................. R: ................................... 3.w2.t1=e[0].s1; ......................... R: ................................... .............................. 4.g2.t1=9; R: ................................... 5.g2.t1=g2.t2; ............................ R: ................................... .............................. 6.m2.x3=g2.x2; R: ................................... .............................. 7.m2.s3=9; R: ................................... .............................. 8.m2.s1=9; R: ................................... .............................. 9.m2.x1=9; R: ................................... .............................. 10.m2.t3=g2.t2; R: ...................................
2.w2.t1=9;
3. Se dă o clasă ce gestionează elementele unui class C3: public A1 şir de caractere (această clasă va conţine un { int x3,y3; public: int s3,t3; pointer la un şir de numere de tip real). public: Să se supraîncarce un operator care să permită C3():A1() {afis("CONSTRUCTOR_0"); } obţinerea unui obiect având şirul de numere C3(char *numevar1):A1(numevar1) {afis("CONSTRUCTOR_1"); } ordonat crescător (se va scrie declaraţia clasei, C3(char *numevar1,int x11,int y11,int s33): unui constructor, explicitarea A1(numevar1,x11,y1 explicitarea 1) destructorului şi explicitarea funcţiei operator). {s3=s33;afis("CONSTRUCTOR_2"); }
TEST #6
Se dau următoarele clase: #include #include #include #include
class A1 {int g; protected: int h; public:int xa,ya;char numevar[20]; static int s; A1() {xa=0;ya=0;strcpy(numevar,”N/A”); afis("CONSTRUCTOR_0”); } A1(char*); A1(char*, int); A1(char*,int,int); ~A1() {afis("DESTRUCTOR");} virtual void afis(char *str); virtual void tipar(); }; A1::A1(char *numevar1) {xa=0;ya=0;strcpy(numevar,numevar1); afis("CONSTRUCTOR_1"); } A1::A1(char *numevar1, int x1) {xa=x1;ya=0;;strcpy(numevar,numevar1); afis("CONSTRUCTOR_2"); } A1::A1(char *numevar1,int x1, int y1) {xa=x1;ya=y1;;strcpy(numevar,numevar1); afis("CONSTRUCTOR_3"); } void A1::afis(char *str) {cout<<”A1_var:”<
}
{B2 g2("g2"),*g1;; {A1 d1[2],w2("d1",15,41); C3 m1("m1"); } g1=new B2("g1",51,29); delete g1; } getch(); return 0;
2.Este posibilă execuţia următoarelor instrucţiuni? Explicaţi de ce! 2.1. void main() {A1 d1[2];
d1[0].g=1;}
2.2. void main() {B2 d1[2]; d1[1].g=3;} 2.3. void main() {B2 d1[2]; d1[1].xa=7;}
... 2.4. void main() {B2 d1[2]; d1[1].h=5;}
..... 2.5. void main() {C3 a; a.h=7;}
........ 2.6. void main() {C3 a; a.g=9;}
...................... 2.7. void main() {C3 a; a.xa=1;}
. 2.8. void main() {A1 *m[2]; C3 a; m[0]=@a;}
. 2.9. void main() {A1 m[2]; C3 *a; a=m[0];}
........... 2.10. void main() {A1 m[2]; C3 *a; a>xa=(int)&m[0];}
.
3. Ce se afişează în urma execuţiei ? }
void B2::afis(char *str) {cout<<”B2_var:”<
void A1::tipar() {cout<<”xa=”<
C3:public A1 in loc de class C3:private A1 şi class B2:public A1 în loc de class B2:protected A1
class C3: private A1 { public:int xc,yc; void main() C3():A1(){xc=0;yc=0;afis("CONSTRUCTOR_0”);} {A1 *m[3],r1("var-r1",45); B2 r2("var-r2",46,47); C3(char *numevar1):A1(numevar1) C3 r3("var-r3",48,49,43,44); {xc=0;yc=0; afis("CONSTRUCTOR_1"); m[0]=&r1;m[1]=&r2; m[2]=&r3; } m[0]->tipar(); C3(char *numevar1,int x1,int y1,int s1, int m[1]->tipar(); t1): A1(numevar1,x1,y1) m[2]->tipar(); getch();} {xc=s1;yc=t1;afis("CONSTRUCTOR_5"); } ~C3() {afis("DESTRUCTOR");} 4. Se dă o clasă pentru gestiunea operaţiilor cu void afis(char *str); void tipar(); date calendaristice. Clasa conţine o variabilă ce }; void C3::afis(char *str) {cout<<”C3_var:”<
1. Ce se afişează în urma execuţiei ? int main() {C3 *m2;
memorează numărul se minute raportat la 31.12,1899, ora 24:00:00.000. Să se supraîncarce un operator care să permită adunare cu un anumit număr de ore (se va scrie declaraţia clasei, explicitarea unui constructor şi explicitarea funcţiei operator).
TEST #7
Se dau următoarele clase: #include #include #include #include
}
delete r1; getch(); return 0;
R: 2.Este posibilă execuţia următoarelor instrucţiuni? Explicaţi de ce!
class A1 {int g; protected: int h; public:int xa,ya;char numevar[20]; static: int 2.1. void main() {A1 d1[2]; d1[0].g=1;} s; A1() {xa=0;ya=0;strcpy(numevar,”N/A”);afis("CONSTR UCTOR_0”);} 2.2. void main() {B2 d1[2]; d1[1].g=3;} A1(char *numevar1) {xa=0;ya=0;strcpy(numevar,numevar1);afis("CON 2.3. void main() {B2 d1[2]; d1[1].xa=7;} STRUCTOR_1");} ................................. A1(char *numevar1, int x1) {xa=x1;ya=0;;strcpy(numevar,numevar1);afis("C 2.4. void main() {B2 d1[2]; d1[1].h=5;} ONSTRUCTOR_2");} A1(char *numevar1,int x1, int y1) {xa=x1;ya=y1;;strcpy(numevar,numevar1);afis(" 2.5. void main() {C3 a; a.h=7;} ................................ CONSTRUCTOR_3");} ~A1() {afis("DESTRUCTOR");} 2.6. void main() {C3 a; a.g=9;} virtual void afis(char *str); ................................ virtual void tipar(); 2.7. void main() {C3 a; a.xa=1;} }; void A1::afis(char *str) {cout<<”A1_var:”<
.............................. .............................. 2.10. void main() {A1 m[2]; C3 *a; a>xa=(int)&m[0];}
.............................. }
class C3: protected A1 { public:int xc,yc; C3():A1(){xc=0;yc=0;afis("CONSTRUCTOR_0”);} C3(char *numevar1):A1(numevar1) {xc=0;yc=0; afis("CONSTRUCTOR_1"); } C3(char *numevar1,int x1,int y1,int s1, int t1): A1(numevar1,x1,y1) {xc=s1;yc=t1;afis("CONSTRUCTOR_5"); } ~C3() {afis("DESTRUCTOR");} void afis(char *str); void tipar(); }; void C3::afis(char *str) {cout<<”C3_var:”<
int main() { A1 *r1; {A1 w2("d1",13,12),d1[2]; C3 m1("m1"); r1=new A1("r1",11,61); B2 g2("g2"); }
2.8. void main() {A1 *m[2]; C3 a; m[0]=@a;} 2.9. void main() {A1 m[2]; C3 *a; a=m[0];}
void B2::afis(char *str) {cout<<”B2_var:”<
1. Ce se afişează în urma execuţiei ?
................................
3. Ce se afişează în urma execuţiei ?
void A1::tipar() {cout<<”xa=”<
C3:public A1
in loc de
class C3:protected A1
void main() {A1 *m[3],r1("var-r1",15); B2 r2("var-r2",2,3); C3 r3("var-r3",4,5,6,7); m[0]=&r3;m[1]=&r2; m[2]=&r1; m[0]->tipar(); m[1]->tipar(); m[2]->tipar(); getch();}
4. Se dă o clasă ce gestionează elementele unui şir de caractere (această clasă va conţine un pointer la un şir de caractere). Să se supraîncarce un operator care să permită adăugarea unui caracter la sfârsitul şirului (se va scrie declaraţia clasei, explicitarea unui constructor, explicitarea destructorului şi explicitarea funcţiei operator).
TEST #8
Se dau următoarele clase: #include #include #include #include
class A1 {int g; protected: int h; public:int xa,ya;char numevar[20]; static int s; A1() {xa=0;ya=0;strcpy(numevar,”N/A”); afis("CONSTRUCTOR_0”); } A1(char*); A1(char*, int); A1(char*,int,int); ~A1() {afis("DESTRUCTOR");} virtual void afis(char *str); virtual void tipar(); }; A1::A1(char *numevar1) {xa=0;ya=0;strcpy(numevar,numevar1); afis("CONSTRUCTOR_1"); } A1::A1(char *numevar1, int x1) {xa=x1;ya=0;;strcpy(numevar,numevar1); afis("CONSTRUCTOR_2"); } A1::A1(char *numevar1,int x1, int y1) {xa=x1;ya=y1;;strcpy(numevar,numevar1); afis("CONSTRUCTOR_3"); } void A1::afis(char *str) {cout<<”A1_var:”<
}
class C3: private A1 { public:int xc,yc; C3():A1(){xc=0;yc=0;afis("CONSTRUCTOR_0”);} C3(char *numevar1):A1(numevar1) {xc=0;yc=0; afis("CONSTRUCTOR_1"); } C3(char *numevar1,int x1,int y1,int s1, int t1): A1(numevar1,x1,y1) {xc=s1;yc=t1;afis("CONSTRUCTOR_5"); } ~C3() {afis("DESTRUCTOR");} void afis(char *str); void tipar(); }; void C3::afis(char *str) {cout<<”C3_var:”<
int main() {A1 d1[2],*r1;
2.Este posibilă execuţia următoarelor instrucţiuni? Explicaţi de ce! 2.1. 2.2. 2.3. 2.4. 2.5.
void void void void void
main() main() main() main() main()
{A1 {B2 {B2 {B2 {C3
d1[2]; d1[0].g=1;} d1[2]; d1[1].g=3;} d1[2]; d1[1].xa=7;} d1[2]; d1[1].h=5;} a; a.h=7;}
....................... 2.6. void main() {C3 a; a.g=9;}
..................... 2.7. void main() {C3 a; a.xa=1;}
.. 2.8. void main() {A1 *m[2]; C3 a; m[0]=@a;}
.................. 2.9. void main() {A1 m[2]; C3 *a; a=m[0];}
....................... 2.10. void main() {A1 m[2]; C3 *a; a>xa=(int)&m[0];}
3. Ce se afişează în urma execuţiei ?
void B2::afis(char *str) {cout<<”B2_var:”<
1. Ce se afişează în urma execuţiei ?
}
B2 *g1; {A1 w1("d1"); g1=new B2("g1",21,19); } {C3 m1("m1"); r1=new A1("r1",11,61); delete g1; } delete r1; getch(); return 0;
void A1::tipar() {cout<<”xa=”<
C3:public A1 in loc de class C3:private A1 şi class B2:public A1 în loc de class B2:protected A1 void main() {A1 *m[3],r1("var-r1",51); B2 r2("var-r2",52,53); C3 r3("var-r3",54,55,56,57); m[0]=&r1;m[1]=&r2; m[2]=&r3; m[0]->tipar(); m[1]->tipar(); m[2]->tipar(); getch();}
4. Se dă o clasă pentru gestiunea operaţiilor cu date calendaristice. Clasa conţine o variabilă ce memorează numărul se minute raportat la 31.12.1899, ora 24:00:00.000. Să se supraîncarce un operator care să permită adunare cu un anumit număr de zile (se va scrie declaraţia clasei, explicitarea unui constructor şi explicitarea funcţiei operator).
TEST #9 {cout<<”C3_var:”<
Se dau următoarele clase:
1. Ce se afişează în urma execuţiei ? #include #include #include #include
class A1 {int g; protected: int h; public:int xa,ya;char numevar[20]; static int s; A1() {xa=0;ya=0;strcpy(numevar,”N/A”); afis("CONSTRUCTOR_0”); } A1(char*); A1(char*, int); A1(char*,int,int); ~A1() {afis("DESTRUCTOR");} virtual void afis(char *str); virtual void tipar(); }; A1::A1(char *numevar1) {xa=0;ya=0;strcpy(numevar,numevar1); afis("CONSTRUCTOR_1"); } A1::A1(char *numevar1, int x1) {xa=x1;ya=0;;strcpy(numevar,numevar1); afis("CONSTRUCTOR_2"); } A1::A1(char *numevar1,int x1, int y1) {xa=x1;ya=y1;;strcpy(numevar,numevar1); afis("CONSTRUCTOR_3"); } void A1::afis(char *str) {cout<<”A1_var:”<
}
void B2::afis(char *str) {cout<<”B2_var:”<
int main() { C3 m1("m1"); B2 *g1,g2("g2",1,4); {A1 d1[2]; {A1 w2("w2",5,4); g1=new B2("g1",21,17); } delete g1; } getch(); return 0; }
.
2.Este posibilă execuţia următoarelor instrucţiuni? Explicaţi de ce! 22.1. void main() {A1 d1[2]; d1[0].g=1;} 2.2. void main() {B2 d1[2]; d1[1].g=3;} 2.3. void main() {B2 d1[2]; d1[1].xa=7;} 2.4. void main() {B2 d1[2]; d1[1].h=5;} 2.5. void main() {C3 a; a.h=7;} 2.6. void main() {C3 a; a.g=9;} 2.7. void main() {C3 a; a.xa=1;} 2.8. void main() {A1 *m[2]; C3 a; m[0]=@a;} 2.9. void main() {A1 m[2]; C3 *a; a=m[0];} 2.10. void main() {A1 m[2]; C3 *a; a>xa=(int)&m[0];}
.
3. Ce se afişează în urma execuţiei ?
void A1::tipar() {cout<<”xa=”<
C3:public A1 in loc de class C3:private A1 şi class B2:public A1 în loc de class B2:protected A1 void main() {A1 *m[3],r1("var-r1",31); B2 r2("var-r2",32,33); C3 r3("var-r3",34,35,36,37); m[0]=&r3;m[1]=&r2; m[2]=&r1; m[0]->tipar(); m[1]->tipar(); m[2]->tipar(); getch();}
4. Se dă o clasă pentru gestiunea operaţiilor cu date calendaristice. Clasa conţine o variabilă ce memorează numărul se minute raportat la 31.12.1899, ora 24:00:00.000. Să se supraîncarce un operator care să permită adunare cu un anumit număr de secunde (se va scrie declaraţia clasei, explicitarea unui constructor şi explicitarea funcţiei operator).
TEST #10
Se dau următoarele clase: #include #include #include
C3(char *numevar1,int x11,int y11,int s33): A1(numevar1,x11,y11) {numevar=new char[100]; strcpy(numevar,numevar1); s3=s33;afis("CONSTRUCTOR2 C3"); } ~C3() {afis("DESTRUCTOR C3");delete[] numevar;} void afis(char *str); }; void C3::afis(char *str) {printf("\n %s -- numevar:%s x3=%d y3=%d s3=%d t3=%d",str,numevar,x3,y3,s3,t3);}
class A1 {int x1,y1; char *numevar; protected: int s1; public: int t1; A1() {numevar=new char[100];strcpy(numevar,"N/A"); x1=0;y1=0;s1=-1;t1=-1;afis("CONSTRUCTOR_0 A1");} A1(char *numevar1) {numevar=new char[100]; strcpy(numevar,numevar1); x1=0;y1=0;s1=-1;t1=-1;afis("CONSTRUCTOR1 A1");} A1(char *numevar1,int x11, int y11) {numevar=new char[100]; strcpy(numevar,numevar1); x1=x11; y1=y11; s1=0;t1=0;afis("CONSTRUCTOR2 A1");} ~A1() {afis("DESTRUCTOR A1");delete[] numevar;} virtual void afis(char *str); private: void calc(); };
1. Ce se afişează în urma execuţiei ? int main(int argc, char* argv[]) {C3 *m2; A1 *r1; {A1 d1[2],w1("d1"),w2("d1",5,4); B2 *g1,g2("g2"); C3 m1("m1"); g1=new B2("g1",21,17,19); m2=new C3("m2",101,32,54); delete m2; r1=new A1("r1",11,61); delete g1; } delete r1; getch(); return 0; } 2.1.Ce va afişa funcţia afis(char *str) dacă nu este apelată ultima în cadrul unui constructor? 2.2. Ce va afişa funcţia afis(char *str) dacă nu este apelată prima în cadrul unui destructor?
void A1::afis(char *str) {printf("\n %s -- numevar:%s x1=%d y1=%d s1=%d t1= 2.3 De ce nu a putut fi afişat numevar şi pentru %d",str,numevar,x1,y1,s1,t1);} construcorul implicit? class B2: public A1 2.4 Ce legătură există între variabila numevar { char *numevar; din clasa de bază şi cea declarată în clasele int x2,y2,x1,y1,s1,t1; derivate? protected: 2.5.Pentru variabilele declarate la pct.1. Este int s2,t2; posibil accesul lui g1->t1? Explicaţi! public: Dar al lui m1->t1 ? Explicaţi! B2(char *numevar1):A1(numevar1) {numevar=new char[100]; 3. Adăugaţi câte un contor pentru numărul de strcpy(numevar,numevar1); obiecte instanţiate, pentru fiecare clasă în parte x2=0; y2=0; s2=0; t2=0; s1=-2;t2=-2; (adăugaţi direct pe codul scris şi rescrieţi numai afis("CONSTRUCTOR1 B2"); metodele modificate). Afişaţi acest număr în } cadrul constructorilor şi destructorilor. B2(char *numevar1,int x11,int y11,int s22): 4.Se dă: A1(numevar1,x11,y11) int main(int argc, char* argv[]) { numevar=new char[100]; { strcpy(numevar,numevar1); A1 w2("d1",5,4),d[3]; s2=s22;afis("CONSTRUCTOR2 B2"); B2 g2("g2",21,17,19); } C3 m2("m2",101,32,54); ~B2() {afis("DESTRUCTOR B2");delete[] numevar;} d[0]=w2; void afis(char *str); d[1]=g2;// 4.1 }; d[2]=m2; //4.2 d[0].afis("d[0]");//4.3 void B2::afis(char *str) d[1].afis("d[1]");//4.3 {printf("\n %s -- numevar:%s x2=%d y2=%d s2=%d d[2].afis("d[2]");//4.3 t2=%d",str,numevar,x2,y2,s2,t2);} getch(); return 0; class C3: protected A1 } { char *numevar; int x3,y3; 4.1. Este posiblil asignarea „d[1]=g2”;? protected: Explicaţi! int s3,t3; .4.2. Este posiblil asignarea „d[2]=m2”;? public: C3(char *numevar1):A1(numevar1) Explicaţi! . {numevar=new char[100]; 4.3. În cazul în care este posibilă asignarea ce strcpy(numevar,numevar1); se afişează în urma apelului metodei x3=0;y3=0;s3=0;t3=0;s1=-3;t1=-3; afis(“d[i]”) , i=0,1 sau 2 ? Explicaţi! afis("CONSTRUCTOR1 C3"); }