Sunteți pe pagina 1din 52

PROGRAMAREA

CALCULATOARELOR 2

Modul 2
1
Curs 5
Argumente cu valori implicite

 Metodele membre pot avea argumente cu valori implicite,


cu respectarea aceloraşi reguli :
 aceste argumente trebuie să apară în coada listei de
parametri
 expresiile de iniţializare trebuie să poată fi convertite la
tipul argumentului

2
class Point
{
int x,y;
public :
Point(int a=0, int b=0) {
x=a; y=b;
}
};

Point p1; // echivalent cu Point(0,0);
Point p2(10); // echivalent cu Point(10,0);
Point p3(10,10);
3
Liste de iniţializare
 Iniţializarea datelor membre se poate face:
 în corpul constructorilor (prin atribuiri)
 în liste de iniţializare ce apar între antetul
constructorului şi corpul acestuia :

Point::Point(int a, int b) : x(a), y(b)


{
// corp constructor
}

 În acest caz iniţializarea se face înainte de execuţia


corpului constructorului
4
Referinţe ca şi date membre

 Declaraţia acestora se face în mod obişnuit :


class Point {
int x,y;
int &ref_a;

};

 Iniţializarea acestor referinţe se poate face însă numai


prin liste de iniţializare :

Point::Point(const int a, int b, int c) : ref_a(a)


{
x=b;
y=c;
… // corp constructor 5

}
Membri constanţi

 Datele membre pot fi declarate constante utilizând


modificatorul const astfel:

class Point {
const int x,y;

};

 Aceste date membre pot fi iniţializate numai în


constructor, printr-o listă de iniţializare
 Nici o altă metodă nu mai poate modifica aceste date
membre 6
 Metodele unei clase pot fi definite ca metode constante
pentru a specifica faptul că aceste metode pot fi accesate
de obiecte constante:

class Point {
const int x,y;
public :
Point(int a, int b) : x(a), y(b){;}
void print1(void) const;
void print2(void);
};

void Point::print1(void) const {


cout << "\n Abscisa (const) : " << x;
cout << "\n Ordonata (const) : " << y;
} 7
void Point::print2(void) {
cout << "\n Abscisa : " << x;
cout << "\n Ordonata : " << y;
}

int main(void)
{
const Point pct(5,1);
pct.print1( );
//pct.print2( );
}

 La compilare, în funcţia main( ) se va genera cel puţin un


avertisment legat de metoda print2( ) apelată pentru un
obiect constant, iar la executie o eroare:
 error C2662: 'Point::print2' : cannot convert 'this' pointer from
'const Point' to 'Point &' 8
EXEMPLU CONST CU FIȘIER ANTET
// Fișierul header hPoint.h:
class Point {
const int x,y;
public :
Point(int a, int b) : x(a), y(b){;}
void print1(void) const;
void print2(void);
};//Point class

9
// Codul sursă App_Point.cpp
#include <iostream>
using namespace std;
#include "hPoint.h"

void Point::print1(void) const {


cout << "\n Abscisa (const) : " << x;
cout << "\n Ordonata (const): " << y;
}
void Point::print2(void) {
cout << "\n Abscisa : " << x;
cout << "\n Ordonata : " << y;
}
void main(void){
const Point pct(5,1); //const Point
pct.print1( ); 10
//pct.print2( );
}
Obiecte ca şi date membre
 Datele membre pot fi obiecte ale unei alte clase :

class Point {
private :
int x, y;
public:
Point( ) {x=0; y=0;}
Point(int a, int b) {x=a; y=b;}
};
class Rectangle {
Point topLeft;
Point botRight;
public:
Rectangle(int, int, int, int); 11

};
 Constructorul clasei Rectangle trebuie să facă iniţializarea
obiectelor de tipul Point prin intermediul unei liste de
iniţializare:

Rectangle::Rectangle(int left, int top, int right, int bottom):


topLeft(left, top), botRight(right, bottom)
{
// corp constructor
}

12
Tablouri de obiecte

 Pentru tipurile definite de utilizator se pot defini tablouri


