Download as pdf or txt
Download as pdf or txt
You are on page 1of 18

Clase si obiecte

review of C users defined types: struct


mecanisme de lucru cu structuri: functii de setup/modificare/afisare/etc. a unei variabile (obiect)
definirea de catre utilizator de noi tipuri in C++: clase
declararea si definirea claselor: date + functionalitate la un loc (data + behavior) => modularitate
instantierea unei clase: obiecte (variabile)
structura unei clase: membrii clasei
incapsulare
abstractizare

Problema: modelarea (reprezentarea) unui vector geometric


Varianta 1: Lucram direct cu cele patru valori (coordonatele puctelor de start si end ale vectorului) :
#include <iostream>
using namespace std;
void main ()
{
//...
int xStart = 1;
int yStart = 2;
int xEnd = 5;
int yEnd = 8;
cout << "\nVector: ";
cout << "(" << xStart << ", " << yStart << ") --> ";
cout << "(" << xEnd << ", " << yEnd << ")" << endl;
//...
}

O varianta mai buna: Implementam functii pentru diverse operatii asupra coordonatelor vectorului
(afisare, etc.);
#include <iostream>
using namespace std;
void print_Vector (int xS, int yS, int xE, int yE)
{
cout << "\nVector: ";
cout << "(" << xS << ", " << yS << ") --> ";
cout << "(" << xE << ", " << yE << ")" << endl;
}
void main () {
{
//...
int xStart = 1;
int yStart = 2;
int xEnd = 5;
int yEnd = 8;
//...
print_Vector (xStart, yStart,
//...
print_Vector (3, 8, 7, 1);
//...
}

xEnd, yEnd);

Adaugam functionalitate noua asupra vectorului: deplasarea unui vectorului cu un offset:


void move_Vector (int &xS, int &yS, int &xE, int &yE,
int offset_xS, int offset_yS, int offset_xE, int offset_yE)
{
cout << "\nDeplasam vector cu un offset...";
xS += offset_xS;
yS += offset_yS;
xE += offset_xE;
yE += offset_yE;
}
void main ()
{
//...
int xStart = 1;
int yStart = 2;
int xEnd = 5;
int yEnd = 8;
//...
print_Vector (xStart, yStart,

xEnd, yEnd);

//...
move_Vector (xStart, yStart, xEnd, yEnd, 2, 5, -1, 7);
cout << "\nNoua pozitie a vectorului: ";
print_Vector (xStart, yStart, xEnd, yEnd);
//...
}

Initializarea unui vector (initializam/modificam coordonatele sale):


void set_Vector (int &xS, int &yS, int &xE, int &yE,
int val_xS, int val_yS, int val_xE, int val_yE)
{
cout << "\nInitializam vector...";
xS = val_xS;
yS = val_yS;
xE = val_xE;
yE = val_yE;
}

Varianta 2: Utilizam o structura (struct) pentru reprezentarea vectorului:


struct Vector {
int xStart;
int yStart;
int xEnd;
int yEnd;
};
void print_Vector (Vector V)
{
cout << "\nVector: ";
cout << "(" << V.xStart << ", " << V.yStart << ") --> ";
cout << "(" << V.xEnd << ", " << V.yEnd << ")" << endl;
}
void move_Vector (Vector &V, int offset_xS, int offset_yS, int offset_xE, int offset_yE)
{
cout << "\nDeplasam vector cu un offset...";
V.xStart += offset_xS;
V.xStart += offset_yS;
V.xEnd += offset_xE;
V.yEnd += offset_yE;
}
void main ()
{
//...
Vector V = {1, 2, 5, 8};
//...
print_Vector (V);
//...
move_Vector (V, 2, 5, -1, 7);
cout << "\nNoua pozitie a vectorului: ";
print_Vector (V);
//...
}

Not: utilizarea referintei: optimizare !!


void print_Vector (Vector &V)
{
cout << "\nVector: ";
cout << "(" << V.xStart << ", " << V.yStart << ") --> ";
cout << "(" << V.xEnd << ", " << V.yEnd << ")" << endl;
}

Sau, si mai bine in acest caz: referinta constanta.... optimizare + protectie + lizibilitate !!
void print_Vector (const Vector &V)
{
cout << "\nVector: ";
cout << "(" << V.xStart << ", " << V.yStart << ") --> ";
cout << "(" << V.xEnd << ", " << V.yEnd << ")" << endl;
}

Varianta 3: Putem incerca sa abstractiza (si modulariza/layeriza) putin problema: ne imaginam


vectorul ca fiind format din 2 puncte (in loc de 4 coordonate separate).
- In acest sens, introducem o structura noua Point pentru reprezentarea/modelarea unui
punct:
struct Point {
int x;
int y;
};
struct Vector {
Point Start;
Point End;
};
void print_Vector (const Vector &V)
{
cout << "\nVector: ";
cout << "(" << V.Start.x << ", " << V.Start.y << ")";
cout << " --> ";
cout << "(" << V.End.x << ", " << V.End.y << ")";
}
void main ()
{
//...
Vector V = {{1, 2}, {5, 8}}; // declaram si initializam vectorul V
//...
print_Vector (V); // "desenam" vectorul V
//...
Vector V2 = {-2, 3, 1, 7}; // declaram si initializam vectorul V2
print_Vector (V2); // "desenam" vectorul V2
//...
}

void set_Vector (Vector &Vect, int xStart, int yStart,


{
cout << "\nInitializam vector...";
Vect.Start.x = xStart;
Vect.Start.y = yStart;
Vect.End.x = xEnd;
Vect.End.y = yEnd;
}

int xEnd, int yEnd)

void main ()
{
//...
Vector V = {{1, 2}, {5, 8}}; // declaram si initializam vectorul V
//...
print_Vector (V); // "desenam" vectorul V
//...
set_Vector (V, -2, 3, 1, 7);
print_Vector (V); // "desenam" din nou vectorul V
//...
}

Putem obtine acum mai multe variante de lucru cu vectorul:


void set_Vector (Vector &Vect, int xStart, int yStart,
{
cout << "\nInitializam vector...";
Vect.Start.x = xStart;
Vect.Start.y = yStart;
Vect.End.x = xEnd;
Vect.End.y = yEnd;
}

int xEnd, int yEnd)

void set_Vector (Vector &Vect, const Point &pStart, const Point &pEnd)
{
cout << "\nInitializam vector...";
Vect.Start.x = pStart.x;
Vect.Start.y = pStart.y;
Vect.End.x = pEnd.x;
Vect.End.y = pEnd.y;
}
void print_Vector (const Vector &Vect)
{
cout << "\nVector: ";
cout << "(" << Vect.Start.x << ", " << Vect.Start.y << ")";
cout << " --> ";
cout << "(" << Vect.End.x << ", " << Vect.End.y << ")";
}
void main ()
{
//...
Vector V = {{1, 2}, {5, 8}}; // declaram si initializam vectorul V
//...
print_Vector (V); // "desenam" vectorul V
//...
set_Vector (V, -2, 3, 1, 7);
print_Vector (V); // "desenam" din nou vectorul V
//...
Point P1 = {1,2}, P2 = {-1, 18}; // declaram si intializam direct 2 Puncte
set_Vector (V, P1, P2); // initializam vectorul V
print_Vector (V); // "redesenam" vectorul
}

Modularizarea ne poate ajuta si mai mult: in sensul ca fiecare functie se ocupa de entitatea sa.
//*************************************************************************/
void set_Vector (Vector &Vect, int xStart, int yStart, int xEnd, int yEnd);
void set_Vector (Vector &Vect, const Point &pStart, const Point &pEnd);
void print_Vector (const Vector &Vect);
void set_Point (Point &P, int x, int y);
void print_Point (const Point& P);
void main ()
{
//...
Vector V = {{1, 2}, {5, 8}}; // declaram si initializam vectorul V
//...
print_Vector (V); // "desenam" vectorul V
//...
set_Vector (V, -2, 3, 1, 7);
print_Vector (V); // "desenam" din nou vectorul V
//...
Point P1 = {1,2}, P2 = {-1, 18}; // declaram si intializam direct 2 Puncte
set_Vector (V, P1, P2); // initializam vectorul V
print_Vector (V); // "redesenam" vectorul
}
//*************************************************************************/
void set_Vector (Vector &Vect, int xStart, int yStart, int xEnd, int yEnd)
{
cout << "\nInitializam vector...";
set_Point (Vect.Start, xStart, yStart);
set_Point (Vect.End, xEnd, yEnd);
}
void set_Vector (Vector &Vect, const Point &pStart, const Point &pEnd)
{
cout << "\nInitializam vector...";
set_Point (Vect.Start, pStart.x, pStart.y);
set_Point (Vect.End, pEnd.x, pEnd.y);
}
void print_Vector (const Vector &Vect)
{
cout << "\nVector: ";
print_Point (Vect.Start);
cout << " --> ";
print_Point (Vect.End);
}
//*************************************************************************/
void set_Point (Point &P, int x, int y)
{
cout << "\nInitializare punct cu coordonate noi: " << x << ", " << y << "...";
P.x = x;
P.y = y;
}
void print_Point (const Point& P)
{
cout << "(" << P.x << ", " << P.y << ")";
}
//*************************************************************************/

Cateva concluzii:
- Structurile ne ajuta pentru a putea modela diverse entitati
- Se poate lucra modular: modificarile de functionalitate (comportament) sau de structura
(date) se fac in puncte clare
- [Utilizarea referintelor la structuri aduce avantataje]
In general, o entitate are: structur (date) + comportament (functionalitate) !!
Problema:
- Datele sunt separate de comportament.
- Fiecare functie de lucru cu o entitate (comportament) nu apartine acelei entitati.
Lucreaza de la distanta cu structura (datele) entitatii.
- Solutia C++ (OOP): utilizarea claselor !!

Varianta 4: Declararea si implementarea clasei Point


class Point {
int x;
int y;
public:
void set_Point (int a, int b) {
cout << "\nInitializare punct cu coordonate noi: " << a << ", " << b << "...";
x = a;
y = b;
}
void print_Point () {
cout << "(" << x << ", " << y << ")";
}
int get_x() const {return x;}
int get_y() const {return y;}
};
void main ()
{
Point P1, P2;
P1.set_Point (1, 2);
P2.set_Point (-1, 18);
cout << "\n";
P1.print_Point();
P2.print_Point();
}

// declaram 2 Puncte
// init P1
// init P2

Declaratia si implementarea (definitia) clasei Vector:


/* Declaratia clasei */
class Vector {
Point Start;
Point End;
public:
void set_Vector (int xStart, int yStart, int xEnd, int yEnd);
void set_Vector (const Point &pStart, const Point &pEnd);
void print_Vector ();
};
/* Implementarea (definitia) clasei => obs: este separata de declaratia clasei */
void Vector::set_Vector (int xStart, int yStart, int xEnd, int yEnd)
{
cout << "\nInitializam vector...";
Start.set_Point (xStart, yStart);
End.set_Point (xEnd, yEnd);
}
void Vector::set_Vector (const Point &pStart, const Point &pEnd)
{
cout << "\nInitializam vector...";
Start.set_Point ( pStart.get_x(), pStart.get_y() );
End.set_Point ( pEnd.get_x(), pEnd.get_y() );
}
void Vector::print_Vector ()
{
cout << "\nVector: ";
Start.print_Point ();
cout << " --> ";
End.print_Point ();
}

void main ()
{
//...
Vector V;
V.set_Vector (1, 2, 5, 8);
//...
V.print_Vector ();
//...
V.set_Vector (-2, 3, 1, 7);
V.print_Vector ();
//...

// declaram vectorul
// initailizam vectorul
// "desenam" vectorul V
// "desenam" din nou vectorul V

Point P1, P2;


P1.set_Point (1, 2);
P2.set_Point (-1, 18);

// declaram 2 Puncte

V.set_Vector (P1, P2);


V.print_Vector ();

// initializam vectorul V pe baza punctelor P1 si P2


// "redesenam" vectorul

- Clasa: tip nou definit in cadrul unui program (user-defined datatype) care grupeaza
impreuna mai multe informatii => similiare cu structurile
- Numele clasei => numele noului tip definit
- Membrii clasei => datele clasei, campurile clasei (structura de date a clasei) + functiile
clasei (comportamentul clasei)
- O clasa in general modeleaza (gestioneaza) o entitate.
- Fiecare entitate are in general:
o O anumita structur de date si
o Un anumit comportament.
Exemplu de aplicatie: managementul informatiilor privind situatia studentilor in ATM:
gestiunea studentilor (militari, civili), situatia scolara, situatia militara (numai pentru
studentii militari), grupe de studenti, examene, note, medii, etc., elementele logistice
(locatia in camin, gestiunea meselor, gestiunea echipamentului militar, etc.), orarul,
materiile, etc.
Putem identifica o serie de entitati: Student, Student_civil, Student_militar, Grupa,
Nota, Colectie_note, Echipament, Materie, Colectie_materii, Orar, etc.
- Variabile in cadrul programului: obiecte (instante ale clasei).
- Datele membre ale unei clase: pot fi de mai multe tipuri:
class Student
public:
int
char
float

id;
nume [256];
medie;

//...
};

- Putem avea 0, 1 sau mai multe instante ale unei clase (locale, globale, parametrii)
- Fiecare instanta are spatiul ei de memorie si setul ei propriu de date (ex: id, nume, medie)

Putem lucra cu instantele unei clase in diverse forme:


void main ()
{
Student S1;
// Instanta S1 a clasei student
Student *S2 = new Student; /* Declaratia unui pointer la Student si
initializarea sa cu o instanta a unui
student alocat in mem heap */
Student &S3 = S1;
Student &S4 = *S2;
Student *S5;

// Referinta la studentul S1
// Referinta la studentul catre care pointeaza S2
/* Declaratia unui pointer catre un obiect Student;
Atentie: nu este alocat inca obiectul Student */

//...
S1.id = 100;
S1.medie = 9.14;
strcpy (S1.nume, "Popescu Ionel");
S1.id = 101;
strcpy (S1.nume, "Popescu Ionel");
S1.medie = 9.14;
S2->id = 102;
strcpy (S2->nume, "Vasile Mihai");
S2->medie = 8.21;
S3.medie = 9.52;
S4.medie = 9.01;
cout << S1.nume << ": " << S1.medie;
cout << S2->nume << ": " << S2->medie;
S5->id = 103;
/* crash !!! */
S5->medie = 5.25;
/* crash !!! */
strcpy (S5->nume, "Ionescu Marian"); /* crash !!! */
//...
}

- Obs: fiecare din obiectele S1, (*S2), (*S3) (daca exista undeva S3 = new Student;) vor
avea spatiul de memorie si datele proprii.

Adaugam metode de lucru cu datele membre (functionalitate):


class Student {
private:
int
id;
char nume[256];
float medie;
//...
public:
void print ();
void setId (int i);
void setNume (char *n);
void setMedie (float m);

//
//
//
//

metoda
metoda
metoda
metoda

a
a
a
a

void update (int i, char *n, float m);

clasei
clasei
clasei
clasei
// metoda a clasei

//...
};
void Student::setId (int i) {
id = i;
}
void Student::setNume (char *n) {
strcpy (nume, n);
}
void Student::setMedie (float m) {
medie = m;
}
void Student::update (int i, char *n, float m) {
setId (i);
setNume (n);
setMedie (m);
}
void Student::print () {
cout << "\nStudent: " << id << " " << nume << " " << medie;
}
void main ()
{
Student S1;
// instanta S1 a clasei student
Student *S2 = new Student; /* declaratia unui pointer la Student si initializarea sa
cu o instanta a unui student alocat in mem heap */
Student &S3 = S1;
// referinta la studentul S1
Student &S4 = *S2;
// referinta la studentul catre care pointeaza S2 */
Student *S5;

// declaratia unui pointer; atentie: nu este inca alocat */

//...
S1.setId (101);
S1.setNume ("Popescu Ionel");
S1.setMedie (9.14);
S2->setId (102);
S2->setNume ("Vasile Mihai");
S2->setMedie (8.21);
S3.setMedie (9.52);
S4.setMedie (9.01);

S1.print ();
S2->print ();
S5 = new Student;
S5->setId (103);

// alocam un student nou in heap (S5 adreseaza spatiul de memorie)

S5->setMedie (5.25);
S5->setNume ("Ionescu Marian");
S5->print();
}

Daca modificam structura clasei:


class Student {
private:
int
id;
char *nume;
float medie;
//...
public:
void print ();
void setId (int i);
void setNume (char *n);
void setMedie (float m);
void update (int i, char *n, float m);
};

Se va modifica doar implementarea functiei membre setNume:


void Student::setNume (char *n) {
nume = new char [strlen (n) + 1];
strcpy (nume, n);
}

Incapsularea (ascunderea) datelor in cadrul clasei.


Functiile membre sunt foarte apropiate de datele mebmbre ale clasei.
Accesul la datele clasei se face doar prin intermediul metodelor clasei.
Orice modificare in burta clasei va fi ascunsa pentru exteriorul clasei.

- Recomandarea (viziunea OOP):


o pastrarea structurii claselor cat mai ascunsa
o expunerea in exterior a functionalitatilor claselor prin metode publice
- Metode:
o Functii membre ale unei clase (apartin unei clase).
o La apel primesc in mod automat (implict, transaparent) un parametru: adresa
obiectului care apeleaza metoda.
o Sunt ca niste butoane la nivelul unei clase

Cerin: modelarea unor operatii cu vectori geometrici: implementarea adunarii a doi vectori.
#include <iostream>
using namespace std;
/******************************************************************************/
class Point { /* Declaratia clasei Point */
int x;
int y;
public:
void set(int a, int b) { /* functie (metoda) inline */
cout << "\nInitializare punct cu coordonate noi: " << a << ", " << b << "...";
x = a;
y = b;
}
void
void

print();
move (int off_x, int off_y);

int
int

getx() const {return x;}


gety() const {return y;}

};
/* Implementarea (definitia) clasei Point */
void Point::move (int off_x, int off_y) {
this->x = this->x + off_x;
this->y = this->y + off_y;
}
void Point::print() {
cout << "(" << x << ", " << y << ")";
}
/******************************************************************************/
class Vector { /* Declaratia clasei Vector */
char nume[32];
Point start;
Point end;
void
public:
void
void
void
Vector&

/* numele vectorului */
/* punctul de start al vectorului (originea) */
/* punctul de final al vectorului (destinatia) */

align_to (Vector &V);


set (const char *nume, int xs, int ys, int xe, int ye);
print ();
move (int off_xs, int off_ys, int off_xe, int off_ye);
add (Vector &V);

};
/* Implementarea (definitia) clasei Vector */
void Vector::set(const char *nume, int xs, int ys,

int xe, int ye) {

cout << "\nInitializam vectorul '" << nume << "'...";


strncpy (this->nume, nume, sizeof(this->nume));
start.set (xs, ys);
end.set (xe, ye);
}

void Vector::print() {
cout << "\nDesenam vectorul '" << nume << "': ";
start.print ();
cout << " --> ";
end.print ();
}
void Vector::move (int off_xs, int off_ys, int off_xe, int off_ye) {
start.move(off_xs, off_ys);
end.move(off_xe, off_ye);
}
void Vector::align_to (Vector &V) {
this->move (0, V.start.gety() - this->start.gety(),
0, V.start.gety() - this->start.gety());
this->move (V.start.getx() - this->start.getx(), 0,
V.start.getx() - this->start.getx(), 0);
}
Vector& Vector::add (Vector &V)
{
Vector V1 = *this;
Vector V2 = V;
Vector *V3 = new Vector; // vectorul rezultat(metoda intoarce referinta catre el)
char nume[32];
sprintf (nume, "%s+%s", V1.nume, V2.nume);
V2.align_to (V1);
V3->set (nume, V1.start.getx(), V1.start.gety(),
V1.end.getx() + V2.end.getx() - V2.start.getx(),
V1.end.gety() + V2.end.gety() - V2.start.gety());
return (*V3);
}
/******************************************************************************/
void main ()
{
//...
Vector V1, V2;
V1.set ("V1", 1, 2,
V2.set ("V2", 4, 1,

// declaram vectorii
2, 4); // initializam vectorul V1
5, 5); // initializam vectorul V2

cout << endl;


V1.print ();
V2.print ();
cout << endl;
Vector &V3 = V2.add (V1);
V3.print ();

// adunam V2 + V1 => V3
// desenam noul vector "V2+V1"

cout << endl;


Vector &V4 = V1.add (V2);
V4.print ();

// adunam V1 + V2 => V4
// desenam noul vector "V1+V2"

cout << "\n";


}

Cateva observatii:
- Pointerul this
- Operatorul de scop (scope access operator) ::
- Clasa Vector foloseste membrii clasei Point
- Metoda Vector::add (...) intoarce referinta catre un obiect. Atentie, este alocat
dinamic in heap. Q: cum facem putem delete ?
- Accesul la membrii non-public ai claselor se poate face numai prin metode de
acces publice. Exemplu in clasa Point::getx ( ) si Point::gety ( )

- Incapsulare !!
- ....

You might also like