Documente Academic
Documente Profesional
Documente Cultură
Programare Obiect Orientata
Programare Obiect Orientata
ndrumar
C++
-3-
Cuprins
Lucrarea nr. 1
// valid
// valid
// valid
// valid
// invalid
-7-
_cdecl
_cs
else
far
_huge
interrupt
operator
register
sizeof
this
volatile
Spaiu de
memorie
ocupat
Domeniu de valori
8 bii
-128127
unsigned char
8 bii
0255
16 bii
-3276832767
16 bii
065535
32 bii
-21474836482147483647
32 bii
04294967295
Domeniu de valori
float
+/-(3.4E-383.4E+38)
precizie 7 cifre
double
64 bii
+/-(1.7E-3081.7E+308)
precizie 15 cifre
long double
80 bii
+/-(3.4E-49321.1E4932)
precizie 19 cifre
Tipul fundamental void indic absena oricrei valori i se utilizeaz n
Constante
Constantele sunt valori fixe (numerice, caractere sau iruri de caractere),
care nu pot fi modificate n timpul execuiei programului. Tipul constantei este
determinat de compilator pe baza valorii i sintaxei utilizate. Ele rmn n
memorie pe toat durata execuiei programului.
Constante ntregi
Tipul constantei este determinat pe baza valorii, sau prin utilizarea unui
sufix (U sau u pentru unsigned, respectiv L sau l pentru long).
Constantele ntregi pot fi zecimale, octale sau hexazecimale.
Constante zecimale (baza 10)
Constantele zecimale se disting prin faptul c prima cifr este diferit de
0, cum ar fi:
23
23u
32768
77UL
// tip int
// tip unsigned int
// tip long int
// tip unsigned long int
// tip int
// tip unsigned int
// tip long int
// tip unsigned long
// eroare, prima cifr indic reprezentarea n octal i numrul include
// cifrele 8 i 9
// tip int
// tip unsigned int
// tip unsigned int
// tip long int
// tip unsigned long int
parte ntreag
punct zecimal
parte fracionar
Caracter
alarm (bell)
BS
FF
LF
CR
TAB
VT
\
?
orice caracter
orice caracter
Descriere
sun alarma
backspace
formfeed
linefeed
carrige return
tab orizontal
tab vertical
backslash
apostrof
ghilimele
semnul ntrebrii
ir de cifre octale
ir de cifre hexazecimale
// se afieaz caracterul ?
// se afieaz caracterul ? , 63 fiind valoarea
// corespunztoare n codul ASCII
// se afieaz caracterul ?
// se afieaz caracterul ?
Pentru scrierea irurilor lungi se poate utiliza simbolul (\) care semnaleaz
continuarea irului pe rndul urmtor:
Exemplu de sir \
scris pe doua randuri
Variabile
Declaraii de variabile
Toate variabilele trebuie declarate nainte de a fi folosite.
Declaraia unei variabile (obiect) precizeaz numele (identificatorul) cu
care va fi referit, cruia i poate asocia o serie de atribute, cum ar fi:
- tipul datei poate fi tip fundamental sau definit de utilizator i determin
structura, gama de valori, dimensiunea spaiului ocupat n memorie;
- clasa de memorare stabilete zona de memorie n care se va plasa
informaia asociat identificatorului (segment de date, registru, stiv,
heap) i delimiteaz durata sa de alocare;
- domeniul reprezint poriunea de program n care poate fi accesat
informaia asociat identificatorului, el fiind determinat de poziia
declaraiei;
- durata de via a identificatorului reprezint perioada ct exist efectiv n
memorie i este corelat cu clasa de memorie;
- legtura precizeaz modul de asociere a unui identificator cu un anumit
obiect sau funcie, n procesul de editare a legturilor.
Atributele se pot asocia identificatorilor n mod implicit, n funcie de
poziia i sintaxa declaraiei sau explicit prin utilizarea unor specificatori.
Sintaxa unei declaraii de variabil impune specificarea tipului, avnd
forma general:
tip_var nume_var;
tip_var este un specificator de tip de date oarecare, standard, pointer sau
definit de utilizator.
float * r;
unsigned int n;
}
int functie (int n, float q)
static
Declaraia static a unei variabile locale foreaz durata static fr a
modifica domeniul de existen. Variabilele statice i pstreaz valoarea ntre
dou apeluri succesive ale blocurilor care le conin, asigurndu-se n acelai
timp o protecie, dar ele nu pot s fie accesate din blocuri care nu constituie
domeniul lor de existen. Variabilele statice pot fi declarate cu iniializare, n
caz contrar, implicit se iniializeaz cu valoarea 0, similar variabilelor globale.
#include <stdio.h>
int fct()
{
static int a=2;
return (a++); }
void main(void)
{
int n;
Programul afieaz:
Prima atribuire : n= 3
A doua atribuire : n= 4
register
Declaraia register are ca efect memorarea variabilei ntr-un registru al
procesorului i nu n memorie, avnd ca rezultat creterea vitezei de execuie a
programului. Aceste variabilele pot fi variabile locale, nestatice, de tip int sau
char. Numai dou variabile pot fi memorate simultan n registre, n cazul
existenei mai multor declaraii register, cele care nu pot fi onorate vor fi tratate
de compilator ca variabile obinuite.
register char c;
extern
Specificatorul extern indic legtura extern i asigur durata static
pentru variabile locale i globale sau pentru funcii (acestea au implicit legtur
extern i durat static).
Pentru identificatorii cu legtur extern sunt permise mai multe declaraii
de referin, dar o singur definiie. De exemplu, n cazul unui proiect n care o
variabil se folosete n mai multe fiiere, ea se va defini global ntr-un fiier, n
celelalte fiind declarat extern fr definire. Compilatorul i va aloca o singur
dat memorie.
// Fiier Ex_prj.cpp
#include <stdio.h>
extern int m;
void main(void)
{
scanf(%d, &m);
printf(\nm= %#x, m);
}
// Fiier Ex_prj1.cpp
...
int m ;
// declaraia variabilei m
// declaraie cu iniializare
// eroare, nu se poate converti const int * la int *
// corect, tipul de date corespund
// eroare, se ncearc modificarea unui obiect constant
volatile
Variabilele volatile pot fi modificate din exteriorul programului (de
exemplu servirea unei ntreruperi).
Declaraia typedef
Specificatorul typedef nu declar un obiect, ci asociaz un nume unui tip
// pointer la ntreg
// tablou de pointeri ctre ntregi
// dubl indirectare; pointer la pointer
Programul afieaz:
Variabila var se afl la adresa: FFF4 si are valoarea iv= 20
Variabila pvar are valoarea: FFF4 si adreseaza obiectul: 20
Noua valoare a lui var este 50
Situaia:
tipl * id_pl;
tip2 * id_p2;
id_pl=&id_p2;
nu genereaz erori dac tip1 i tip2 sunt identice, sau, n caz contrar dac tip1
este void.
Dac se folosete un pointer void, pentru orice referire a obiectului adresat
este necesar precizarea explicit a tipului utiliznd operatorul cast.
void main()
{ void *p1;
float *p2, var=1.5;
p2=&var;
p1=p2;
Variabile referin
C++ ofer posibilitatea de a declara identificatori ca referine de obiecte
(variabile sau constante). Referinele, ca i pointerii, conin adrese. Pentru a
declara o referin la un obiect se folosete simbolul &, folosind sintaxa:
tip & id_referinta = nume_obiect;
tip este tipul obiectului pentru care se declar referina, iar simbolul &
precizeaz c id_referinta este numele unei variabile referin, iar nume_obiect
este obiectul a crui adres va fi coninut n id_referinta.
int n;
int * p=&n;
int &r=n;
n=20;
*p=25;
r=30;
// n primete valoarea 20
// n primete valoarea 25
// n primete valoarea 30
int &r=20 ;
&tab[0] = = tab ;
&tab[2] = = tab+2 ;
tab[0] = = *tab ;
tab[2] = = *(tab+2) ;
tab++ ;
// eroare, tab este un pointer constant, deci nu se poate incrementa
ptr++ ;
// corect, ptr este un pointer la float, nu a fost declarat constant
sau
typedef enum {false, true} boolean; // declaraia este echivalent declaraiei anterioare
# include <stdio.h>
enum boolean {false, true}; // valoarea identificatorului false este 0, iar a lui true este 1
void main()
{
boolean op1=false, op2;
op2=true;
printf(\n op1=%d\nop2=%d, op1, op2);
}
// p1 se declar cu iniializare
// prin atribuire, p2 preia, membru
// cu membru datele din p1
printf(\nNumele:%s, p2.nume);
printf(\nPrenume:%s, p2.prenume;
printf(\nData nasterii: %d.%d.%d, p2.data_n.zi, p2.data_n.luna, p2.data_n.an);
void main()
{
DATE data_n;
// se declar un obiect de tip DATE
unsigned int aux1, aux2, aux3;
puts(Introduceti data :)
scanf(%2d.%2d.%4d, &aux1, &aux2, &aux3); // este necesar utilizarea unor variabile
// auxiliare pentru citirea valorilor,
// deoarece pentru cmpurile de bii nu se
// poate face referire la adres
Uniuni
Uniunea permite utilizarea n comun a unei zone de memorie de ctre mai
multe obiecte de tipuri diferite. Sintaxa de declarare a unei uniuni este similar
declaraiei unei structuri:
union id_tip_uniune {
tip_elem1 id_elem1;
tip_elem2 id_elem2;
};
};
void main ()
{
intreg i;
i.val=22;
// se afieaz fiecare bit al uniunii separat:
printf("\n0x%x se reprezinta in binar: %d%d%d%d%d%d%d%d", i.val, i.bit.b7,
i.bit.b6, i.bit.b5, i.bit.b4, i.bit.b3, i.bit.b2, i.bit.b1, i.bit.b0);
}
Programul afieaz:
0x16 se reprezinta in binar 00010110
Programul afieaz:
Intruduceti un numar intreg si apoi un numar real:15 3.1416
Ati introdus:15 si 3.1416
Introduceti numele dvs: ANDREI
Salut, ANDREI !
Programul afieaz:
Sir de caractere
S
0xffe0
0xffe0
s
sir de caractere
Alt sir de caractere
Alt sir de caractere
abc
a
0xfff4
0x00be
Programul afieaz:
Acesta este un sir prea lung pentru a fi scris pe un singur rand.
El poate fi continuat pe randul urmator.
Exerciii:
1. S se creeze un fiier cu extensia .h n care s se declare funcii cu
diferite prototipuri, cu liste de parametri i valori returnate de tip void,
char, int sau float. Funciile vor fi definite ntr-un fiier cu extensia .cpp
ce include fiierul header definit anterior, ele afind numele funciei,
valorile argumentelor i tipul returnat. Un al treilea fiier, tot cu extensie
b. #include<iostream.h>
void main()
{ int x,y;
cin>>x>>y;
x=x/y;
cout<<"x="<<x;}
c. #include<iostream.h>
void main()
{ char *p;
p="salut";
cout<<p<<" salut";}
d. #include<iostream.h>
void main()
{ int x=2,y=7,z=4;
char w='f';
cout<<x<<y<<" "<<z;
cout<<"\n"<<w;}
b.
.................
float i=3.14;
int &j=i;
j+=3;i-=1;
j++;
..............
b.
................
float i=3.14;
int &j=i;
j+=3;i-=1;
j++;
..............
Lucrarea nr. 2
()
->
++
--
&
<<
>>
<
>
<=
>=
==
!=
&& | |
?:
*=
/=
%= +=
-=
^=
##
.*
->*
|=
sizeof
new delete ::
Operatori
() [] - :: .
! ~ + - ++ -- & *
(tip) sizeof new delete
.* ->*
* / %
+ << >>
< <= > >=
= = !=
&
^
|
&&
||
?: (operator condiional)
= *= /= %= += -=
&= ^= |= <<= >>=
, (operator virgul)
Asociativitate
de la stnga la dreapta
de la dreapta la stnga
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la dreapta la stnga
de la dreapta la stnga
de la stnga la dreapta
Operatori aritmetici
// i=6, j=6;
// i=5, j=6;
- 39 -
unar
binar
binar
binar
binar
binar
complement fa de 1
I bit cu bit
SAU bit cu bit
SAU EXCLUSIV bit cu bit
deplasare la stnga
deplasare la dreapta
Operatori de atribuire
Expresii de tipul:
e1 = (e1) operator (e2);
pot fi scrise ntr-o form condensat :
e1 operator= e2;
unde (operator= ) este operator de asignare n care operator poate fi unul dintre:
+ - * / % << >> & ^ |
i = i+2;
x= x*(y+1);
a=a>>b;
echivalent cu
echivalent cu
echivalent cu
- 40 -
i+=2;
x*=y+1;
a>>=b;
// 1
// 2
// 3
int x=7;
int *y=&x;
delete y;
#include<iostream.h>
int a=3;
- 43 -
}
void f(int a)
{ a++;
(::a)++;
}
- 44 -
Instruciuni
O instruciune este o expresie care se ncheie cu punct i virgul (;).
Instruciunile se pot scrie pe mai multe linii de program, spaiile
nesemnificative fiind ignorate.
int i;
i=
5;
Instruciunea vid
Instruciunea vid are forma:
;
i este utilizat pentru a evita utilizarea unei etichete sau atunci cnd corpul unui
ciclu nu conine nici o instruciune.
Instruciunea compus (blocul de instruciuni)
Instruciunea compus grupeaz declaraii i instruciuni. Blocul de
- 45 -
// se declar i
// nceputul blocului
// se redefinete i
// se declar j
// se afieaz i=9
// sfritul blocului
// se afieaz i=7
// eroare, instruciunea se afl n afara domeniului de
// existen a lui j
deseori
combinaie
cu
- 46 -
- 47 -
for(i=n; i; i--)
cout<<\ni=<<i;
Instruciunea switch
Instruciunea switch este o instruciune decizional, ea permind selecia,
n funcie de valoarea unei expresii, ntre mai multe opiuni posibile. Sintaxa
instruciunii este:
switch (expr)
{
case const1: lista_instructiuni;
<break;>
case const2: lista_instructiuni;
<break;>
..
<default> lista_instructiuni;
}
unde:
- 48 -
Instruciunea break
Instruciunea are forma:
break;
i are ca efect terminarea execuiei unui ciclu de tip while, do-while, for sau a
instruciunii switch, controlul fiind transferat instruciunii imediat urmtoare.
Instruciunea continue
Instruciunea are forma:
continue;
i are ca efect trecerea la urmtoarea iteraie ntr-un ciclu while, do-while sau
for.
Instruciunea return
Formele admise sunt:
return;
sau
return (expr);
sau
return expr;
Efectul instruciunii este de a trece controlul la funcia care a apelat
funcia ce conine instruciunea return, fr transmiterea unei valori n prima
form i cu transmiterea valorii expr n celelalte.
- 49 -
a. #include <iostream.h>
int a=2;
void main ()
{
a=3;
a++;
cout<<(::a);
}
void main()
{ int a=5; a++;
cout<<"\t"<<f(a);}
int f(int a)
{ a++; cout<<(::a);
return a; }
- 50 -
c. ..........
int *p;
p=new int(10);
delete p;
.............
b. .........
int *p,*q;
p=new int(7);
q=p;
delete q;
*p=17;
...........
d. ........
int x=7;
int *y;
delete y;
*y=7;
.........
- 51 -
Lucrarea nr. 3
Funcii n C/C++
Funcii
n limbajul C++ (similar cu limbajul C standard) programul este o colecie
de module distincte numite funcii, structura general a programului fiind:
<directive preprocesor>
<declaraii globale>
funcii
Un program C++ conine obligatoriu o funcie numit main() i aceasta
este apelat la lansarea n execuie a programului.
Programul surs poate fi partiionat n mai multe fiiere grupate ntr-un
proiect (se utilizeaz meniul Project din mediul de programare utilizat). Fiecare
fiier conine declaraii globale i un set de funcii, dar numai unul conine
funcia main().
n C++, ca i n C, se utilizeaz declaraii i definiii de funcii.
Definiii de funcii
Sintaxa definiiei unei funcii este:
tip_rez nume_funcie (<lista_parametri>)
{
declaraii locale
secven de instruciuni
}
unde:
- 52 -
Transferul parametrilor
Transferul prin valoare. Conversii de tip
La apelul unei funcii, valoarea parametrilor efectivi este ncrcat n zona
de memorie corespunztoare parametrilor formali. Acest procedeu se numete
transfer prin valoare. Dac parametrul efectiv este o variabil, ea nu este
afectat de nici o operaie asupra parametrului formal, ceea ce poate constitui o
protecie util.
Transferul de valoare este nsoit de eventuale conversii de tip realizate de
compilator, implicite sau explicite dac se folosete operatorul cast.
Transferul prin referin
Pentru ca o funcie s poat modifica valoarea unei variabile folosit ca
parametru efectiv, trebuie folosit un parametru formal de tip pointer, iar la apelul
funciei s se foloseasc ca parametru explicit adresa variabilei.
#include <stdio.h>
void schimba(int *, int *);
void main()
{
int i, j;
scanf(%d%d, &i, &j);
schimba(&i, &j);
// la apelul funciei, parametrii efectivi sunt adrese de variabile
printf(\ni=%d, j=%d, i, j);
}
void schimba(int *a, int *b)
{ int temp ;
temp=*a;
*a=*b;
*b=temp;
}
- 54 -
- 55 -
Pointeri de funcii
Limbajul C++, ca i limbajul C, permite operarea cu variabile pointer care
conin adresa de nceput a codului executabil al unei funcii. Aceste variabile
permit:
// prototip de funcie
- 57 -
}
void test(char*a, char*b, int(*comp)(char*, char*))
{
if(!(comp)(a, b))
printf("\ns1 egal cu s2");
else
printf("\ns1 diferit de s2");
}
int comp(char *s1, char *s2)
{ return(s1[0]-s2[0]); }
- 58 -
void main()
{
cout<<Apel normal : f( 5, 10)<<endl;
f( 5, 10);
cout<<Apel cu un singur parametru: f( 5 )<<endl;
f( 5 );
}
void f(int a, int b)
{
cout<<a=<<a<<; b=<<b<<endl;
}
Programul afieaz:
Apel normal: f( 5, 10)
a=5; b=10
Apel cu un singur parametru: f( 5 )
a=5; b=20
}
void f2(int i, double q = 7.5)
{
cout<<\ni=<<i;
cout<<\tq=<<q;
}
void f3(int i, long j, double r)
{
cout<<\ni=<<i;
cout<<\tj=<<j;
cout<<\tr=<<r;
}
// definiie corect
Programul afieaz:
i=1
i=2
i=3
i=4
j=111
j=1
j=99
j=99
r=3.5
r=3.5
r=3.5
r=7.8
- 60 -
// funcia 1
// funcia 2
void main()
{
int i = 5;
float r = 2.5;
char c = a;
long l = 10000;
- 61 -
// apel funcia 1
// apel funcia 2 cu conversie nedegradant float ->double
// apel funcia 1 cu conversie nedegradant char ->int
// eroare la compilare datorat ambiguitii aprute n etapa a 3-a
}
void g(int a)
{
cout<<\nApel functia 1 cu argumentul: <<a;
}
void g( double a )
{
cout<<\nApel functia 2 cu argumentul: <<a;
}
// funcia 1
// funcia 2
}
void g(int a, float b)
{
cout<<\nApel functia 1 cu argumentele:
cout<<a=<<a<<\tb=<<b;
}
void g(float a, int b)
{
- 62 -
// 1
// 2
// 3
- 63 -
Funcii inline
Directiva de preprocesare #define ofer posibilitatea utilizrii
macrodefiniiilor cu parametri. Pentru fiecare apel, prepocesorul insereaz n
textul programului, n locul apelului, textul macrodefiniiei n care se substituie
numele parametrilor formali cu cele ale parametrilor efectivi. Compilatorul preia
apoi textul, ignornd existena macrodefiniiilor.
#define fct( a, b ) a+b
void main()
{
int i = 2, j = 5, k ;
k = fct( i, j );
float r = 2.3, s = 5.2, t;
t = fct( r, s );
cout<<\nk=<<k;
cout<<\nt=<<t;
}
// corect, j = 5*5 = 25
// incorect, j= 5 + 1 * 5 + 1 = 11
- 64 -
// corect j = ( 5 ) * ( 5 ) = 25
// corect j = ( 5+1 ) * ( 5+1 ) = 36
- 65 -
// definiie corect
f(20);
f(20, 30);
3. Ce afieaz secvenele:
a. #include<iostream.h>
b. #include<iostream.h>
void f(int);
void f(double);
void main()
{ f(3,6); f(3.14,6); f(3); }
void f(int a, int x)
{ cout<<"\nMesaj si x="<<x; }
void f(double b, int y)
{ cout<<"\tEroare si y="<<y; }
void main()
{ f(3); f(3.14); }
void f(int x)
{ cout<<"Mesaj\t"<<x; }
void f(double y)
{ cout<<"\nEroare\t"<<y; }
// Funcia a
// Funcia b
// Funcia c
- 67 -
Lucrarea nr. 4
Tipul class
Sintaxa general de declarare a unui tip de date class este similar cu a
tipului struct:
class <nume_clasa> <: lista_clase_baza> {<lista_membri>}
<lista_variabile>;
unde:
lista_clase_baza este lista claselor din care este derivat clasa declarat (dac
este cazul);
- 70 -
void main()
{
Punct Punct1;
int x1, y1;
cout<<"\n Introduceti coordonata x= ";
cin>>x1;
cout<<" Introduceti coordonata y= ";
cin>>y1;
Punct1.init(x1, y1);
cout<<"\n x este = "<<Punct1.getx();
cout<<"\n y este = "<< Punct1.gety();
Punct1.move(10, 20);
cout<<"\n x este = "<<Punct1.getx();
cout<<"\n y este = "<< Punct1.gety();
Punct Punct2;
Punct2.init();
Punct2.afisare();
Punct *p_Punct3;
p_Punct3 = &Punct2;
p_Punct3 -> move ( 5, 12);
Punct2.afisare();
int x, y;
- 72 -
Constructori i destructori
Unele obiecte necesit alocarea unor variabile dinamice la creare,
eventual atribuirea de valori adecvate datelor nainte de utilizare. Pe de alt
parte, eliminarea unui obiect de acest tip impune eliberarea zonei de memorie
alocat dinamic.
Pentru crearea, iniializarea, copierea i distrugerea obiectelor, n C++ se
folosesc funcii membre speciale, numite constructori i destructori.
Constructorul se apeleaz automat la crearea fiecrui obiect al clasei,
indiferent dac este static, automatic sau dinamic (creat cu operatorul new),
inclusiv pentru obiecte temporare.
Destructorul se apeleaz automat la eliminarea unui obiect, la ncheierea
timpului de via sau, n cazul obiectelor dinamice, cu operatorul delete.
Aceste funcii efectueaz operaiile prealabile utilizrii obiectelor create,
respectiv eliminrii lor. Alocarea i eliberarea memoriei necesare datelor
membre rmne n sarcina compilatorului.
Constructorul este apelat dup alocarea memoriei necesare datelor
membre ale obiectului (n faza final crerii obiectului).
Destructorul este apelat naintea eliberrii memoriei asociate datelor
membre ale obiectului (n faza iniial a eliminrii obiectului).
Constructorii i destructorii se deosebesc de celelalte funcii membre prin
cteva caracteristici specifice:
// destructor
- 75 -
- 76 -
// constructor implicit
// constructor cu parametri
// destructor
Programul afieaz:
Constructor implicit
Constructor cu parametri
x=0 y=0
x=10 y=20
Destructor Punct
Destructor Punct
Constructor de copiere
La crearea unui obiect, acesta poate prelua valorile corespunztoare ale
unui obiect deja existent, prin apelul unui constructor special, numit constructor
de copiere.
Declaraia constructorului de copiere pentru o clas este un constructor cu
un parametru unic de tip referin la obiecte de tipul clasei ce se definete:
nume_clasa( nume_clasa &);
n absena definirii explicite a constructorului de copiere n cadrul clasei,
- 77 -
P2.afisare();
i se definete:
Punct::Punct(Punct &P)
{
cout<< \n Constructor de copiere;
x=P.x;
y=P.y;
}
#include <iostream.h>
#define N 10
class tablou
{
float tab[N];
public:
tablou();
void citire();
void afisare();
void modif(int, float);
};
tablou::tablou()
{
for (int i=0; i<N; i++)
tab[i]=0;
}
void tablou::citire()
{
for(int i=0; i<N; i++)
{ cout<<"\ntab["<<i<<"]=";
cin>>tab[i];
}
}
void tablou::afisare()
{
cout<<"\nadresa="<<this;
for(int i=0; i<N; i++)
cout<<"\ntab["<<i<<"]="<<tab[i];
}
void tablou::modif(int i, float el)
{
tab[i]=el; }
void main()
{
tablou t1;
t1.citire();
tablou t2(t1);
t2.modif(0, 2.5);
- 79 -
tablou::tablou()
{
cout<<"\nConstructor implicit";
nr_el=10;
tab=new float[nr_el];
for(int i=0; i<nr_el; i++)
tab[i]=0;
}
tablou::tablou(int n)
{
cout<<"\nConstructor cu parametru ";
nr_el=n;
tab=new float[nr_el];
for(int i=0; i<nr_el; i++)
tab[i]=0;
}
tablou::tablou(tablou &t)
{
cout<<"\nConstructor de copiere";
nr_el=t.nr_el;
tab=new float[nr_el];
for(int i=0; i<nr_el; i++)
tab[i]=t.tab[i]; }
- 80 -
// definire destructor
void tablou::citire()
{
for(int i=0; i<nr_el; i++)
{ cout<<"\ntab["<<i<<"]=";
cin>>tab[i];
}
}
void tablou::afisare()
{
cout<<"\nadresa="<<this;
for(int i=0; i<nr_el; i++)
cout<<"\ntab["<<i<<"]="<<tab[i];
}
void tablou::modif(unsigned int i, float el)
{
if (i>=nr_el)
cout<<"\nParametru ilegal";
else
tab[i]=el;
}
void main()
{
tablou t1(5);
t1.citire();
tablou t2(t1);
t2.modif(0, 2.5);
t1.afisare();
t2.afisare();
tablou t3;
t3.citire();
t3.afisare();
}
care reprezint timpul scurs de la ora 0:0:0 a unei zile, exprimat n secunde.
Funciile membre vor conine afiarea de mesaje i afiarea autoreferinei
obiectelor, astfel nct s se poat urmri, la execuia programului, obiectul
asupra cruia se opereaz i funcia apelat. Funcia main() va conine
declaraii de obiecte de tip ceas cu apel al diferiilor constructori i atribuiri
ntre obiecte de tip ceas i afiarea proprietilor obiectelor ceas prin apelul
funciei afisare().
2. S se defineasc tipul de date:
class sir
{ private:
char * continut;
int dim;
public:
sir(int d = 80);
sir (sir &);
~sir();
void citire();
void afisare(); };
Lucrarea nr. 5
- 83 -
- 84 -
p0.afisare();
cout<<"\nFinal main()";
}
- 85 -
{
cout<<"\nApel test()";
p.deplasare(10,10);
return p;
Programul afieaz:
Apel main()
Constructor 0xfff2
x=0 y=0
Constructor 0xffee
x=1 y=1
Constructor copiere 0xffe6
x=1 y=1
Apel test()
Constructor copiere 0xffea
x=11 y=11
Destructor 0xffe6
x=11 y=11
Destructor 0xffea
x=11 y=11
x=11 y=11
Final main()
Destructor 0xffee
x=1 y=1
Destructor 0xfff2
x=11 y=11
// se creeaz p0
// se creeaz p1
// se creeaz parametrul ca obiect temporar echivalent
// cu apelul p(p1)
// se creeaz obiectul temporar care transfer rezultatul
// se elimin p
// se elimin obiectul care transfer rezultatul
// se elimin p1
// se elimin p0
- 86 -
// se creeaz p0
// se creeaz p1
// se elimin p1
// se elimin p0
- 87 -
// constructor implicit
// constructor cu parametri
void citire_sir();
void afisare();
...
};
//constructor cu parametri
// destructor
- 89 -
- 90 -
Tablouri de obiecte
Tablourile pot avea elemente de orice tip, inclusiv de tip clas.
La crearea unui tablou cu elemente de tip clas, se va apela constructorul
clasei tip element pentru fiecare element n parte. Problemele semnalate la
crearea obiectelor cu membri de tip clas vor aprea i n acest caz. Mai mult, n
cazul tablourilor nu exist posibilitatea specificrii valorilor corespunztoare
parametrilor, deci pentru tipul clas corespunztor elementelor tabloului este
obligatoriu s existe declarat constructor implicit sau constructor cu toi
parametrii implicii. Pentru fiecare element de tablou de tip clas se apeleaz
constructorul, la ncetarea domeniului de existen a tabloului, pentru fiecare
element de tablou se apeleaz destructorul clasei.
#include <iostream.h>
class pozitie
{
int x,y;
public:
pozitie(int abs, int ord)
//constructor cu parametri
{ x=abs; y=ord;
cout<<"Constructor cu parametri - pozitie ";
afisare();
}
- 91 -
- 92 -
#include <iostream.h>
class pozitie
{
public:
int x, y;
pozitie(int abs, int ord)
{ x=abs; y=ord;
cout<<"Constructor cu parametri-pozitie ";
afisare();
}
~pozitie()
{ cout<<"\nDestructor pozitie";}
void deplasare(int abs, int ord)
{ x+=abs; y+=ord; }
void afisare()
{ cout<<"\nx="<<x<<\ty="<<y; }
};
void main()
{
pozitie p(1, 1), *p_poz;
int pozitie::*p_x, pozitie::*p_y;
- 94 -
public:
- 95 -
}
~pozitie()
{ cout<<"\nDestructor pozitie";
cout<<"\nSe distruge obiectul nr. "<<st;
st--;
// odat cu distrugerea unui obiect pozitie, contorul st se
// decrementeaz
}
static void nr_obj()
// funcie static ce permite accesul la membrul static
// privat st
{cout<<"\nNr. obiecte: "<<st;}
void deplasare(int abs, int ord)
{ x+=abs;
y+=ord; }
void afisare()
{ cout<<"\nx="<<x<<"\ty="<<y; }
};
int pozitie::st;
void main()
{
pozitie::nr_obj();
pozitie::st;
pozitie p1(1,1), p2(2,2), *p3;
p1.nr_obj();
p3=new pozitie(3,3);
pozitie::nr_obj();
delete p3;
}
- 96 -
- 97 -
};
void compar(pozitie &p1, pozitie &p2)
{
if ((p1.x= =p2.x)&&(p1.y= =p2.y))
// Situaia 2
#include <iostream.h>
class A;
class B
{
int b;
public:
B(int n)
{b=n;}
void func(A &);
};
class A
{
int a;
public:
A(int n)
{a=n;}
- 98 -
cout<<'\n'<<b;
}
void main()
{
A ob1(10);
B ob2(20);
ob2.func(ob1);
}
- 99 -
- 100 -
public:
dreptunghi(int=1, int=1, int=80, int=25);
// coordonatele sunt normalizate
~dreptunghi();
void afisare();
// afiarea se face n mod text, prin marcarea laturilor
// dreptunghiului cu un caracter oarecare afiat n mod repetat
static int nr_dreptunghiuri(); // afieaz numrul obiectelor dreptunghi existente la un
// moment
void deplasare(int, int);
// realizeaz translatarea dreptunghiului; coordonatele
// sunt normalizate
};
Lucrarea nr. 6
Supradefinirea operatorilor
Funcia operator
Limbajul C++ permite programatorului definirea diverselor operaii cu
obiecte ale claselor, folosind simbolurile operatorilor standard.
Operatorii standard sunt deja supradefinii, ei putnd intra n expresii ai
cror operanzi sunt de diferite tipuri fundamentale, operaia adecvat fiind
selectat n mod similar oricror funcii supradefinite.
Un tip clas poate conine definirea unui set de operatori specifici asociai,
prin supradefinirea operatorilor existeni, utiliznd funcii cu numele:
operator simbol_operator
unde:
- operator este cuvnt cheie dedicat supradefinirii operatorilor;
- simbol_operator poate fi simbolul oricrui operator, mai puin operatorii:
( . ), (.*), ( :: ) i ( ? : ).
Pentru definirea funciilor operator se pot folosi dou variante de
realizare:
- definirea funciilor operator cu funcii membre clasei ;
- definirea funciilor operator cu funcii prietene clasei.
Prin supradefinirea operatorilor nu se pot modifica:
- pluralitatea operatorilor (operatorii unari nu pot fi supradefinii ca
operatori binari sau invers);
- precedena i asociativitatea operatorilor.
Operatorii care pot fi supradefinii n C++ sunt prezentai n Tabelul nr. 7.
- 102 -
Tip
Operatori
Binar () [] ->
Unar ! ~ + - ++ -- &
* (tip) new delete
Binar ->*
Binar * / %
Binar + Binar << >>
Binar < <= > >=
Binar = = !=
Binar &
Binar ^
Binar |
Binar &&
Binar ||
Binar = *= /= %= += -=
&= ^= |= <<= >>=
Binar , (operator virgul)
Asociativitate
de la stnga la dreapta
de la dreapta la stnga
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la stnga la dreapta
de la dreapta la stnga
de la stnga la dreapta
- 103 -
- 104 -
Programul va afia:
re=1
re=3
re=4
re=8
im=2
im=4
im=6
im=12
- 105 -
};
complex operator+(complex a, complex b)
{
complex c;
c.re=a.re+b.re;
c.im=a.im+b.im;
return c;
}
void main()
{
complex c1(1, 2), c2(3, 4), c3, c4;
c1.afisare();
c2.afisare();
c3=c1+c2;
c3.afisare();
c4=c1+c2+c3;
c4.afisare();
}
Programul va afia:
re=1
re=3
re=4
re=8
im=2
im=4
im=6
im=12
operator op(x)
sau
#include <iostream.h>
class pozitie {
int x, y;
public:
pozitie (int abs=0, int ord=0)
{
x=abs;
y=ord;
}
void afisare()
{
cout<<"x="<<x;
cout<<", y="<<y<<'\n';
}
pozitie operator ++()
{
x++; y++;
cout<<"Op++";
return pozitie(x, y);
}
pozitie operator --()
{
x--;
y--;
cout<<"Op--";
return pozitie(x, y);
}
};
// supradefinire operator ++
// supradefinire operator --
- 107 -
r.afisare();
r=++p;
r.afisare();
r=p--;
r.afisare();
}
- 108 -
vector(int gr=10);
~vector();
void afisare(); };
public:
vector::vector(int gr)
{ cout<<"\nConstructor vector\n";
grad=gr;
comp=new double[grad];
cout<<\nVectorul are <<grad<< componente, introduceti valorile:
for(int i=0; i<grad; i++)
cin>>comp[i];
}
vector::~vector()
{ delete comp; }
void vector::afisare()
{
cout<<"\n\nAdresa obiectului este: this="<<this;
cout<<\nVectorul are << grad << componente;
cout<<"\nAdresa membrului comp este: "<<∁
cout<<"\tsi contine valoarea: "<<comp;
cout<<"\nComponentele vectorului sunt:\n";
for(int i=0; i<grad; i++)
cout<<comp[i]<<" ";
}
void main(){
vector v1(5), v2(3);
v1.afisare();
v2.afisare();
v2=v1;
v2.afisare();
}
- 109 -
- 110 -
// constructor de copiere
// supradefinire operator de atribuire
};
vector::vector(int gr)
{ cout<<"\nConstructor vector\n";
grad=gr;
comp=new double[grad];
cout<<"\nVectorul are "<<grad <<"componente, introduceti valorile:\n";
for(int i=0; i<grad; i++)
cin>>comp[i];
}
vector::~vector()
{ cout<<"\nDestructor obiect cu adresa: "<<this;
delete comp;
}
vector::vector(vector &v1)
{
grad=v1.grad;
comp=new double[grad];
for(int i=0; i<grad; i++)
comp[i]=v1.comp[i];
}
void vector::afisare()
{
cout<<"\n\nAdresa obiectului este: this="<<this;
cout<<"\nVectorul are "<<grad<<"componente";
cout<<"\nAdresa membrului comp este: "<<∁
cout<<"\tsi contine valoarea: "<<comp;
cout<<"\nComponentele vectorului sunt:\n";
for(int i=0; i<grad; i++)
cout<<comp[i]<<" ";
}
void vector::operator=(vector &v)
{ if (this!=&v)
{ delete comp;
grad=v.grad;
comp=new double[grad];
- 111 -
- 112 -
Supradefinirea operatorului []
Operatorul de indexare [ ] este un operator binar. El are forma general:
expresie1[expresie2]
Funcia operator[] se definete ca funcie membr a unei clase (ea nu
poate fi definit ca funcie prieten).
Dac pentru o clas A s-a definit funcia operator[](), expresia a[n], unde
a este obiect al clasei A, este echivalent cu :
a.operator[](n)
Clasa vector definit anterior se poate completa cu funcia operator[]()
avnd prototipul:
double& operator[](int);
care, va fi definit astfel:
double& vector::operator[ ](int n)
{ return comp[n];}
- 114 -
public:
persoana()
// constructor implicit
{ *nume='\0';
varsta=0;
}
void date_persoana(char * p, double v)
// funcie membr prin care se transmit
// valori pentru membrii obiectului
{ strncpy(nume, p, 19);
nume[19]='\0';
varsta=v;
}
void afisare()
{ if (this!=NULL)
cout<<"\nNume: "<<nume<<" varsta: "<<varsta<<" ani";
else
cout<<"\nElement inexistent in lista"; }
};
class exemplu_index
{
persoana lista[N];
public:
void citire_date(void);
- 115 -
persoana * operator[](double);
persoana * operator[](int);
};
void exemplu_index::citire_date()
{
char n[20];
double d;
for(int i=0; i<N; i++)
{ cout<<"\nTastati numele si varsta: ";
cin>>n>>d;
lista[i].date_persoana(n, d);
}
}
- 116 -
public:
vector(int gr=10);
~vector();
void afisare();
void * operator new(size_t dim);
void operator delete(void *);
};
int vector::cnt=0;
vector::vector(int gr)
// definire constructor cu parametru implicit
{ cout<<"\nConstructor vector\n";
grad=gr;
comp=new double[grad];
cout<<"\nVectorul are "<<grad <<"componente, introduceti valorile:\n";
for(int i=0; i<gr; i++)
cin>>comp[i];
}
vector::~vector()
// definire destructor
{
cout<<"\nDestructor obiect cu adresa: "<<this;
delete comp;
}
void * vector::operator new(size_t dim)
{
cnt++;
- 118 -
delete p;
}
void vector::afisare()
{
cout<<"\nVectorul are "<<grad<<"componente";
cout<<"\nComponentele vectorului sunt:\n";
for(int i=0;i<grad;i++)
cout<<comp[i]<<" ";
}
void main()
{
vector *pv1, *pv2, *pv3;
pv1=new vector(5);
pv2=new vector(*pv1);
pv3=::new vector(2);
pv1->afisare();
pv2->afisare();
pv3->afisare();
delete pv1;
delete pv2;
::delete pv3;
- 119 -
~rational();
void afiseaza();
};
- 120 -
Lucrarea nr. 7
- 122 -
- 123 -
class complex {
float re, im;
public:
complex(float r=0, float i=0)
//constructor complex
{ re=r; im=i; }
void afisare()
{ cout<<"(re="<<re;
cout<<", im="<<im<<")";
}
friend complex operator +(complex, complex); // supradefinire operator +() binar pentru
// clasa complex
friend pozitie::operator complex();
// declararea funciei operator complex() membr
// a clasei pozitie, prieten clasei complex
};
pozitie::operator complex()
{ cout<<"\nOperator pozitie->complex:";
complex c;
c.re=x;
c.im=y;
cout<<"("<<x<<","<<y<<")->";
c.afisare();
return c;
}
- 125 -
- 127 -
- 128 -
void afisare()
{ cout<<"\nComplex: re="<<re;
cout<<" , im="<<im;
}
complex operator+(complex c)
{
complex aux;
aux.re=re+c.re;
aux.im=im+c.im;
return aux;
}
};
class pozitie
{
int x, y;
public:
pozitie(int abs=0, int ord=0)
{x=abs; y=ord;}
void afisare()
{cout<<"\nPozitie: x="<<x<<"\ty="<<y;}
friend complex::complex(pozitie);
};
complex::complex(pozitie p)
{
re=p.x; im=p.y;
}
void main()
{
complex c1, c2;
pozitie p1(5, 5), p2(7, 7);
// conversie pozitie->complex explicit
c1=complex(p1);
cout<<endl;
p1.afisare();
c1.afisare();
- 129 -
cout<<endl;
c1.afisare();
}
- 131 -
Lucrarea nr. 8
Modificatorul
de acces
private
public
Accesul motenit
de clasa derivat
inaccesibil
private
private
inaccesibil
protected
public
Accesul din
exterior
inaccesibil
inaccesibil
inaccesibil
inaccesibil
inaccesibil
accesibil
Pentru a avea acces la membrii clasei de baz din clasa derivat, este
necesar ca acetia s fi fost declarai protected sau public.
Pentru a pstra dreptul de acces la membrii clasei de baz, este necesar s
se foloseasc acces public.
La stabilirea specificatorilor de acces se au n vedere perspectivele de
dezvoltare a ierarhiei de clase, fr a se nclca principiul ncapsulrii datelor.
Motenirea este asemntoare cu procesul de includere a obiectelor n
obiecte (procedeu ce poart denumirea de compunere), dar exist cteva
elemente caracteristice motenirii:
- codul poate fi comun mai multor clase;
- clasele pot fi extinse, fr a recompila clasele originare;
- funciile ce utilizeaz obiecte din clasa de baz pot utiliza i obiecte
din clasele derivate din aceast clas.
#include <iostream.h>
class punct
{
float x, y;
public :
punct(float a=0, float b=0)
{x=a; y=b;}
- 133 -
cout<<"\tRaza="<<raza; }
void modific_cerc(float dx, float dy, float dr)
{centru.modific_punct(dx, dy);
// modificarea valorilor corespunztoare
// centrului se face prin funcia membr clasei
// punt; nu este permis acces direct deoarece
// membrii x i y sunt private
raza+=dr; }
};
void main()
{
cerc c1;
c1.modific_cerc(1.1, 2.2, 3.3);
c1.afisare();
}
- 134 -
float x, y;
public :
punct(float a=0, float b=0)
{x=a; y=b;}
void modific_punct(float dx, float dy)
{x+=dx; y+=dy;}
};
class cerc : public punct
// n declaraie se specific clasa de baz punct cu acces public
{
float raza;
public:
cerc(float r=0)
{raza=r;}
void afisare()
{cout<<"\nCentru cerc: x="<<x<<"\ty="<<y; // accesul la membrii clasei punct se face
// direct datorit specificatorului
// protected din clasa punct i a
// specificatorului public ataat clasei de
// baz
cout<<"\tRaza="<<raza;
}
void modific_cerc(float dx, float dy, float dr)
{ x+=dx;
// accesul la membrii clasei punct se face direct
y+=dy;
raza+=dr;}
};
void main()
{
cerc c1;
c1.modific_cerc(1.1, 2.2, 3.3);
c1.afisare();
c1.modific_punct(2.5, 4.6);
c1.afisare();
}
punct p1;
p1=c1;
p_p=p_c;
- 136 -
{
raza=r;
cout<<"\nConstructor cerc: this="<<this;
cout<<"\traza="<<r<<endl;
}
~cerc()
{
cout<<"\nDestructor cerc: this="<<this;
cout<<"\traza="<<raza;
}
};
void main()
{
cerc c1(1.1, 2.2, 10), c2(5, 10, 15);
}
x=1.1 y=2.2
raza=10
x=5 y=10
raza=15
raza=15
x=5 y=10
raza=10
x=1.1 y=2.2
- 138 -
Programul afieaz:
Constructor punct:
Constructor cerc:
x=1.1 y=2.2
raza=10
Destructor cerc:
Destructor punct:
raza=10
x=1.1 y=2.2
Destructor cerc:
Destructor punct:
raza=10
x=1.1 y=2.2
punct(punct &p)
{
x=p.x;
y=p.y;
cout<<"\nConstructor de copiere punct:";
cout<<"\tx="<<x<<"\ty="<<y;
}
x=1.1 y=2.2
raza=10
raza=10
x=1.1 y=2.2
Destructor cerc:
Destructor punct:
raza=10
x=1.1 y=2.2
- 140 -
x=1.1 y=2.2
raza=10
Constructor punct:
x=1.1 y=2.2
Constructor de copiere cerc: raza=10
Destructor cerc:
Destructor punct:
raza=10
x=1.1 y=2.2
Destructor cerc:
Destructor punct:
raza=10
x=1.1 y=2.2
x=1.1 y=2.2
raza=10
raza=10
x=1.1 y=2.2
Funcia de afiare membr a clasei punct este motenit de clasa cerc, dar,
avnd n vedere faptul c o funcie de afiare pentru clasa cerc ar trebui s ofere
mai mult informaie, este necesar definirea unei noi funcii de afiare, membr
a clasei cerc.
Este permis supradefinirea funciilor membre clasei de baz cu funcii
membre ale clasei derivate.
Clasa cerc se completeaz cu funcia membr: void afisare().
void cerc::afisare()
{
cout<<\nCerc:;
cout<<\ncentru: x=<<x<<\ty=<<y;
cout<<\nraza: <<raza;
}
Apelul funciei :
c.afisare();
Noile definiii din clasa derivat nu substituie definiiile din clasa de baz,
ci se adaug acestora.
x=1.1 y=2.2
raza=10
raza=10
x=1.1 y=2.2
Destructor cerc:
Destructor punct:
raza=10
x=1.1 y=2.2
- 143 -
- 145 -
- 146 -
Exerciiu:
S se defineasc clasa dreptunghi pentru referirea unei zone din ecran prin
poziia colurilor stnga-sus i dreapta-jos, cu specificarea culorii de afiare.
Prelund aceast clas drept clas de baz, s se defineasc clasa derivat
dreptunghi_cu_chenar prin care se specific caracterul folosit pentru trasarea
chenarului i culoarea acestuia. Afiarea se face n modul text.
- 147 -
Lucrarea nr. 9
- 148 -
- 149 -
x=5
y=5
// se creeaz obiectul p1
x=7
y=7
constructor punct:
poz: x=7
y=7
*
*
constructor poz:
vizibil=1 culoare=7
x=12 y=12
constructor punct:
vizibil=1 culoare=15
constructor caracter: caracter = #
#
destructor caracter: caracter = #
destructor punct:
vizibil=1 culoare=15
destructor poz:
x=12 y=12
destructor punct:
destructor poz:
vizibil=1 culoare=15
x=8 y=8
destructor poz:
x=5
y=5
Clasa caracter este derivat din clasa punct, care la rndul su este
derivat din clasa poz. Ea motenete membrii x i y de la clasa poz, vizibil i
culoare de la clasa punct i adaug membrul caracter. Funcia af() a clasei poz
- 150 -
Motenirea multipl
Conceptul de motenire permite crearea de clase noi care motenesc
proprietile mai multor clase de baz. Motenirea multipl aduce mai mult
flexibilitate n construirea claselor, rezultatul fiind obinerea unor structuri de
clase complexe.
Sintaxa folosit pentru declararea unei clase derivate D este:
class D: specif_acces clasa_baza1, specif_acces clasa_baza2, {}
n lista claselor de baz, pentru fiecare clas de baz, se include
specificatorul de acces.
Principiile prezentate la derivarea simpl i la crearea ierarhiilor simple de
clase sunt valabile i n cazul derivrii multiple.
Prin clasa strpoz se vor crea obiecte ce conin un ir de caractere mpreun
cu poziia de afiare. Aceast clas se obine prin derivarea din clasele pozitie i
string, accesul ctre acestea fiind public.
#include <iostream.h>
#include <string.h>
#include <conio.h>
class pozitie
{
protected :
int x, y;
public:
pozitie(int=0, int=0);
pozitie(pozitie&);
~pozitie();
void afisare();
void deplasare(int,int);
};
- 151 -
- 152 -
char culoare;
public:
// n antetul constructorului se specific parametrii preluai de constructorii claselor de baz
strpoz(int abs, int ord, int n=0, char c='A') : pozitie(abs, ord), string(n)
{
culoare=c;
cout<<"\nConstructor 1 - strpoz";
afisare();
}
strpoz(int abs, int ord, char *s, char c='A'):pozitie(abs, ord), string(s)
{
culoare=c;
cout<<"\nConstructor 2 - strpoz";
afisare();
}
strpoz(strpoz &sp) : pozitie(sp), string(sp)
// parametrul preluat de constructorii
// claselor de baz este chiar sp pentru
// care se face conversia implicit ctre
// clasa de baz respectiv
- 153 -
Programul afieaz:
Constructor pozitie
pozitie: x=5 y=5
Constructor 2 - string
string : TEXT
Constructor 2 strpoz
strpoz: TEXT
x=5 y=5
- 154 -
Constructor 2 string
string: aaa
Constructor 2 string
string: bbb
Constructor 1 string
string:
Destructor string
string: aaabbb
string: aaabbb
Destructor - strpoz
strpoz : TEXTTEXT
- 155 -
strpoz:TEXTTEXT
x=10 y=10
culoare:A
Destructor - strpoz
strpoz : TEXTTEXT
x=10 y=10
culoare: A
Destructor string
string: TEXTTEXT
Destructor pozitie
pozitie: x=10 y=10
Destructor string
string:aaabbb
Destructor string
apelndu-se
string:bbb
Destructor string
string:aaa
Destructor strpoz
strpoz:TEXT
x=5 y=5
culoare=A
Destructor string
string:TEXT
Destructor pozitie
pozitie: x=5 x=5
Destructor strpoz
strpoz:TEXT
x=5 y=5
culoare=A
Destructor string
string:TEXT
Destructor pozitie
pozitie: x=5 x=5
- 156 -
Exerciiu:
S se defineasc o clas derivat produs care descrie un produs prin
denumire, cod, pre. Se vor folosi o clas de baz string pentru membrul
denumire i o clas care definete codul prin trei grupe de caractere. Se vor
realiza cele dou variante de derivare, i anume o ierarhie simpl de clase i,
respectiv, derivarea multipl.
- 157 -
Lucrarea nr. 10
Clase virtuale
n situaia unei derivri multiple, n lista claselor de baz se pot regsi
clase, derivate din aceeai clas de baz. Problema care apare este faptul c noua
clas obinut va conine membri duplicai. Acetia pot fi referii folosindu-se
operatorul de rezoluie ::.
De exemplu, se consider situaia:
class Baza { protected x ;};
class B1: public Baza {};
class B2 : public Baza {};
class D: public B1, public B2 {};
Clasa D conine doi membri x. Cel care provine din clasa B1 se poate
referi sub forma:
Baza::B1::x
iar cel care provine din clasa B2 sub forma:
Baza::B2::x
De obicei aceast duplicare nu este necesar. Pentru a prelua membrul
neduplicat, se declar clasa Baza virtual n declaraiile claselor B1 i B2.
class Baza { protected x ;};
class B1: public virtual Baza {};
class B2 : public virtual Baza {};
class D: public B1, public B2 {};
Rezultatul utilizrii cuvntului cheie virtual este faptul c n clasa
derivat D se va include un singur membru x. Declararea clasei Baza virtual nu
- 158 -
- 159 -
{
protected:
float latura;
public:
patrat(int abs, int ord, int l) : poz(abs, ord)
{
cout<<"\nConstructor patrat";
latura=l;
}
void afisare()
{
cout<<"\nx="<<x<<" y="<<y;
cout<<"\nlatura="<<latura;
}
};
class fig : public cerc, public patrat
// se declar clasa fig derivat din cerc i
{
// patrat
public:
// la definirea constructorului se specific parametrii preluai de constructorii claselor de baz
fig(int abs, int ord, float dim) : cerc(abs, ord, dim/2.): patrat(abs, ord, dim)
{
cout<<"\nConstructor fig";
}
void afisare()
{
cout<<"\nx="<<cerc::x<<" y="<<cerc::y;
cout<<"\nx="<<patrat::x<<" y="<<patrat::y;
cout<<"\nraza="<<raza<<" latura="<<latura;
}
};
void main()
{
fig f(5, 10, 25);
f.afisare();
}
- 160 -
- 161 -
fr a genera erori.
La execuia programului se va afia:
Constructor poz
Constructor cerc
Constructor patrat
Constructor fig
x=5 y=10
raza=12.5 latura=25
Funcii virtuale
Aa cum s-a artat n lucrarea anterioar, ntre o clas derivat i clasa de
baz se admite o anumit compatibilitate n sensul conversiei de la clasa derivat
spre cea de baz, nu i invers. Conversiile implicite sunt acceptate att pentru
obiecte de tip clas derivat, ct i pentru referine sau pointeri ai acestora.
Presupunem c avem o clas de baz, B i clasele derivate D1, D2, D3,
, care redefinesc o metod M. Se pune problema modului n care compilatorul
identific corect care metod va fi apelat. n situaia utilizrii operatorului de
scop (un apel de forma B::M()) sau apelului cu ajutorul obiectului asupra cruia
se aplic metoda ( de exemplu o exprimare de forma: D1 d; d.M();), decizia este
simpl i este luat n faza de compilare. n acest caz este vorba despre legtura
static (n terminologia englez early binding). Exist ns situaii n care un
pointer la clasa de baz poate primi pe parcursul execuiei programului ca
valoare adrese de obiecte de tip clas derivat sau clas de baz, ceea ce
presupune luarea unei decizii n privina metodei care se apeleaz chiar n timpul
execuiei programului. Acest mod de lucru se numete legtur dinamic (late
binding). Funciile membre pentru care se realizeaz legtura dinamic se
numesc funcii virtuale i se declar cu ajutorul cuvntului cheie virtual.
Redefinirea cu acelai prototip n ntreaga ierarhie de clase a unei funcii
declarat virtual n clasa de baz, se supune legturii dinamice. Funciile
virtuale au urmtoarele proprieti:
- sunt funcii membre nestatice ale unei clase;
- redefinirea funciei virtuale se face cu respectarea prototipului;
- redefinirea funciei virtuale n clasele derivate nu este obligatorie;
- redefinirea unei funcii virtuale cu schimbarea prototipului, are ca efect
- 162 -
- 163 -
- 164 -
p_poz=p_car;
p_poz->afisare();
p_poz->deplasare(3, 3);
Programul afieaz:
Constructor pozitie: 0xfff0
Constructor pozitie: 0xffe6
Constructor punct: 0xffe6
Constructor pozitie: 0xffd8
Constructor punct: 0xffd8
Constructor caracter:0xffd8
x=1
x=2
x=2
x=3
x=3
x=3
Pozitie: 0xfff0
x=1
y=1
Deplasare poz:
Pozitie: 0xfff0
x=1
y=1
y=1
y=2
y=2
y=3
y=3
y=3
culoare=1
vizibil=0
culoare=1
culoare=1
vizibil=0
vizibil=0 caracter=*
- 165 -
x=2
y=2
culoare=1
vizibil=0
Deplasare punct:
Punct: 0xffe6
x=3
y=3
culoare=1
vizibil=0
Caracter:0xffd8
x=3
y=3
culoare=1
vizibil=0 caracter=*
Deplasare caracter:
Caracter:0xffd8
x=8
y=8
culoare=1
vizibil=0 caracter=*
// Se poate observa c, dei p_poz este definit ca pointer la poz, el conine adresa unui obiect
// punct, deci, datorit faptului c funcia afisare() este virtual, se va apela definiia funciei
// corespunztoare clasei punct
Punct: 0xffe6
x=5 y=5 culoare=1
vizibil=0
// Funcia deplasare() nu este virtual, deci se va apela definiia funciei corespunztoare
// clasei poz, dar funcia afisare() apelat din interiorul acesteia este corect apelat
Deplasare poz:
Punct: 0xffe6
x=8 y=8 culoare=1
vizibil=0
// Se poate observa c, dei p_poz este definit ca pointer la poz, el conine adresa unui obiect
// caracter, deci, datorit faptului c funcia afisare() este virtual, se va apela definiia funciei
// corespunztoare clasei caracter
Caracter:0xffd8
x=8 y=8 culoare=3
vizibil=0 caracter=*
// Funcia deplasare() nu este virtual, deci se va apela definiia funciei corespunztoare
// clasei poz, dar funcia afisare() apelat din interiorul acesteia este corect apelat
Deplasare poz:
Caracter:0xffd8
x=11 y=11 culoare=3
vizibil=0 caracter=*
- 166 -
x=5
y=5
culoare=1
vizibil=0
Deplasare punct:
Punct: 0xffe6
x=8
y=8
culoare=1
vizibil=0
Caracter:0xffd8
x=8
y=8
culoare=3
vizibil=0 caracter=*
Deplasare caracter:
Caracter:0xffd8
vizibil=0 caracter=*
Pentru secvena:
- 167 -
se va afia:
Caracter:0xffd8
x=8
y=8
culoare=3
vizibil=0 caracter=*
Deplasare punct:
Caracter:0xffd8
vizibil=0 caracter=*
vizibil=0 caracter=*
- 168 -