similar cu definirea tablourilor pentru tipurile predefinite:
Point patrat[4];

 În acest caz avem un constructor implicit vid sau trebuie


să existe un constructor explicit fără parametri (sau cu toți
parametrii impliciți în unele medii de programare) în clasa
Point, ce va fi apelat pentru fiecare element din tablou
 De asemenea, începând cu C++1y, se poate păstra
constructorul implicit în clasă, prin declarația
NumeClasa()=default;
pentru a fi utilizat pentru crearea de tablouri de obiecte.
13
Tabloul poate fi iniţializat la declarare :
Point patrat[4] = {Point(5,5), Point(5,10), Point(10,10)};

Observații:
 pentru fiecare element din lista de iniţializare se
apelează constructorul cu parametri
 dacă lista de iniţializare nu are suficiente elemente,
pentru elementele din tablou neiniţializate se apelează
constructorul fără parametri sau cel cu toti parametrii
impliciti
 dacă la declarare se face inițializarea tuturor
elementelor utilizând constructorul cu parametri, atunci
constructorul fără parametri poate lipsi (excepție în
unele medii de programare)

14
 Dacă constructorul poate fi apelat cu un singur parametru,
se admite o formă scurtă astfel:

Point patrat[4] = {5, 10, 15, 20};


echivalentă cu:

Point patrat[4] = {Point(5), Point(10), Point(15), Point(20)};

15
 Tablourile de obiecte pot fi create dinamic astfel:
Point *patrat = new Point[4];

delete [ ] patrat;

 Obiectele unui tablou dinamic nu pot fi iniţializate explicit


la declarare, ca urmare trebuie să existe un constructor
fără parametri pentru acea clasă (sau toţi parametrii
impliciţi)
 Ulterior se pot face iniţializări explicite astfel :
patrat[0] = Point(5,5);

16
Rectangle.h

class Rectangle {
// membri privati
int height;
int width;
public:
// membri publici
Rectangle(int h=10, int w=10); // constructor explicit cu toti parametrii impliciti
//sau de la C++1y
// Rectangle(int h, int w);
// Rectangle()=default;
int get_area(void);
void set_values(int h, int w);
17
};
Rectangle::Rectangle(int h, int w) // constructor explicit
{
height = h;
width = w;
}

int Rectangle::get_area(void){
return height * width;
}

void Rectangle::set_values(int init_height, int init_width){


height = init_height;
width = init_width;
}
18
#include "Rectangle.h"
#include <iostream>
using namespace std;

int main( )
{
int i;
cout << "\n\nTablou de obiecte initializat la declarare\n";
Rectangle group1[4]={
Rectangle( ), //echivalent Rectangle(10,10),
Rectangle(20,10),
Rectangle(30,10),
Rectangle(40,10)
};
19
for (i = 0 ; i < 4 ; i++)
cout << "\tAria dreptunghiului: " << group1[i].get_area() << "\n";
cout << "\n...................................\n\n";
// tablou de obiecte
Rectangle group2[4];
cout << "\nTablou de obiecte initializat cu metoda set_values()\n";
for (i = 1 ; i < 4 ; i++)
group2[i].set_values(i + 10, 10);

for (i = 0 ; i < 4 ; i++)


cout << "\tAria dreptunghiului: " << group2[i].get_area() << "\n";
cout << "\n...................................\n\n";

20
// tablou dinamic
Rectangle *group3 = new Rectangle[4];
cout << "\nTablou dinamic de obiecte initializat cu set_values()\n";
for (i = 1 ; i < 4 ; i++)
(group3+i)->set_values(i + 10, 10);

for (i = 0 ; i < 4 ; i++)


cout << "\tAria dreptunghiului: " << group3[i].get_area() << "\n";

delete [ ]group3;
cout << "\n...................................\n\n";

21
// tablou dinamic
Rectangle *group4 = new Rectangle[4];
cout << "\nTablou de obiecte initializat prin constructor\n";
group4[0]=Rectangle(5,10);
group4[1]=Rectangle(15,20);
group4[2]=Rectangle(25,30);
group4[3]=Rectangle(35,40);

for (i = 0 ; i < 4 ; i++)


cout << "\tAria dreptunghiului: " << (group4+i)->get_area() << "\n";

delete [ ]group4;
cout << "\n...................................\n\n";
cin.get();
}//main
22
23
Membri statici

 Membrii unei clase, fie ei atribute(variabile) sau metode,


