duminică, 25 mai 2008
Notele finale
Nume Nota proiecte Nota lucrare
1. Sulea Octavia-Maria 9 8.5
2. Popescu Andreea-Lavinia 8.5 8
3. Chiorean Vlad Alexandru 8.5 7.5
4. Negrota Remus Sebastian 9 10
5. Ciulei Cristian 6 7.5
6. Raulea Mihai 8.5 6
7. Ganju Ionut 10 10
8. Balint Alexandru 7 7
9. Iorgulescu Alexandra 8.5 6
10 Cretu Horia 10 9
11. Tone Cristian 9.5 10
12. Tomescu Bogdan George 6 8
13. Eftimescu Mircea 8.5 9
14. Leonte Roxana-Cristina 10 6
15. Grigoras Razvan-Valentin 9 9
16. Dorojan Elena Cristina 8 7
17. Paraschiv Mihai Alexandru 9 10
18. Iorgulescu Stefan 10 6
19. Josu Vladimir 7 10
20. Mereuta Mihai Andrei 8 7
21. Ionita Anca 9 9
22. Ciobanu Vladimir 5 5
joi, 22 mai 2008
Problema
pint p; // pointer "sigur" la int
p= new pint[10]; // imi aloca niste memorie
p = new pint; //iar imi aloca niste memorie si o pierde pe cea de mai devreme - memory leak; ar trebui dezalocata memoria de mai devreme.
Programul trebui sa incerce sa rezolce toate cazurile asemanatoare/posibile.
Rezolvarea pana la 9 jumate (ceasul mailului meu). Cine depaseste chiar ca nu mai am ce face.
luni, 19 mai 2008
Problema se intoarce
{
arbore a;//arb binar de cautare/ordonat
cin>>a;
a+=1;
a+=4;
arbore b;
b+=5;
b+=6;
arbore c;
c=a+b;
if(c.inArbore(2))
cout<<"am gasit elementul\n";
a.getLeft().getRight() = 9;
cout<< c;
}
duminică, 18 mai 2008
Problema
{
cout<<("tEXT"+s+" "+10+" "+20.5);
void main()
{
mystring s(20);
cin>>s;
afisare(s);
mystring text2;
text2 = s+s;
cout<< text2;
for(int i=0;i < text2.length();i++)
cout<< text2[i]+" ";
}
Lucrare lab
1. Maria S.
2. Andreea P.
3. Ionut G.
4. Horia C.
5. Bogdan T.
6. Razvan G.
7. Vladimir J.
8. Mihai R.
Marti:
1. Vlad C.
2. Cristian C.
3. Alexandru B.
4. Alexandra I.
5. Mircea E.
6. Elena D.
7. Stefan I.
8. Anca I.
Daca nu s-a gasit cineva pe lista let me know. Proiectele inca se corecteaza :(
Va astept :D
PS: marti de la ora 8 sala 315
vineri, 25 aprilie 2008
Proiect 3
Ideea la proiectul 3 este sa creati o clasa lista universala - campul de informatie trebuie sa poata stoca orice tip de data/clasa.
Sunt mai multe metode de implementare, nu va restrang la nici una dar va recomand sa o incercati pe a treia (punctajul va fi un pic subiectiv si adjustat in functie de complexitatea rezolvarii oferite de voi - asta nu inseamna ca daca faceti ca mine pierdeti puncte ci doar sa incercati sa scrieti cat mai bine algoritmul si sa fie cat mai universal).
Metode de rezolvare care imi trec in cap momentan:
1. liste clasice cu o modalitate de a avea ca membru orice tip de clasa (fara templates)
2. liste clasice cu templates
3. mai apropiat de conceptul de vector decat cel de lista. Dar imaginati-va urmatoarea structura:
struct Lista{
ListHeader header;
void *data;
}
data va pointa catre spatiul de memorie alocat pentru lista noastra. ListHeader ar trebui sa aiba cam urmatorii membri:
- dimensiunea unui element (pentru lista de int va fi sizeof(int) etc)
- nr de elemente alocate
- nr de elemente in lista
- marja de siguranta - daca nr alocate - nr lista <= marja realocam lista (realloc) cu
- nr elemente alocate la realocare
Lista trebuie sa poata as faca:
- insertie
- scoaterea unui element din lista
- cautarea dupa indice si cheie (la cheie e un pic dubios pentru unele clase, incercati ceva cat mai ... cum va trece voua prin cap si cat de cat okay)
- sortarea elementelor listei (aveti grija ca nu e obligatori ca toate clasele sa aiba suprascris operatorul <)
Paste Fericit si toate cele bune.
marți, 22 aprilie 2008
Update
In legatura cu proiectul 2 - este recomandat sa-l faca macar cat de cat cei care nu prea m-au vazut la ochi semestrul asta pe la laborator. Sper ca saptamana asta sa afisez enuntul la proiectul 3 care va fi obligatoriu.
Pentru orice nemultumiri/neclaritati nu ezitati sa ma contactati.
Pentru cei care au ratat ultimul laborator faceti un google search pentru c++ template classes si cititi primul link s ava faceti o idee despre templates.
luni, 14 aprilie 2008
Intrebare update
Stiu ca a fost un pic nedrept pentru unii din voi etc...
duminică, 13 aprilie 2008
Proiect 1 again
Clasa "matrice" (matrice de double), avand:
- membri privati pentru matricea propriuzisa, numarul de linii si numarul
de coloane;
- constructor pentru initializarea cu un numar dat pe toate componentele
(primeste ca parametru numarul respectiv si numarul de linii si de
coloane);
- constructori pentru initializare si copiere;
- metode publice pentru citire si afisare (preferabil suprascrierea operatorilor >> si <<);
- metoda-operator public de atribuire =;
- metoda publica pentru reactualizarea numarului de linii si coloane si
initializarea componentelor cu un numar dat (primeste ca parametru
numarul respectiv, numarul liniilor si al coloanelor);
- operator []; implementarea se va face astfel incat daca a este o matrice, i si j doi intregi iar x un real, sa fie posibile constructii ca:
"cin>>a[i][j]", "cout<< x="a[i][j]">
- operatori friend: + (in doua variante: suma si matricea insasi (unar)), - (in doua variante: diferenta si opusa (unar)), * (in doua variante: produsul matricilor si inmultirea cu un scalar)
- +=, -=, *= (cu efectul cunoscut; *= se va scrie in doua variante, avand in vedere inmultirea si inmultirea cu un scalar),
- == (testarea egalitatii), != (testarea neegalitatii) <, <=, >, >= (comparare pe componente), operatorii ==, !=, <, <=, >, >= se vor scrie in trei variante, pentru a putea lucra cu operanzi matrice-matrice, real-matrice, matrice-real (in ultimele doua cazuri se va compara matricea data cu un vector de aceeasi dimensiune care are pe fiecare componenta numarul respectiv); aveti grija la operatiile care sunt comutative;
- !(daca matricea are 0 pe toate componentele, furnizeaza intregul 0, altfel furnizeaza intregul 1),
- functii "nrlinii", "nrcoloane", "nrelemente" care furnizeaza
numarul liniilor, coloanelor, respectiv nr elementelor matricii;
duminică, 6 aprilie 2008
Proiect 2
Clasa "obiect", avand:
- ca membri privati: un "void*" (adresa unei zone de memorie, alocata dinamic, continand informatia aferenta obiectului), si un "int"(dimensiunea zonei);
- o metoda de citire si una de afisare (implementarea este la latitudinea programatorului);
- operatorul friend: <(implementarea lor este la latitudinea programatorului insa se va baza pe continutul pointerului la void, nu doar pe dimensiune).
Restul metodelor necesare sunt la latitudinea pprogramatorului.
Sa se creeze o lista simplu inlantuita de "obiecte" (list se va implementa ca clasa) si sa se sorteze.
Dupa ce se sorteaza, se afiseaza (cumva) continutul clasei si cat la suta ocupa instanta respectiva din memoria totala ocupata de instantele din clasa "obiect".
duminică, 23 martie 2008
Clase polimorfice. Clase abstracte.
class A
{
virtual f1(){cout<< "f1A";}
f2(){cout<< "f2A";}
};
class B:A
{
f1(){cout<< "f1B";}
f2(){cout<< "f2B";}
f3(){cout<< "f3B";}
};
Pentru urmatoare secventa de cod programul ne va afisa f1B, f2B, f3B (ceea ce era si de asteptat, clasele sunt instantiate clar, nimic deosebit):
B b;
b.f1();
b.f2();
b.f3();
Specificatorul virtual este folositor daca lucram in felul urmator:
A* b;
b=new B;
b->f1();
b->f2();
b->f3();
In primul rand eroare la compilare: f3 nu se regaseste si in A, si cum b este declarata de tipul A compilatorul se ataca.
Output-ul va fi: f1B, f2A.
In primul rand - pot declara o variabila ca pointer la clasa de baza si s-o instantiez cu o clasa derivata. Insa asa pot apela doar metodele care exista in clasa de baza (fie ca le-am suprascris sau nu). La fel, daca functia o suprascriem cu mai multi parametri in clasa derevivata vom avea eroare la compilare. Clasa de baza trebuie mostenita public.
In al doilea rand - in momentul in care apelez o functie din b, conteaza daca aceasta a fost declarata in clasa de baza ca fiind virtuala sau nu. Daca a fost declarata virtuala, se apeleaza metoda suprascrisa din clasa derivata. Daca nu este virtuala, chiar daca este suprascrisa in clasa derivata, va fi apelata metoda din clasa de baza.
Clasele care au metode virtuale se numesc clase polimorfice.
Putem avea metode virtuale pure - metode care doar sunt declarate in clasa de baza, fara a fi implementate:
class A
{
virtual int funt()=0;
};
O clasa care contine metode virtuale pure se numeste clasa abstracta. Nu putem crea o instanta a acestei clase, trebuie neaparat sa o derivam si sa implementam metodele virtuale pure.
TEMA LABORATOR:
Sa presupunem ca avem doua produse: bond si swap.
1. Bond este caracterizat prin nume, nr de zile total, zile scurse si valoare initiala, valoare curenta.
2. Swap este caracterizat prin nume, valoare initiala, valoare datorata, indice, valoare curenta.
Valoarea curenta se calculeaza in modul urmator:
1. valoare initiala + (valoare intiala* zile scurse/nr total de zile)
2. valoare initiala + (valoare datorata * indice)
Initial, pt 1. zile scurse = 0 si pt 2. indice = 10%.
Sa se realizeze un program care sa ofere utilizatorului urmatoarele optinui:
a. introdu bond
b. introdu swap
c. ziua urmatoare
In momentul in care se alege c. se afiseaza calculeaza valoarea curenta pentru fiecare produs, se afiseaza numele si valoarea curenta pentru fiecare produs, si pt 1. se incrementeaza zile scurse cu 1 iar pt 2. indice *=0.01
C++ Stuff
char *c = new char[2];
c[5] = 4;
S-ar putea sa se atace pe la c[9]=4; sau o valoare mai mare cand isi da si el seama ca te joci cu memorie pe care nu ti-ai marcat-o ca fiind a ta.
Pentru programe mici s-ar putea sa nu prea conteze. Insa pentru programe care folosesc mai multa memorie si scrii heap-ul aiurea s-ar putea sa te trezesti cu rezultate total neasteptate care sunt foarte greu de debbug-at.
duminică, 16 martie 2008
Mostenire
http://www.codersource.net/cpp_tutorial_inheritance.html
http://www.cs.bu.edu/teaching/cpp/inheritance/intro/
http://www.cplusplus.com/doc/tutorial/inheritance.html
Mostenirea presupune sa avem o clasa de baza A pe care sa o derivam in clasa derivata B (sau mai multe clase derivate C,D,E...). Putem avea si mostenire multipla - clase de baza A si B le mostenim in clasa derivata C.
Sintaxa:
class B: A
{
...
};
Clasa B mosteneste clasa A.
class C: A,B
{...};
Clasa C mosteneste clasele A si B.
Ce inseamna mostenirea? (Vom considera exemplul mostenirii simple B este derivata din A) Clasa B va avea toati membrii clasei A, pe langa care mai putem adauga extensii specifice clasei derivate. Sa presupunem ca am implementat o clasa lista simplu inlantuita numita L1. Pentru a construi o lista dublu inlantuita este suficient sa mostenim L1 si sa mai adaugam o proprietate si o metoda pentru deplasarea la stanga.
O clasa derivata mosteneste toti membrii clasei de baza cu exceptia:
- constructorilor si destructorilor
- operatorul de atribuire
- clasele si metodele friend
Putem de asemenea apela si constructorii cu parametri:
class A{
A(int,int);
};
class B:A
{ B(int a):A(a,a);
};
Despre specificatorii de access am mai discutat in introducere. Ii mai putem aplica si la felul in care mostenim o clasa: putem mosteni clasa A privat(implicit), public si protected. Specificatorii se refera la proprietatile membrilor mosteniti din clasa de baza in clasa derivata.
Putem suprascrie metodele din clasele de baza. Este recomandat (si vom vedea laboratorul viitor de ce) ca in fata metodelor pe care le vrem suprascrise in clasa derivata sa folosim specificatorul virtual:
class A
{
...
virtual int f();
};
duminică, 9 martie 2008
Proiect 1
- membri privati pentru matricea propriuzisa, numarul de linii si numarul
de coloane;
- constructor pentru initializarea cu un numar dat pe toate componentele
(primeste ca parametru numarul respectiv si numarul de linii si de
coloane);
- constructori pentru initializare si copiere;
- metode publice pentru citire si afisare (preferabil suprascrierea operatorilor >> si <<); - metoda-operator public de atribuire =; - metoda publica pentru reactualizarea numarului de linii si coloane si initializarea componentelor cu un numar dat (primeste ca parametru numarul respectiv, numarul liniilor si al coloanelor); - operator []; implementarea se va face astfel incat daca a este o matrice, i si j doi intregi iar x un real, sa fie posibile constructii ca: "cin>>a[i][j]", "cout<< x="a[i][j]">, >= (comparare pe componente), !(daca matricea are 0 pe toate componentele, furnizeaza intregul 0, altfel furnizeaza intregul 1), operatorii ==, !=, <, <=, >, >= se vor scrie in trei variante, pentru a putea lucra cu operanzi matrice-matrice, real-matrice, matrice-real (in ultimele doua cazuri se va compara matricea data cu o matrice de aceleasi dimensiuni care are pe fiecare componenta numarul respectiv); aveti grija la operatiile care sunt comutative;
- functii "nrlinii", "nrcoloane", "nrelemente" care furnizeaza
numarul liniilor, coloanelor, respectiv nr elementelor matricii;
Operatori, constructor de copiere
class vector
{
int dimensiune;
int *elemente;
...
};
Ar fi bine ca toate metodele clasei sa fie cat mai intuitive pentru cel care o va utilzia in program. Adunarea sa se faca a+b si nu a.adunare(b), cin>>a si nu a.citeste etc.
La fel si pentru a[i] si nu a.getElement(i). Pentru asta suprascriem operatorul [].
int vector::operator [](int i)
{
return elemente[i]; //sau *(elemente+i), eventual si cu o verificare impotriva erorilor
}
Este corect definita functia de mai sus?
O alta problema care apare la clase care au membri pointeri ar fi atribuirea. Sa consideram urmatoarea bucata de cod:
vector a,b;
//initializam pe a
b=a;
Copierea se va face default de compilator - copie exact valorile din a in b. Dar elemente este o adresa, deci va copia adresa din a in b, si nu valorile de la adresa respectiva. Daca modificam valori in a.elemente si vor modifica si in b. Problema aceasta se rezolva scriind un constructor de copiere - constructor care primeste ca parametru tipul clasei careia ii apartine si/sau suprascriind operatorul =. Pentru constructor de copiere:
vector::vector(vector &a){...}
Constructorul de copiere va fi apelat in mai multe cazuri:
- daca initializam o instanta a unei clase cu un obicet deja existent (vector a(b); echivalent cu a scrie vector a=b)
- daca avem parametri de tipul cu constructor de copiere transmiri prin valoare (int ceva(vector a){..}) pentru ca se realizeaza o copie a obicetului pe stiva
NOTA: 1. Este recomandat ca operatorii de tip = sa returneze referinte, pentru a putra face atribuiri inlantuite: a=b=c=d.
2. Daca avem o instanta a unei clase care ocupa multa memorie este recomandat sa o transmitem prin referinta si nu sa-i facem inca o copie in memorie (transmiterea prin valoare).
3. Daca pentru un operator transmitem parametrii prin referinta, e bine sa folosim specificatorul const, pentru a fi siguri ca nu se modifica in cadrul functiei:
vector operator + (const vector & a,const vector &b){...}
Tema laborator: Realizati o clasa vector care sa o folosim in urmatorul main:
int main()
{
int m;
cin>>m;
vector a(m);
cin>>a;
vector b;
cin b;
vector c=a+b;
cout<< a << "+" << b << "=" << c;
cout<< a << "*" << b << "=" << a*b; //produs scalar
for(int i=0;i< m;i++)
cout << a[i]<<" ";
count<< endl;
}
NOTA: Declararea variabilelor in C++
In C era obligatoriu sa-ti declari variabilele la inceputul blocului de instructiuni. In C++ poti sa le declari oriunde, insa pentru a face codul usor de citit este recomandat sa le declarati tot la inceputul blocului.
Un caz aparte este for-ul, daca il scriem for(int i....). Variabila i este recunoscuta doar in cadrul for-ului sau si dupa ce iesim din for?
Standard-ul initial C++ spunea ca o sa fie recunoscuta in tot blocul din care face for parte.
Realitatea spune ca depinde de compilator (in versiunile mai noi de Visual va fi recunoscuta doar in cadrul for-ului, insa Linux-ul s-ar putea sa respecte standardul).
miercuri, 5 martie 2008
Clasa Rational
using namespace std;
class rational
{
private:
int numitor;
int numarator;
public:
rational();
rational(int, int);
~rational();
friend rational operator + (rational, int);
friend istream &operator >>(istream &,rational&);
friend ostream &operator <<(ostream&,rational);
};
rational::rational(int a,int b=1)
{
numitor = b;
numarator = a;
}
rational::~rational()
{
}
rational::rational()
{
numitor = 0;
numarator = 1;
}
rational operator + (rational a, int b)
{
rational rezultat;
rezultat.numarator=b*a.numitor+a.numarator;
rezultat.numitor=a.numitor;
return rezultat;
}
istream& operator >>(istream& cin,rational &a)
{
cin>>a.numarator>>a.numitor;
return cin;
}
ostream& operator <<(ostream& cout,rational a)
{
cout<< a.numarator<<"/"<< a.numitor<
}
int main()
{
rational a;
rational b(3);
rational c(3,2);
cin>>a;
cout<< a<<"+2="<<(a+2);
cout<< b<<"+2="<<(b+2);
cout<< b<<"+2="<<(c+2);
}
sâmbătă, 1 martie 2008
Stupid bug
#define True 1
int isUpdated()
{
boolean updated;
if(True == updated)
{
return 1;
{
return 0;
}
Polimorfism si suprascrierea operatorilor
int functie(int &a,int b)
{
b=a; //la iesirea din functie b va avea aceeasi valoarea, chiar daca am facut o atribuire
a=b+5; // a va avea valoarea schimbata pentru ca a fost transmis prin referinta
}
Polimorfism in C++: putem folosi acelasi nume de functie pentru a realiza mai multe actiuni - trebuie sa difere numarul parametrilor sau tipul parametrilor (cred). Daca difera doar tipul returnat, sau daca difera tipul parametrilor la modul ca intr-o parte avem int iar in alta parte double compilatorul va genera erori. Atentie la functiile cu parametri impliciti.
Functii cu parametri impliciti:
int clasa_mea::functie(int a, int b=0)
{
this->a = a;
this->b = b;
}
...
obiect.functie(5,3); //obiect.a va lua valoarea 5 iar b valoarea 3
obiect.functie(5); //daca nu specificam al doilea parametru aceasta va primi valoarea implicita specificata la implementare
Sa presupunem ca pe langa functia de mai sus definim inca una cu un singur parametru:
int clasa_mea::functie(int a)
{
this->a = a;
this->b = 500;
}
In momentul in care apelam obiect.functie(5) programul nu va sti care dintre cele doua implementari trebuie sa o apeleze => bad polymorphism.
Operatorii din C/C++ sunt functii deci pot si suprascrisi:
class clasa_mea
{
...
clasa_mea operator +(alta_clasa b)
{
//operatii smechere scrise inline din lene
}
};
Operatorul + cu un singur operand? Si cum il apelam? Restul metodelor le apelam obiect.functie(); deci pentru functie() aveam o structura de date cu care lucram in cadrul ei, chiar daca nu are parametri - instanta care apeleaza operatorul. Deci operatorul + de mai sus are doi parametri: unul de tip clasa_mea, cel care apeleaza functia/operatorul si unul de tip alta_clasa.
Operatorul il apelam cum am apela orice alt operator:
clasa_mea a;
alta_clasa b;
clasa_mea c=a+b;
Dar 1. daca respectam incapsularea, membrii variabile vor fi privati 2. cum fac pentru comutativitate? Daca scriem ca mai sus primul parametru va fi intotdeauna de tipul clasa_mea; daca vreau sa fac alta_clasa+clasa_mea. Daca alta clasa este definita de mine nu voi avea acces la membrii privati din clasa_mea. Daca alta_clasa este un tip din C++ cum fac?
Putem scrie o functie care nu face parte din nici o clasa, in felul acesta putem specifica ce ordine vrem pentru operatori:
clasa_mea operator+(clasa_mea a, alta_clasa b){...}
Insa si asa vom avea probleme cu membrii privati. Pentru asta folosim specificatorul friend:
class clasa_mea
{
...
friend clasa_mea operator +(clasa_mea a,alta_clasa b)
{
//operatii smechere scrise inline din lene
}
};
Acesta ii spune clasei ca operatorul + nu face parte din clasa_mea, insa ii poate accesa membrii privati. Poate fi folosit pentru orice functii, nu neaparat pentru operatori (cred ca merge si pentru membri ai altor clase - daca vrei sa faceti programe ciudate).
Cand suprascriem operatori trebuie sa respectam numarul parametrilor.
cin si cout (de fapt >> si <<) sunt operatori (deja suprascrisi chiar, ca pot fi folositi si la shiftarea pe biti) deci pot fi suprascrisi. Sintaxa lor standard este cam asa:
istream& operator >> (istream& cin, int &a){...}
ostream& operator << (ostream& cout, int a){...}
Ar trebui sa returneze ceva?
vineri, 29 februarie 2008
Introducere
class numar
{
private:
int a;
public:
numar(); //constructor, are acelasi nume cu clasa, se apeleaza cand
//instantiem un obiect de tipul numar
numar(int); //constructor cu un parametru
~numar(); //destructor, se apeleaza fie cand se incheiete executia
//si toate variabilele de pe stiva sunt distruse,
//fie cand eliberam memoria, daca a fost alocat dinamic
int geta();
int seta(int);
};
Pana acum doar am declarat clasa, urmeaza s-o implementam. Se recomanda implementarea in cadrul declararii clasei doar a functiilor scurte (functii inline) - ruleaza mai rapid dar ocupa spatiu de fiecare data cand instantiem un obiect de tipul clasei.
Putem avea oricati constructori, cu conditia sa difere numarul parametrilor (sau tipul lor, daca nu sunt tipuri similare, gen int - double). Constructorul cu parametri il putem aplea in mod urmator:
numar a(1);
sau
numar *a = new numar(1);
Implementarea metodelor:
numar::numar(){...}
numar::numar(int a){...}
numar::~numar(){...}
Sintaxa pentru cosntructor si destructor. Destructorul nu primeste nici un parametru niciodata. Operatorul :: specifica clasa careia ii apartine metoda pe care o implementam.
int numar::seta(int a)
{
return this->a = a;
}
Ce se intampla daca unul dintre parametri are acelasi nume cu un membru al clasei? Parametrul va fi mai sus in stiva decat membrul clasei, deci in interiorul functiei variabila a va desemna parametrul si nu membrul clasei. Pentru a avea acces la membru folosim pointerul this. Orice clasa are un pointer implicit catre ea insasi (recomandat de folosit pentru a evita confuziile).
Specificatoru: private, public, protected.
private - membrii privati pot fi accesati doar de membri ai clasei;
public - membrii publici pot fi accesati de orice metoda a programului;
protected - membrii protected pot fi accesati doar de membrii clasei si clasei ce o mosteneste.