POO - Laborator 2 Definirea si utilizarea claselor. Functii constructor Structura de fisiere a unei aplicatii CPP cu clase este: - nume.h - fisier header care contine definitia clasei (sau a unui grup de clase inrudite) - nume.cpp - fisier sursa care contine implementarea clasei/claselor - concret e vorba de functiile membre care nu au fost definite chiar in definitia clasei - altnume.cpp - program principal (de exemplu un program de test) Din punct de vedere sintactic, clasa este o extensie naturala a structurii. O clasa este o structura in care toti membrii sunt impliciti private (inaccesibili din interior). Sa consideram definitia unei structuri de tip stiva de numere intregi. // // Fisierul stack.h - Definitia clasei // class stack { int *buf; int sp; // Acesti membri sunt impliciti private. int nrmax; // Ei pot fi accesati doar prin functii (metode) char nume[10]; // ale clasei public: // // Aceasta este o functie constructor. // Ea are acelasi nume cu clasa si este fara tip (nici macar void). // Functia constructor este apelata la crearea obiectelor (statica, auto sau dinamica). // stack (char *); stack (int, char *); // Alt constructor care va fi definit in exterior ~stack(); // Destructor: functie care va fi apelata la incetarea // duratei de viata a obiectului int is_empty() { return sp == -1; } int is_full() { return sp == nrmax-1; } void push (int); int pop(); char *getnume() { return (char *) nume; } }; Membrii private ai clasei stack sunt: - buf: pointer la un tablou de intregi - sp: indicatorul de stiva (initializat cu -1 <==> stiva vida) - nrmax: dimensiunea bufferului - nume: un nume asociat obiectului Exista doi constructori, unul cu parametru unic (numele clasei) si al doilea cu 2 parametri (dimensiune buffer si numele obiectului). Faptul ca pot exista mai multe functii constructor este o consecinta directa a supradefinirii. Metodele sunt: is_empty, is_full, push, pop, getnume, cu semnificatiile evidente. // // Fisierul stack.cpp - Implementarea metodelor clasei // #include #include #include #include "stack.h" stack::stack(char *obnume) { buf = new int [100]; sp = -1; nrmax = 100; strncpy(nume, obnume, 9); cout << "Constructor cu dimensiune implicita pentru obiectul " << nume << "\n"; } stack::stack(int dim, char *obnume) { // Constructor cu dimensiune precizata buf = new int [nrmax = dim]; sp = -1; strncpy(nume, obnume, 9); cout << "Constructor cu dimensiune explicita = " << dim << " pentru obiectul " << nume << "\n"; } stack::~stack() { delete [] buf; cout << "Destructor pentru obiectul " << nume << "\n"; } void stack::push(int elem) { if (!is_full()) buf[++sp] = elem; else { cout << "Eroare: stiva plina\n"; exit(1); } } int stack::pop() { if (!is_empty()) return buf[sp--]; else { cout << "Eroare: stiva vida\n"; exit(1); return -1; // Doar ca sa se respecte tipul functiei } } Pentru a pune in evidenta secventa de creare/distrugere a obiectelor, in functiile constructor si destructor s-au prevazut mesaje adecvate. De observat utilizarea operatorului de rezolutie ::, care precizeaza ca functiile respective sunt membre ale clasei stack (am putea avea o alta functie is_full care sa fie membra a unei clase coada). // // Fisierul tstack.cpp - Programul principal (de test) // #include #include "stack.h" stack a("a"); void main() { int i; stack b("b"); cout << "\n\n"<< "Start main\n"; stack c(200, "c"); stack *pd = new stack(300, "d"); a.push(1); a.push(2); pd->push(3); cout << "Pop din stiva " << pd->getnume() << ": " << pd->pop() << "\n"; // // Etc., etc. // delete pd; // A fost alocat dinamic, deci eliberam memoria cout << "Sfirsit main\n"; } Se defineste un obiect stack la nivel exterior "a" (cu alocare statica). El va fi creat inainte de a incepe executia functiei main. In main se definesc doua obiecte in clasa auto ("b" si "c") si unul prin alocare dinamica (a se vedea forma new stack(...)). Apoi se fac citeva operatii uzuale cu stivele astfel definite. La consola se va urmari si explica secventa de mesaje din functiile constructor, destructor si main. De observat afisarea comoda la consola (cout) cu operatorul << (e necesar #include ). Tema 1) Pentru testare, se va defini un proiect (Project/Open Project, apoi Add files, apoi Close Project), care sa contina fisierele stack.h, stack.cpp si tstack.cpp. Astfel se poate lucra comod cu mediul integrat Borland. 2) Se va scrie o secventa care sa inverseze ordinea elementelor dintr-un tablou de intregi prin push intr-o stiva si apoi pop. Se va lista tabloul inainte si dupa secventa respectiva. 3) Functia push testeaza daca stiva nu e plina si da un mesaj de eroare in acest caz. Sa se rescrie aceasta functie astfel incit, in situatia de stiva plina, sa se realoce un buffer de dimensiune mai mare. Trebuie avute in vedere copierea continutului bufferului vechi in cel nou si eliberarea memoriei ocupate de cel vechi. Observatie Unele compilatoare mai vechi, de exemplu Borland 2.0, nu recunosc operatotul delete []. Se va substitui acesta cu delete obisnuit (in ~stack).