Documente Academic
Documente Profesional
Documente Cultură
n aceast seciune sunt prezentate soluii pentru unele din exerciiile propuse n text. n general, s-au selectat acele exerciii care ofer o modalitate de abordare a unei anumite categorii de probleme i cele care ofer rspunsuri n situaii mai deosebite de execuie. Celelalte, care extind doar materialul deja soluionat, rmn ca exerciiu de programare pentru cititori.
Deoarece incrementarea postfix permite utilizarea incrementarea acesteia, se poate scrie mai concis astfel:
while (*q! = 0) *p++ = *q++; *p = 0;
valorii
apoi
Deoarece valoarea *p++ = *q++ este *q, se poate scrie nc mai concis:
while(*p++ = *q++);
E1.4 Funcia fr() returneaz o referin la o variabil local. Unele compilatoare dau un mesaj de atenionare (warning) n acest sens. Dup apelul funciei fr(), int& v = fr(4, 6); referina v va indica variabila local x n funcia, care se afl n stiv. Apelul altei funcii (cum este funcia operator <<) folosete stiva, modificnd coninutul acesteia, deci inclusiv locaia de memorie refereniat cu numele v. De aceea, cele dou operaii de scriere la consol a referinei v pot s dea rezultate diferite.
214
E1.8
2 Clase i obiecte
E2.4 Mesajele sunt: Nr. Nr. Nr. Nr. Nr. Nr. Nr. Nr. Nr. Nr. Nr. Nr. Nr. Nr. Nr. Nr. obiecte obiecte obiecte obiecte obiecte obiecte obiecte obiecte obiecte obiecte obiecte obiecte obiecte obiecte obiecte obiecte 1 2 3 4 5 4 3 4 5 6 5 4 3 2 1 0
Primele trei obiecte (ob1, ob2, ob3) sunt create la nceputul funciei main(). La intrarea n blocul nou creat se mai creeaz 2 obiecte (ob4 i ob5) (deci numrul de obiecte ajunge la 5), care sunt imediat distruse la ieirea din bloc. Dup aceasta se creeaz un vector de 3 obiecte, care sunt distruse prin apelul operatorului delete. La ieirea din funcia main() se distrug i cele 3 obiecte rmase, ob1, ob2, ob3. E2.5 Programul modificat este:
#include <iostream.h>
Soluii class Item{ static int numbers; // (a) public: Item(){ // constructorul creste cu 1 nr obiectelor numbers++; cout << "Nr. obiecte " << numbers << endl; } ~Item(){ //destructorul descreste cu 1 nr obiectelor numbers--; cout << "Nr. obiecte " << numbers << endl; } }; int Item::numbers = 0; // (b) void main(){ Item ob1, ob2, ob3; { // se deschide un nou bloc Item ob4, ob5; } Item *pob6 = new Item[3]; delete [] pob6; }
215
Se remarc urmtoarele modificri notate (a) i (b): (a) numbers este declarat membru static al clasei Item. (b) numbers este definit i iniializat n alt parte n program, n afara clasei Item. (a) Mesajul afiat la consol este: 11 22 33 44 (b) Modificarea pointerilor p i p1, urmat de tergerea lor cu delete produce eroare de execuie, deoarece se ncearc eliberarea altei zone de memorie dect cea alocat. E2.7 Funciile de inserare i eliminare a unui element din vectorul clasei IntArray sunt:
int IntArray::InsertAt(int i, int x){ if (i < 0 || i > count){ cout << Eroare indice de inserare\n; return -1; // eroare de inserare } else { if (i == count) Add(x); else { if (count < size){ for (int j= count; j > i;j--) p[j] = p[j-1]; p[i] = x; count++; } else {
E2.6
216
Elemente de Programare Orientat pe Obiecte int *p1 = p; p = new int[count + grows]; for (int j=0; j < i;j++) p[j] = p1[j]; p[i] = x; for (j=i; j < count;j++) p[j+1] = p1[j]; delete p1; count++;
} } int IntArray::RemoveAt(int i) { if (i < 0 || i >= count){ cout << Eroare de stergere element\n; return 0; } else { for(int j=i; j < count-1;j++) p[j] = p[j+1]; count--; return 1; } }
} } return count - 1;
0 33 55.
E2.8 La apelul funciei fint()programul d eroare de execuie, deoarece se transmite un argument de apel prin valoare care se copiaz n variabila local
Soluii
217
corespunztoare. Eroarea apare datorit copierii membru cu membru a unui obiect de clas IntArray care conine date alocate dinamic. Soluia corect este de a se defini un constructor de copiere al clasei IntArray astfel:
IntArray::IntArray(IntArray &r){ count = r.count; grows = r.grows; size = r.size; p = new int[size]; for (int i = 0; i < count; i++) p[i] = r.p[i]; }
E2.11 Este necesar ca unele funcii membre ale clasei s acceseze obiecte declarate const. Deci sunt necesare urmtoarele modificri: int GetCount() const {return count;} int GetAt(int i) const;
Dezavantajele acestei implementri sunt: nu se poate defini o list vid; orice operaie de inserare sau tergere modific valoarea pointerului la list; pentru
218
extragerea unui element se folosesc dou funcii GetHead() i RemoveHead(), iar dup aceea nodul eliminat din list trebuie ters folosind operatorul delete. E3.2 Destructorii claselor IntSListNode i IntSList se mai pot defini i astfel:
~IntSListNode(){ cout << "Destructor nod v = "<< v <<endl; if(link){ delete link; link = 0; } } IntSList::~IntSList(){ IntSListNode* p = first; if (first){ delete first; first = 0; } }
Cu aceste definiii nodurile listei se terg n ordine invers, ncepnd cu ultimul nod i sfrind cu primul nod. Mesajele care se afieaz la execuia funciei fslist1() sunt urmtoarele:
1 2 3 4 5 Destructor Destructor Destructor Destructor Destructor nod nod nod nod nod v v v v v = = = = = 5 4 3 2 1
219
} IntDList::IntDList(IntDList& r){ first = 0; last = 0; count = 0; IntDListNode* ref = r.first; for (int i=0;i<r.count;i++){ AddTail(ref->v); ref = ref->next; } } IntDList::~IntDList(){ IntDListNode* p = first; while (p){ IntDListNode* current = p; p = p->next; delete current; } }
220
Funcia Display() a clasei IntDList afieaz elementele listei de la capul listei pn la sfritul acesteia. Funcia ReverseDisplay() afieaz elementele listei n ordine invers: de la sfritul listei pn la primul element.
void IntDList::Display(){ IntDListNode* p = first; while (p){ cout << p->v <<" "; p = p->next; } cout << endl; } void IntDList::ReverseDisplay(){ IntDListNode* p = last; while (p){ cout << p->v<<" "; p = p->prev; } cout << endl; }
Funciile de citire a elementelui din capul listei (GetHead()) i a elementului de la sfritul listei (GetTail()) i funciile de extragere element (RemoveHead() i RemoveTail()) sunt urmtoarele:
int IntDList::GetHead(){ if (count == 0){ cout << Eroare lista vida\n; return -1; } else return first->v; } int IntDList::GetTail(){ if (count == 0){ cout << Eroare lista vida\n; return -1; } else return last->v; } int IntDList::RemoveHead(){ if (count == 0){ cout << Eroare lista vida\n; return -1; } else { int v = first->v; IntDListNode* p = first; first = first->next; if (first) first->prev = 0; delete p;
221
} } int IntDList::RemoveTail(){ if (count == 0){ cout << Eroare lista vida\n; return -1; } else { int v = last->v; IntDListNode* p = last; last = last->prev; if (last) last->next = 0; delete p; count--; if (count == 0){ first = 0; } return v; } }
E3.6
void IntTree::postorder1(IntTreeNode *root){ if(!root) return; postorder1(root->left); postorder1(root->right); if(root->d) cout << root->d <<" ";
}
void IntTree::postorder(){ postorder1(root); } void IntTree::delTree1(IntTreeNode *root){ if(!root) return; delTree1(root->left); delTree1(root->right); delete root; }
E3.7
if (f(data, r->d) == 0) return 0; if(f(data, r->d) < 0) return insert1(r, r->left, data); else return insert1(r, r->right, data);
}
void PointTree::insert(Pdate data) { if(!root) root = insert1(root, root, data); else insert1(root, root, data);
}
Soluii void PointTree::preorder(){ preorder1(root); } void PointTree::postorder1(PointNode *root){ if(!root) return; postorder1(root->left); postorder1(root->right); if(root->d) g(root->d); } void PointTree::postorder(){ postorder1(root); } void PointTree::delTree1(PointNode *root){ if(!root) return; delTree1(root->left); delTree1(root->right); delete root; } PointTree::~PointTree(){ delTree1(root); }
223
Funcia de creare a unui arbore binar ordonat folosind clasa PointTree i clasa info este urmtoarea:
void fp1(){ int n = 10; PointTree tree(comp, execute); for(int i=0;i<n;i++){ info *in = new info(rand()%100); tree.insert(in); } cout <<"Numar noduri: " << tree.getcount()<< endl; tree.inorder(); cout << endl; tree.preorder(); cout << endl; tree.postorder(); cout << endl; }
La execuia acestei funcii se creeaz un arbore binar cu 10 noduri; numerele din aceste noduri sunt afiate n ordine cresctoare (prin funcia inorder()), apoi n preordine i n postordine. Aceast reprezentare a unui arbore binar sortat, chiar dac permite generalizarea tipului de informaie din nodul arborelui prin utilizarea unui pointer generic, este destul de incomod (necesit conversii explicite de la pointerul la tipul de date dorit la pointer generic i invers) i este nesigur tocmai datorit faptului c prin conversiile explicite se ocolete mecanismul de verificare a tipului datelor specific limbajelor orientate pe obiecte. Mai mult, sunt necesare funcii callback pentru definirea relaiei de preceden sau a prelucrrilor necesare pentru fiecare tip de date.
224
void NTree::PostOrder(){ if(first){ NTree *current = first; NTree *next = current; while (next){ current = next; next = next->link; current->PostOrder();
} }
if (label) cout << "Nod: " << label << endl; else cout << "Nod: " << endl;
}
void NTree::RemoveChild() { if (first){ NTree* current = first; first = first->link; current->RemoveAll(); } else cout << "Nu are fii\n"; } void NTree::RemoveAll() { if(first) { NTree *current = first; NTree *next = first; while (next){ current = next; next = next->link; current->RemoveAll(); delete current->label; } }
}
225
4 Suprancrcarea operatorilor
E4.1 Clasa Date se definete astfel:
class Date{ int day; int month; int year; public: Date(int d=5, int m=7,int y=1999){ year = y; month = m; day = d;
}
}; ostream& operator <<(ostream& stream, Date& d){ stream << " Ziua: " << d.day << " Luna: " << d.month << " Anul: " << d.year << endl; return stream; }
Date operator++(); friend ostream& operator <<(ostream& stream, Date& d); int& operator[](int i);
E4.2
} if (day==31 && month == 12){ year++; month = 1; day = 1; return *this; } if (day < 30){ day++; return *this;
}
if (day==31 && (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10)){ day = 1; month++; return *this; if (day==30 && (month == 4 || month == 6 || month == 9 || month == 11 )){ day = 1; month++; return *this;
return *this;
E4.3
// afiseaz 2
E4.5 Eroarea de execuie apare la construcia obiectului, datorit faptului c pointerul pasat ca argument indic un tablou de caractere, nu un ir, deci lipsete caracterul 0 la sfritul irului necesar n constructorul de iniializare. Pentru evitarea erorii se definete constructorul:
Soluii String::String(const char* p, int n){ cout << "Constructor init\n"; size = n+1; str = new char[n+1]; for (int i=0;i<n;i++) str[i] = p[i]; str[n] = 0; }
227
E4.7 Funcia operator+() a clasei String care concateneaz dou iruri i o funcie fs() de verificare a funcionrii acestui operator sunt:
String operator+(const String& s1, const String& s2){ String temp; temp.size = s1.size+s2.size-1; temp.str=new char[temp.size]; strcpy(temp.str, s1.str); strcat(temp.str, s2.str); return temp; } void fs(){ String string1="ABCDEF"; String string2="GHIJ"; String string3 = string1+string2; cout << string3; //afiseaza ABCDEFGHIJ }
La execuia funciei fia2() se copiaz ultima jumtate a irului de caractere peste prima jumtate. Mesajele afiate la consol sunt:
0 1 2 3 4 5 6 7 7 6 5 4 4 5 6 7
228
229
CPoint::CPoint(const CPoint &r){ cout << "Constructor copiere\n"; dim = r.dim; coord = new double[dim]; for (int i=0;i<dim;i++) coord[i] = r.coord[i];
}
Point::~CPoint(){ cout << "Destructor CPoint\n"; if (coord){ delete coord; coord = NULL;
} }
void CPoint::Compare(const CPoint& p){ if (dim != p.dim) cout<<"Punctele nu sunt in acelasi spatiu\n"; else { for (int i=0; i<dim;i++) if (coord[i] != p.coord[i]){ cout<<"Punct nu sunt identice\n"; break;
}
Declaraia acestei funcii trebuie s fie adugat n declaraia clasei CPoint. Funcia fcp1() este urmtoarea:
void fcp1(){ double coord[] = {4,5,6,1};
230
Elemente de Programare Orientat pe Obiecte CPoint p13 = CPoint(3, coord); cout << p13; CPoint p14 = CPoint(4, coord); cout << p14; p13.Compare(p14); p13 < p14;
E5.2
Declaraia acestei funcii trebuie adugat n clasa CPoint. Se pot citi i modifica coordonatele unui punct folosind funcia operator de indexare astfel:
void fcp2(){ double coord[] = {4,5,6,1}; CPoint p14 = CPoint(4, coord); cout << p14; cout << p14[0] << p14[1] << p14[2] << p14[3] << endl; p14[0] = 0; cout << p14;
}
E5.3
Soluii CPoint2d(double *p):CPoint(2,p){} ~CPoint2d(){ cout << "Destructor 2d" << endl; } void Display (){ cout << "Display 2d "; cout << *this; }
231
}; class CPoint3d:public CPoint{ public: CPoint3d():CPoint(3){} CPoint3d(double x, double y, double z):CPoint(3){ cout << "Constructor 3d" << endl; (*this)[0] = x; (*this)[1] = y; (*this)[2] = z; } CPoint3d(double *p):CPoint(3,p){} ~CPoint3d(){ cout << "Destructor 3d" << endl; } void Display(){ cout << "Display 3d "; cout << *this; } };
n constructorii claselor derivate s-a folosit funcia operator de indexare a clasei de baz, apelat n dou modaliti. La compilarea funciei fpd() se obine de dou ori mesajul de eroare 'Display' : is not a member of 'CPoint', deoarece se apeleaz cu pointer de tipul CPoint* funcia Display() care nu este definit n acast clas. Soluia corect este declararea funciei: virtual void Display(){} n clasa CPoint. De asemenea destructorul clasei CPoint trebuie s fie declarat virtual. Mesajele afiate la execuia funciei fdp() dup aceast completare sunt:
Constructor initializare cu 1 arg Constructor 2d Display 2d Dimensiune: 2 Coordonate 4 5 Destructor 2d Destructor CPoint Constructor initializare cu 1 arg Constructor 3d Display 3d Dimensiune: 3 Coordonate 4 5 1 Destructor 3d Destructor CPoint
232
Aceste mesaje arat modul de construire a obiectelor, apelul funciei Display() redefinite n fiecare clas derivat i tergerea complet i corect a obiectelor create. E5.6 Funciile membre ale claselor de baz DListNode i DList se definesc astfel:
DList::~DList(){ DListNode* p = first; while (p){ DListNode* current = p; p = p->next; delete current; } } void DList::AddHead(DListNode* elem){ if (count == 0){ first = elem; last = elem; } else{ first->prev = elem; elem->next = first; first = elem; } count++; } void DList::AddTail(DListNode* elem){ if (count==0){ first = elem; last = elem; } else{ last->next = elem; elem->prev = last; last = elem;
}
count++;
}
DListNode* DList::GetHead() {return first;} DListNode* DList::GetTail() {return last;} DListNode* DList::RemoveHead(){ if (count == 0)return 0; else { DListNode* v = first; first = first->next; if (first) first->prev = 0; count--; if (count == 0)last = 0; return v; } }
Soluii DListNode* DList::RemoveTail(){ if (count == 0)return 0; else { DListNode* v = last; last = last->prev; if (last)last->next = 0; count--; if (count == 0)first = 0; return v; } }
233
Funciile membre ale claselor derivate IDListNode i IDList care reprezint o list dublu nlnuit de numere ntregi se definesc astfel:
void IDList::AddHead(int x){ IDListNode* p = new IDListNode(x); DList::AddHead(p); } void IDList::AddTail(int x){ IDListNode* p = new IDListNode(x); DList::AddTail(p); } IDListNode* IDList::GetHead(){ return (IDListNode*) DList::GetHead(); } IDListNode* IDList::GetTail(){ return (IDListNode*) DList::GetTail(); } int IDList::RemoveHead(){ IDListNode* p = (IDListNode*)DList::RemoveHead(); if (p){ int v = p->GetV(); delete p; return v; } else return 0; } int IDList::RemoveTail(){ IDListNode* p = (IDListNode*)DList::RemoveTail(); if (p){ int v = p->GetV(); delete p; return v; } else return 0;
} ostream& operator <<(ostream& stream, IDList& list){ IDListNode* p = list.GetHead(); while (p){ stream << p->GetV()<<" ";
234
Elemente de Programare Orientat pe Obiecte p = (IDListNode*)p->GetNext(); } stream << endl; return stream;
Pentru verificarea funcionrii listei definite prin intermediul acestor clase derivate se reia funcia fdlist2(), n care se modific tipul listelor create din IntDList n IDList. La execuia funciei astfel modificate (fd2()) se obin aceleai mesaje.
void fd2(){ cout << "Functionare ca stiva a listei\n"; IDList list2; list2.AddHead(1); // push 1 list2.AddHead(2); // push 2 list2.AddHead(3); // push 3 cout << list2; // afiseaza 3 2 1 cout << list2.RemoveHead(); // pop, afiseaza 3 cout << list2.RemoveHead(); // pop, afiseaza 2 cout << list2.RemoveHead(); // pop, afiseaza 1 cout << "Functionarea ca o coada a listei\n"; IDList list3; list3.AddTail(1); // inserare 1 list3.AddTail(2); // inserare 2 list3.AddTail(3); // inserare 3 cout << list3; // afiseaza 1 2 3 cout << list3.RemoveHead(); //extragere, afiseaza 1 cout << list3.RemoveHead(); //extragere, afiseaza 2 cout << list3.RemoveHead(); //extragere, afiseaza 3
E5.10 Funciile necesare pentru suprancrcarea operatorului de indexare al clasei IDList sunt: funcia DListNode* operator[](int x) n clasa de baz DList i funcia int& operator[](int x) n clasa derivat IDList. Aceste funcii se definesc n felul urmtor:
DListNode* DList::operator[](int x){ DListNode* p = first; for (int i=0;i<x;i++) p = p->next; return p; } int& IDList::operator[](int x){ IDListNode* p = (IDListNode*)DList::operator[](x); return p->GetV(); }
Dup definirea acestor funcii operator, elementele listei pot fi accesate prin indexare att pentru citire ct i pentru modificare, deoarece funcia operator []
Soluii
235
returneaz o referin la valoarea coninut n nodul indexat al listei. Funcia fd3() se execut corect. E5.13 Funcia operator de indexare a clasei ObArray se definete astfel:
Object* ObArray::operator[](int i) { return p[i];}
Ea poate fi utilizat pentru suprancrcarea operatorului de indexare n orice clas derivat din clasa ObArray. De exemplu, pentru clasa PointArray:
Point* PointArray::operator[](int i){ return (Point*)ObArray::operator[](i); }
E5.14 Se modific clasa Complex definit n seciunile precedente astfel nct s fie derivat din clasa de baz Object:
class Complex : public Object{ double x,y; public: Complex(double xx, double yy) {x=xx; y=yy; } Complex(double v){ x = v; y = v;} ~Complex() {}; //.. };
unde ABCDEFGH este irul de caractere introdus de la consol. Funcia fs() i funcia operator >> a clasei String sunt urmtoarele:
void fs(){ String string1; cin >> string1; } istream& operator >>(istream &stream, String &r){ char buf[256]; cin.get(buf,256); r = buf; return stream; }
Constructorul implicit este apelat la crearea irului string1. La execuia instruciunii r = buf; din funcia operator >> se creaz un obiect temporar de tipul String prin apelul unui constructor de iniializare prin care bufferul de caractere este convertit n obiect de tip String; valoarea acestui obiect este asignat referinei r prin funcia operator de asignare. La returnare din funcia operator de asignare se creaz un obiect temporar prin apelul constructorului de copiere. Cele dou obiecte temporare sunt distruse dup revenirea n funcia fs(). La terminarea funciei fs() este distrus i obiectul string1 creat n aceast funcie. Dac se suprim funcia operator=() a clasei String, se execut o copiere membru cu membru a obiectului temporar de tip String n referina r, folosind constructorul de copiere implicit generat de compilator. Aceast operaie produce eroare de execuie datorit faptului c n dou obiecte String pointerii la vectorul de caractere indic aceeai zon de memorie. La distrugerea obiectelor se apelez operatorul delete de dou ori pentru accei adres de memorie, ceea ce produce eroare de execuie. E6.10 Secvena se apeluri a funciilor iteratorului de clas SetIter a unei mulimi de numere ntregi reprezentat printr-un vector ordonat (clasa IntSet) este: SetIter iter(&set); // iterator pt. multimea set while(iter.inside()) cout << iter.next() << " "; cout << endl; Aceast secven se poate nlocui cu instruciunea cout << iter; dac se definete funcia friend operator << a clasei SetIter astfel:
ostream& operator<<(ostream& stream, SetIter& iter){ iter.start(); while(iter.inside())
Soluii stream << iter.next() << " stream << endl; return stream; ";
237
E7.5 Eroarea de compilare din instruciunea for (; iter; ++iter) apare datorit faptului c nu se poate folosi obiectul iter de clas MapIter ntr-o expresie condiional dac nu exist un operator de conversie la un tip de date care s poat fi comparat cu zero. n locul operatorului de conversie operator void*() se poate folosi un operator de conversie la valoare de tip ntreg astfel:
operator int() { return (int)node; }
n acest caz, ultimul cmp afiat n fiecare linie este valoarea pointerului node convertit n ntreg i afiat zecimal. E7.6 Destructorii claselor MapNode i Map se implementeaz astfel:
template<class K, class V> MapNode<K,V>::~MapNode(){ if (right){ K tmp = right->key; cout << "delete node "<< right->key << endl; delete right; cout << "node "<< tmp << "deleted" << endl; } }
238
Elemente de Programare Orientat pe Obiecte template<class K, class V> Map<K,V>::~Map(){ K tmp = head->key; cout << "delete node " << head->key<< endl; delete head; cout << "node " << tmp << "deleted" << endl; }
La execuia funciei fm2() se creeaz un vector asociativ reprezentat printr-o list nlnuit compus din trei elemente, cu cheile word1, word2, word3. La terminarea funciei fm2() se apeleaz destructorul obiectului table de tip Map, care afieaz un mesaj la consol i apeleaz operatorul delete pentru primul element din list (indicat de pointerul head). Operatorul delete pentru obiectul de clas MapNode apeleaz destructorul clasei. Acest destructor afieaz un mesaj la consol i apeleaz operatorul delete pentru elementul urmtor din list. n acest fel se terge recursiv ntreaga list nlnuit. Mesajele afiate la consol la execuia funciei f3() sunt urmtoarele:
word1 5 word2 8 word3 6 delete node word1 delete node word2 delete node word3 node word3 deleted node word2 deleted node word1 deleted
Elmentele din list se terg ncepnd cu ultimul nod n list, pn la primul. E7.7 Pentru a se folosi acelai iterator iter pentru o nou afiare a listei nlnuite este necesar repoziionarea iteratorului pe primul element al listei. Pentru aceasta n clasa MapIter se adaug funcia:
void first(){ node = map->head; }
n funcia fm2(), dup prima afiare a coninutului listei, se execut poziionarea iteratorului pe primul element din list prin instruciunea: iter.first(); dup care se poate folosi acelai iterator pentru o nou parcurgere a listei. Mesajele afiate la consol se repet pentru cea de-a doua parcurgere la fel ca n prima parcurgere a listei. E7.11 Funcia este urmtoarea:
template <class T> void iocopy(T z, istream& is, ostream& os){
239
Variabila de tip T este transmis ca argument funciei iocopy() numai pentru a se putea identifica tipul obiectului z care se copiaz. Valoarea acesteia nu este utilizat. E7.14 Clasa template TArray se definete astfel:
#include <iostream.h> template <class E> class TArray { E* p; int count; int size; int grows; public: TArray(){ count = 0; grows = 4; size = grows; p = new E[grows]; } TArray(TArray &r); TArray(int* v, int n); ~TArray() { delete p;} int Getcount() const {return count;} int Add(E x); E& GetAt(int i) const{ if (i >= 0 && i < count) return p[i]; else { cout << "Eroare depasire indice\n"; return p[0]; } } int InsertAt(int i, E x); int RemoveAt(int i); E& operator[](int i){return p[i];} friend ostream& operator << (ostream& stream, TArray<E>& r); };
Toate funciile clasei se pot dezvolta prin analogie cu clasa IntArray. O parte dintre acestea sunt prezentate mai jos:
template <class E> int TArray<E>::Add(E x){ if (count < size) p[count++] = x; else { E *p1 = p; p = new E[count + grows]; for (int i=0; i<count;i++)
} template <class E>ostream& operator << (ostream& stream, TArray<E>& r){ int count = r.count; for (int i =0;i<count;i++) stream << r.p[i] <<" "; stream << endl; return stream; } template <class E> TArray<E>::TArray<E>(E* v, int n){ count = n; p = new E[count]; for (int i = 0; i < count; i++) p[i] = v[i]; } template <class E> int TArray<E>::RemoveAt(int i){ if (i < 0 || i >=count) return 0; else { for(int j=i; j < count-1;j++) p[j]=p[j+1]; count--; return 1; } }
} return count-1;
Utilizarea clasei template TArray pentru vectori de numere ntregi, TArray<int> sau pentru vectori de numere complexe TArray<Complex> arat astfel:
void fit1(){ int v[] = {0,1,2,3,4,5,6,7}; int size = sizeof(v)/sizeof (int); TArray<int> iarray(v, size); cout << iarray; // afiseaza 0 1 2 3 4 5 6 7 TArray<Complex> carray; carray.Add(Complex(3.5,8)); carray.Add(Complex(6,9.2)); cout << carray; // afiseaza (3.5,8) (6,9.2)
E7.20 O stiva de numere complexe se poate implementa prin clasa template Tlist astfel:
void ft3(){ TList<Complex> list4;
Soluii list4.AddTail(Complex(1,2));// inserare list4.AddTail(Complex(3,4));// inserare list4.AddTail(Complex(5,6));// inserare cout<< list4.RemoveHead(); //extragere, cout<< list4.RemoveHead(); //extragere, cout<< list4.RemoveHead(); //extragere, cout << endl;
}
241 (1,2) (3,4) (5,6) afiseaza (1,2) afiseaza (3,4) afiseaza (5,6)
8 Tratarea excepiilor
E8.3 Se completeaz clasa IntArray astfel:
class IntArray { //. public: class Range{ int index; public: Range(int i){index = i;} int GetIndex(){return index;} }; int GetAt(int i) const; int& operator[](int i); }; int GetAt(int i) const{ if (i >= 0 && i < size) return p[i]; else{ throw Range(i); return -1; }
}
int& operator[](int i){ if (i >= 0 && i < size) return p[i]; else{ throw Range(i); return p[0]; } }
O funcie care capteaz excepia de depire a indicelui i trateaz aceast excepie este urmtoarea:
void fia3(){ try{ int v[] = {0,1,2,3,4,5,6,7}; int size = sizeof(v)/sizeof (int); IntArray array(v, size); cout << array;
242
Elemente de Programare Orientat pe Obiecte for (int i=0;i<size+3;i++) array[i] = i; cout << array;
} catch(IntArray::Range r){ cout << "Indicele " << r.GetIndex() << " depseste domeniul\n"; } }
Se observ faptul c dup tratarea erorii programul este continuat dup rutina de tratare a excepiei i nu cu instruciunile care urmeaz instruciunii care a provocat excepia. E8.4 Se definete clasa global pentru excepia de extragere a unei date dintr-o list goal astfel:
class Empty{ public: Empty(){}; };
Captarea i tratarea unei excepii de list vid se poate face n felul urmtor:
Soluii
243
void fdlist3(){ try{ IntDList list2; list2.AddHead(1); // push 1 list2.AddHead(2); // push 2 list2.AddHead(3); // push 3 cout << list2.RemoveHead(); // pop, afiseaza 3 cout << list2.RemoveHead(); // pop, afiseaza 2 cout << list2.RemoveHead(); // pop, afiseaza 1 cout << list2.RemoveHead(); // lanseaza exceptia cout << list2.RemoveHead(); } catch(Empty){ cout << "\nExceptie lista goala\n"; } cout << Dupa rutina de tratare a excepiei\n; }
La execuia acestei funcii, ultima operaie RemoveHead() lanseaz excepia Empty, deoarece lista era deja goal. Rutina de tratare a excepiei afieaz un mesaj la consol, iar execuia se continu dup aceast rutin, nu cu instruciunile care urmeaz aceleia care a lansat excepia. Ca urmare, mesajele afiate la consol sunt:
321 Exceptie lista goala Dupa rutina de tratare a exceptiei
Pentru clasa IntSlist se procedeaz n mod similar. E8.10 Se completeaz clasa Date astfel:
class Date{ //. public: int& operator[](int i); class Range{ int indice; public:Range(int i){indice = i;} int get(){return indice;} }; }; int& Date::operator[](int i){ if (i<0 || i>2) throw Range(i); if (i==0) return day; else if (i==1) return month; else return year; }
244