pot avea în declaraţia lor specificatorul static .

 Variabile statice
 Comportamentul datelor membre statice este similar cu
cel al variabilor statice obişnuite, dar primele nu sunt
accesibile decât prin intermediul clasei
 Pentru datele nestatice ale unei clase există copii
distincte în fiecare obiect (valori distincte)
 Datele statice există într-o singură copie:
 dacă un obiect modifică o variabilă de tip static, noua
valoare va fi văzută în toate obiectele instanţiate din clasa
respectivă
24
 Crearea, iniţializarea şi accesul la aceşti membri sunt
independente de celelalte obiecte ale clasei, motiv pentru
care se mai numesc şi variabile de clasă
 Membrii statici ai unei clase pot fi declaraţi în oricare
secţiune (private, public sau protected), iar funcţiile
membre au acces la membrii statici la fel ca la oricare
membru
 Un membru static poate fi referit din exterior astfel:
 indicând numele clasei şi folosind operatorul de rezoluţie,
chiar dacă nu există obiecte instanţiate ale clasei
 specificând un obiect al clasei şi folosind un operator de
acces adecvat ( “.” pentru accesul prin obiect, respectiv “->”
pentru accesul prin pointer)
25
 Variabilele statice trebuie redeclarate în exteriorul clasei,
în caz contrar, compilatorul va afişa un mesaj de eroare:
 acest lucru se datorează faptului că în momentul
declarării unei variabile statice în interiorul clasei,
acesteia nu îi este alocată memorie, operaţia
efectuându-se prin redeclararea acesteia în exterior,
cu specificarea clasei de care aparţine respectiva
variabilă
 în cadrul redeclarării, nu mai apare cuvântul cheie

static

 Declaraţia externă poate fi însoţită de iniţializare (altfel


se face o iniţializare implicită cu valoarea 0)

26
class MyClass {
int x;
public:
static int n;
MyClass (int v) {
cout<<"\nApel constructor cu valoarea: "<<v<<"\n";
x = v;
n++;
}
// metoda de afisare (nerecomandat), de regula folosim getteri pentru accesul
// la date (vedeti exemplul urmator) → slide 30
void showVal(void) {
cout << "Date membre: "<< "x = " << x;
cout << ", n = " << n << "\n";
}
~MyClass( ) {
n--;
cout<<"\nApel destructor: n = "<<n<<"\n";
} 27
};
int MyClass::n; // variabila statică va fi astfel vizibilă

int main( ) {
cout<<"Acces prin numele clasei: n = "<< MyClass::n <<"\n";

MyClass a(3);
a.showVal();
cout<<"\nAcces prin obiectul a: n = "<< a.n <<"\n";

MyClass b(5);
b.showVal();
cout<<"\nAcces prin numele clasei: n = "<<MyClass::n<<"\n";
}

28
 Metode statice
 Pot exista metode precedate de specificatorul static
 Caracteristici:
 au acces doar la alţi membri de tip static ai clasei şi
bineînţeles, pot lucra cu membri globali
 nu pot avea pointeri this

 nu poate exista o versiune statică şi una nestatică a

aceleiaşi metode

 Utilizare uzuală: la definirea rutinelor callback


(programare Windows) pentru care lista de parametri nu
este sub controlul programatorului
 Apel prin obiect sau referință și operatorul ”.”, prin
pointer și operatorul “->” sau prin numele clasei și
operatorul “::”. 29
//campuri si metode statice
#include <iostream>
using namespace std;

class MyClass {
int x;
static int y; //atribut privat
public:

30
void setX(int a){
x = a; }
static void setY(int b) {
y = b; }
int getX( ) {
return x; }
static int getY( ) { pentru acces la atribut privat
return y;
}
};

