Professional Documents
Culture Documents
Obiective:
struct vs. class
Membrii statici într-o clasă
Constructori și destructori de tip private.
Exemplu de utilizare: implementarea unui Singleton (pattern de programare)
Funcții și clase friend
Funcții inline
1
Mihai TOGAN
struct vs. class (ȋn C++)
2
Mihai TOGAN
Declaraţie pentru tipul Point folosind o construcţie de tip struct:
/*****************************************************************************/
struct Point { /* Declaratia tipului Point (am folosit struct) */
//...
void set(int a, int b);
void print();
void move (int off_x, int off_y);
int getx() const {return x;}
int gety() const {return y;}
};
Point::Point ()
{
cout << "\nConstructor implicit in clasa Point ";
x = 0; y = 0;
}
//...
/*****************************************************************************/
struct Vector { /* Declaratia tipului Vector (am folosit struct) */
private:
char *nume; /* membru private */
Point start; /* membru private */
Point end; /* membru private */
public:
Vector ();
Vector (const char *nume, int xs, int ys, int xe, int ye);
Vector (const char *nume, const Point& start, const Point& end);
Vector (const Vector &V); /* declaratia pentru constructorul de copiere
*/
~Vector ();
void set (const char *nume, int xs, int ys, int xe, int ye);
void print ();
//...
};
//...
/*****************************************************************************/
void main () {
Vector V;
Point P (2, 3);
//...
}
/*****************************************************************************/
3
Mihai TOGAN
Membrii statici într-o clasă
//...
public:
static int counter; /* var membra statica */
};
/*****************************************************************************/
int Get_ActiveVectorInstances ()
{
cout << "\nNumarul de instante (obiecte) active ale clasei Vector: "
cout << Vector::counter;
return Vector::counter;
}
int Vector::counter;
/*****************************************************************************/
void main ()
{
Vector V1 ("V1", 1, 2, 3, 4);
Vector V2 = V1;
Vector *V3 = new Vector ();
Get_ActiveVectorInstances ();
//...
delete V3;
Get_ActiveVectorInstances ();
//...
}
/*****************************************************************************/
4
Mihai TOGAN
Observaţii:
O variabilă membră statică nu aparţine nici unui obiect (aceasta aparţine clasei).
Chiar dacă nu există obiecte instanţiate, variabila membru statică există alocată.
Accesibilitatea se face folosind numele clasei și access-scope-operatorul.
Este ca o variabilă globală însă este accesibilă doar prin intermediul clasei.
Ca orice variabila membru, poate fi public sau private.
Este obligatoriu să fie definită (opţional și iniţializată) ȋn afara clasei. Exemplu:
int Vector::counter = 0;
int Vector::getCounter ()
{
return counter;
}
int Get_ActiveVectorInstances ()
{
cout << "\nNumarul de instante (obiecte) active ale clasei Vector: ";
cout << Vector::getCounter();
return Vector::getCounter();
}
/******************************************************************************/
Observaţii:
Apelul unei metode statice se face folosind numele clasei și access-scope-operatorul.
Practic este ca o funcție standalone insa accesibila doar prin intermediul clasei.
Ca orice metoda, poate fi public sau private.
O metodă statică aparţine clasei și nu trebuie gândită ca acţionând asupra datelor unui
obiect specific.
Nu poate accesa date ale clasei care nu sunt statice.
Se poate apela și printr-un obiect V2.getCounter();
De regulă, metodele statice sunt cele care nu au nevoie de datele interne ale unui obiect.
5
Mihai TOGAN
Constructori și destructori de tip private
class Singleton {
public:
static Singleton& GetInstance ();
int GetVal () { return val; }
//...
private:
/* constructor private */
Singleton() : val(5) {
cout << "\nConstructor...";
//...
}
int val;
//...
static Singleton *mpInstance;
};
/******************************************************************************
/
Singleton* Singleton::mpInstance = NULL;
Singleton& Singleton::GetInstance()
{
if (mpInstance == NULL)
mpInstance = new Singleton;
return *mpInstance;
}
/******************************************************************************
/
void main ()
{
// Singleton X; /* eroare (de compilare) */
// Signleton* Y = new Singleton /* eroare (de compilare) */
Singleton X;
Signleton* Y = new Singleton
6
Mihai TOGAN
Pornind de la exemplul de mai sus, putem construi totuşi obiecte folosind mecanismul de
copiere:
void main ()
{
Singleton Z = Singleton::GetInstance(); /* Merge, insa nu e ok (!)*/
/*
Problema apare intrucat constructorul de copiere implicit este public
*/
cout << "Z.val = "<< Z.GetVal();
}
class Singleton {
public:
static Singleton& GetInstance ();
//...
private:
Singleton(int v = 5) : val(v) { /* constructor private */
cout << "\nConstructor...";
}
int val;
//...
static Singleton *mpInstance;
};
/*************************************************************************/
Singleton* Singleton::mpInstance = NULL;
Singleton& Singleton::GetInstance()
{
if (mpInstance == NULL)
mpInstance = new Singleton;
return *mpInstance;
}
void main ()
{
Singleton Z = Singleton::GetInstance(); /* Eroare de compilare */
}
/************************************************************************/
7
Mihai TOGAN
Completăm şi mai mult exemplul:
/*****************************************************************************/
class Singleton {
public:
static Singleton& GetInstance ();
static Singleton* GetInstancePtr (int v);
int GetVal () { return val; }
//...
private:
Singleton(int v = 5) : val(v) { /* const. private */
cout << "\nConstructor...";
}
int val;
//...
static Singleton *mpInstance;
};
/******************************************************************************/
Singleton* Singleton::mpInstance = NULL;
Singleton& Singleton::GetInstance()
{
if (mpInstance == NULL)
mpInstance = new Singleton;
return *mpInstance;
}
Singleton* Singleton::GetInstancePtr(int v)
{
if (mpInstance == NULL)
mpInstance = new Singleton (v); /* atentie, aici:putem face new */
else
mpInstance->val = v;
return mpInstance;
}
/******************************************************************************/
void main ()
{
Singleton &Z = Singleton::GetInstance();
cout << "\n Z.val = "<< Z.GetVal(); /* afiseaza Z.val = 5 */
/******************************************************************************/
8
Mihai TOGAN
Întrebare: cum putem distruge instanța creată ?
void main ()
{
Singleton &Z = Singleton::GetInstance(); /* OK */
cout << "\n Z.val = "<< Z.GetVal(); /* afiseaza Z.val = 5 */
Observaţie: designul clasei nu este suficient de bun, permite build-uri generatoare de erori la
runtime. Dacă am proiectat clasa astfel încât construcţia instanţei unice să fie realizată într-
un mod controlat, la fel trebuie procedat și la distrugerea acelei instanţe.
/********************************************************************/
class Singleton {
public:
static Singleton& GetInstance ();
static Singleton* GetInstancePtr (int v);
private:
Singleton(int v = 5) : val(v) {}
Singleton(const Singleton &S) : val(S.val) {}
int val;
//...
static Singleton *mpInstance;
};
//...
void Singleton::DestroyInstance ()
{
if (mpInstance == NULL)
return;
delete mpInstance;
mpInstance = NULL;
}
/********************************************************************/
9
Mihai TOGAN
void main ()
{
// Singleton X; /* eroare (de compilare) */
// Signleton* Y = new Singleton /* eroare (de compilare) */
/********************************************************************/
10
Mihai TOGAN
Funcții și clase friend
Mecanism care poate fi folosit pentru a facilita accesul la datele și funcțiile membre
private ale unei clase.
Mecanism nerecomandat, încalcă principiul OOP al încapsulării.
class Point {
int x;
int y;
public:
//...
int getx() const {return x;}
int gety() const {return y;}
Acum ȋn clasa Vector putem accesa direct datele membre private ale clasei Point:
Vector::Vector (const char *nume, const Point& start, const Point& end)
{
cout << "\nInitializam vectorul '" << nume << "'...";
this->set (nume, start.x, start.y, end.x, end.y);
}
Observaţie: relaţia de tip friend nu este comutativă. Dacă Point este ȋn relaţie friend cu
Vector, nu înseamnă că implicit și Vector este ȋn relaţie friend cu Point.
Putem face o clasă de tip friend doar cu o singură funcție a unei clase sau cu o funcție
standalone.
class Vector {
//...
public:
11
Mihai TOGAN
Funcții inline
Apelul se înlocuie cu codul obiect al funcției.
Observaţie: este recomandat ca funcţiile inline să fie foarte scurte (creşte codul obiect al
programului).
12