int MyClass::y; //variabila statica va fi astfel vizibila si initializata cu 0


int main( ) {
MyClass ob1, ob2;
ob1.setX(1);
ob1.setY(2); //nerecomandat
MyClass::setY(3);
cout << "\nValoarea lui x(nonstatic): " << ob1.getX();
cout << "\tValoarea lui y(static) prin class: " << MyClass::getY();
cout << "\nValoarea lui y(static) prin obiect: " << ob1.getY();
//nerecomandat
ob2.setX(5);
ob2.setY(6); //nerecomandat
MyClass::setY(7);
cout << "\nValoarea lui x(nonstatic): " << ob2.getX();
cout << "\tValoarea lui y(static) prin class: " << MyClass::getY();
cout << "\nValoarea lui x(nonstatic): " << ob1.getX();
cout << "\tValoarea lui y(static) prin class: " << MyClass::getY();
cin.get( );

31
}
Domeniu de vizibilitate pentru clase

 O clasă introduce un domeniu de vizibilitate la fel ca o


funcţie sau un bloc

 Toţi membrii clasei aparţin acestui domeniu şi ca urmare


sunt ascunse alte definiţii externe de entităţi cu acelaşi
nume

32
 Entităţile externe pot fi accesate folosind operatorul de
rezoluţie astfel:

int x;
class Point {
int x,y;
public:
Point(void);

};

Point::Point(int x) {
x=::x;
33
}
 Declaraţia unei clase poate apărea în următoarele
ipostaze :

 la nivel global, în afara oricărei clase sau funcţii; în


acest caz avem clase globale (cazul uzual);

 în domeniul unei alte clase, rezultând clase imbricate;

 la nivel local, în interiorul unui bloc; în acest caz avem


de-a face cu clase locale;

34
 Clasele imbricate se folosesc atunci când o clasă
este utilizată doar de o altă clasă:

 clasa interioară poate apărea în orice secţiune a clasei


exterioare

 clasa exterioară nu are privilegii în ceea ce priveşte


accesul la membrii clasei interioare

 clasa interioară poate fi considerată membră a clasei


exterioare, dar membrii acesteia nu sunt membri ai
clasei exterioare

 pentru a avea acces din clasa exterioară la membrii


privaţi din clasa interioară şi invers, se foloseşte
conceptul de clasă prietenă
35
class Rectangle {
public:
Rectangle(int, int, int, int);
private:
class Point {
int x,y;
public :
Point(int, int);
};
Point topLeft;
Point botRight;

}; 36
 Definiţiile metodelor clasei Point şi accesul la obiectele
clasei trebuie să conţină calificarea completă, utilizând
operatorul de scop:

Rectangle::Point::Point(int x, int y){


// corp metoda
}

Rectangle::Point pct(1,1); // instanțierea unui obiect
// din clasa interioara Punct

37
 Clasele locale se folosesc atunci când acestea sunt
folosite numai în interiorul unui bloc (funcţie sau
instrucţiune compusă):

 sunt accesibile numai în interiorul blocului


 trebuie definite complet în interiorul blocului, deci
metodele trebuie să fie de tip inline, adică foarte
simple
 În clasele locale nu putem avea date membre statice
 Declarațiile din interiorul unei clase locale pot folosi
doar nume de tipuri, enumerări, variabile statice din
domeniul exterior clasei (bloc), variabile globale, funcții
și variabile externe

38
// Membrii statici și clasele locale
#include <iostream>
using namespace std;

// clasele imbricate POT avea membri statici


class Outer {
class Inner {
static int i; // OK
};
};
int Outer::Inner::i = 47;

39
// clasele locale NU POT avea membri statici
void f() {
class Local {
public:
//! static int i; // Eroare
// Cum poate fi definit i ?
} x;

int main() {
//Outer x;
f(); 40

} // main
#include<iostream>
using namespace std;
int x; // variabile globale
void f() { // definirea funcției
static int y; // variabila statică y poate fi utilizată de clasa locală
// int x; // variabila auto x nu poate fi utilizată de către clasa locală
extern int g(); // funcția externă g poate fi utilizată de clasa locală
class Local { // clasa locală
int g() {cout<<"\nextern local"; return 1;
//return x; // error, local variable x cannot be used by g()
} //g
public: int h() { return y; } // ok, y variabilă statică din blocul extern
int k() { return ::x; } // ok, x- variabilă globală
int l() { return g(); } // ok, g() este funcție externă
}; // class Local
Local ob;
cout<< ob.l(); 41

} // f()
Funcţii prietene

 Funcţia prietenă nu este membră a clasei, dar are acces


la toţi membrii clasei în care este declarată
 Declaraţia unei funcţii prietene se face în interiorul clasei
folosind cuvântul cheie friend

 Există mai multe situaţii posibile :


 o funcţie friend independentă
 o funcţie friend unei clase este membră a altei clase
 o funcţie este prietenă mai multor clase

42
Exemplu: funcție friend independentă

class MyClass {
private: int m, n;
public:
friend float media(MyClass x);
void init(int x, int y) {
m = x;
n = y;
}
};

// are acces chiar si la membrii de tip private din clasa


float media(MyClass x)
{
float rez;
rez = (float)(x.m + x.n)/2;
43
return rez;
}
Exemplu: funcție friend membră în altă clasă
class X; // declarație incompletă

class Y {
public:
float media(X x) {
// corp metoda
}

};

class X {
private: int m, n;
public:
friend float Y::media(X x);
44
};
FUNCTII FRIEND, STRUCTURI ȘI CLASE

a) structura
struct Complex{
double re;
double im;
};
double modul (Complex *z){
return sqrt(z->re * z->re + z->im * z->im);
}
apel:
Complex z1 = {1,1};
double d = modul (&z1);
45
b) Metode membre în clase
class Complex{
double re, im;
public:
Complex(double x=0, double y=0) {
re = x;
im = y; }
double modul(){
return sqrt(re*re + im*im); }
...
}; //Complex class
apel:
Complex z1(1,1); 46

double d = z1.modul();
c) Functii friend în clase
class Complex{
double re, im;
public:
Complex(double x=0, double y=0) {
re = x;
im = y; }
friend double modul(Complex *z);
...
}; //class
double modul (Complex *z){
return sqrt(z->re*z->re + z->im*z->im);}
apel:
Complex z1(1,1); 47

double d =modul (&z1);


Observații:

 Funcţiile friend se utilizează pentru a realiza operaţii


între clase
 Utilizarea funcțiilor friend implică specificarea clară a
parametrilor de apel, pointerul this nefiind valabil.

 Utilizarea acestor funcţii prietene vine în contradicţie


cu conceptul de ascundere a datelor şi metodelor
(incapsulare)

48
Clase prietene

 Clasa prietenă are acces la toţi membrii celeilalte clase

class Square; // declarație incompletă

class Rectangle
{
int x, y;
public :
int aria(void) {
return x*y;
}
int setVal(int, int);
void convert(Square);
49
};
class Square
{
private :
int x;
public :
void setVal(int a) {
x=a;
}
friend class Rectangle; //Rectangle e friend cu Square
};

void Rectangle::convert(Square a)
{
x = a.x;
y = a.x;
} 50
 Intrebari:
- Ce este o lista de initializare? Cand trebuie folosita?
- Ce este o clasa interioara (imbricata)? Cum
instantiem obiecte dintr-o clasa interioara?
- Ce este o clasa locala? Cum poate fi utilizata?
- Ce intelegeti printr-un atribut static al unei clase?
- Este suficient sa declaram un atribut static in clasa
pentru a putea fi folosit?
- Cum poate fi accesat din afara clasei un membru
static public?
- O metoda membra statica are access la toti membrii
clasei?

51
 Intrebari
- Ce este o functie prietena? Cum se declara? Cum
poate accesa membri ai clasei pnetru care e prietena?
- O functie prietena unei clase poate fi fara parametri?
- O functie prietena unei clase poate fi declarata in
orice sectiune a clasei?
- Ce este o clasa prietena?

52

S-ar putea să vă placă și