Vous êtes sur la page 1sur 138

Universitatea Stefan cel Mare Suceava Facultatea de Stiinte Economice si Administratie Public Specializarea : Informatic Economic

Curs Programarea Orientat Obiect

2010 - 2011

1. Redactarea programelor C
1.1. Generaliti
Mediul Borland C a fost extins la Visual C i C++ Builder, adaptate programrii orientate obiect i interfeei grafice Windows 95. Limbajul C a fost extins la C++ permind aplicarea conceptelor programrii prin abstractizarea datelor i programrii orientate spre obiecte. Fiierele surs pot avea extensia C, CP, sau CPP.

1.2. Structura unui program


Un program C este conine o funcie principal (main) i eventual alte funcii secundare, apelate de ctre funcia principal, situate la acelai nivel (far imbricare). Structura unui program este urmtoarea: Directive de procesare, Declaraii de date globale, Declaraii de funcii, sau doar [ Antete de funcii (prototipuri) ] Funcia principal; [ Descrierea funciilor (implementri) ] Se observ c descrierea funciilor se poate face fie n ntregime naintea funciei main fie doar prototipul nainte, iar corpul dup aceasta. Comentariile se scriu ntre caracterele /* i */ ( ... /* comentariu */ ... ), sau la nivelul unui rnd dup caracterele // ( ... // comentariu ). nainte de compilare, un program este precompilat, de ctre un preprocesor, care permite includerea unor fiier surs, definirea i apelul unror macrouri, precum i o compilare condiionat. Includerea unui fiier surs (*.h sau *.c) se realizeaz prin directiva include astfel: sau Exemplu: # include specificator_fiier # include <specificator_fiier> #include <stdio.h>; #include <iostream.h>; // pentru fiiere utilizator // pentru fiiere standard // Standard Input Output Header // Console Input, Console Output

Constantele simbolice se definesc cu ajutorul directivei define astfel: #define Nume_constant ir_caractere Exemplu: #define Pi 3.141592 // nlocuiete Pi cu 3.141592 O constant simbolic poate fi redefinit sau anulat (#undef Nume_constant).

1.3. Funcii
O funcie este format dintr-un antet i un bloc (corp). Ea poate fi apelat dac a fost definit n ntregime sau doar antetul su. Antetul unei funcii are urmtorul format: Tip Nume (List_parametri_formali) unde:

Tip este tipul valorilor funciei (codomeniul); Nume este un identificator (liter urmat eventual de alte litere sau cifre); List_parametri_formali conine parametrii formali separai prin ,.

Exemplu: int Min (int a, int b) { if (a<b) return a; else return b; } Observaie. Prototipul unei funcii este antetul acesteia urmat de ; . Corpul unei funcii are urmtoarea structur: { Declaraii Instruciuni } Exemple: int Cmmdc(int a, int b) { if (b= =0) return a; else return Cmmdc(b,a % b); } int cmmdc(int a, int b) { int rest; do { rest=a%b; a=b; b=rest; } while (rest!=0); return a; } // Cmmdc(a,b) // Cmmdc(b,a Mod b); // cmmdc(a,b)

// rest 0;

1.4. Elementele limbajului


Alfabetul limbajului C este format din litere mari i mici, cifre i caractere speciale (\n=CrLf, \t=Tab). Identificatorii sunt formai din liter_ urmat eventual de litere_ sau cifre (caracterul _ poate fi utilizat pe post de liter). Exist cuvinte cheie care pot fi utilizate doar n contextul definit (de exemplu case, float, int, long, return, short, static, structure, switch, union, unsigned, void ). Tipurile predefinite sunt urmtoarele:

int (Z [-215,215-1]), short (Z [-215,215-1]), long (Z [-231,231-1]), unsigned (N [0,216-1]), float (Q* [-3.410-38, 3.41038]),

double (Q* [-1.710-308, 1.710308]), char (cod ASCII). Constantele numerice pot fi zecimale (123, 123Long, 111long), octale (077), hexa (0xabba, 0Xfac), sau flotante (2.71828, 6.023e23, 6.023E23). Constantele de tip caracter pot fi afiabile ('A', '0', '"') sau funcionale ('\b'=Backspace, '\r'=Return, '\n'=Newline, '\''=Apostrof, '\\'=Backslash, '\v'=Verticaltab, '\f'=Salt de pagin, '\0'=Null. Constantele de tip ir de caractere se scriu ntre ghilimele ("Mesaj"). Declararea variabilelor simple se face astfel: Tip List_identificatori_de_variabile; Exemplu: int i, j; float x,y; char c;

Declararea unui tablou se realizeaz astfel: Tip Nume_Tablou [d1] [d 2] ... [di] ... [dn]; Exemple: float x[100]; int a[2,2]; x[0]=1; ... x[99]=100; a[0][0]=1; a[1][0]=3; a[0][1]=2; a[1][1]=4; // x este pointer la primul element // a conine adresa tabloului // indicele ki: 0 ki<di

2. Variabile
Variabilele pot fi statice sau dinamice, locale sau globale.

2.1. Variabile globale


Declararea unei variabile globale se face la nceputul unui fiier surs (n afara tuturor funciilor) i poate fi referit pn la sfritul programului (n orice funcie). Utilizarea lor n alte fiiere surs se poate face doar dac acestea sunt declarate ca variabile externe: extern declaraie_variabil Exemplu: VExterne.Cpp: #include <stdio.h>; #include "Fs.h"; float Pi=3.14; // variabil global void main (void) { float r; printf(" Dati raza cercului : "); scanf("%f",&r); printf(" Lungimea cercului = %f \n",LungC(r)); scanf ("\n"); } Fs.h: float LungC (float r) { extern float Pi; return 2*Pi*r; } // variabil extern

2.2. Variabile locale


O variabil local este utilizabil (vizibil) doar n modulul sau n funcia n care a fost definit, putnd fi alocat dinamic (variabil automatic, alocat pe stiv) sau static (variabil static, alocat n zona de memorie a programului). Implicit o variabil local este automatic, iar dac dorim ca aceasta s fie static, declaraia ei trebuie s fie precedat de cuvntul cheie static: static declaraie_variabil Funciile au implicit atributul extern, deci pot fi apelate din alte fiiere surs, dar dac dorim ca acest apel s nu fie permis, atunci se vor declara statice prin scrierea cuvntului cheie static naintea antetului acesteia ( static antet_funcie ) ?!.

Exemplu: VLocale.Cpp: #include <stdio.h>; #include "Sursa.h"; void main (void) { int n; printf(" Dati un numar < 256 : "); scanf("%d",&n); printf(" Valoarea in Hexa este "); Print_Hexa(n); // Print_Byte(n/256); Print_Byte(n%256); !? scanf ("\n"); } Sursa.h: static int Cifra_Hexa (int s) { static int c; if (s<10) c=s+'0'; else c=s+'A'-10; // c=s+'0'+7 return c; } static void Print_Byte(int b) { static int H = b / 16; static int h = b % 16; printf("%c%c",Cifra_Hexa(H),Cifra_Hexa(h)); } void Print_Hexa(int z) { static int HH = z / 256; Print_Byte(HH); static int hh = z % 256; Print_Byte(hh); }

2.3. Variabile de tip registru


Exist posibilitatea ca ntr-un registru liber s fie alocat o variabil care este utilizat frecvent, penntru a mri viteza de execuie. n registrii se pot memora parametri funciilor sau variabile automatice de tip int, char sau pointer. Pentru ca o variabil s fie memorat ntr-un registru, declaraia ei trebuie s fie precedat de cuvntul cheie register: register declaraie_variabil Exemplu: float f ( register int i ); { register int n; register char c; ... }

2.4. Iniializarea variabilelor


Variabilele simple se iniializeaz printr-o declaraie de forma: Tip Identificator_de_variabil = Expresie Exemple: float f ( int n ); { int i=1; int m=n/2; ... }

Tablourile se iniializeaz printr-o declaraie de forma: Tip Ident_tablou [n] = {Expresie1, Expresie2,..., Expresiem} unde mn, iar dac n este omis, atunci n=m. Exemple: int X [13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; int Y [ ] = {1,2,3,4,5,6,7}; int A[3][ ] = { {1,2,3},{4,5},{6} }; // {{1,2,3},{4,5,?},{6,?,?}}

irurile de caractere se iniializeaz astfel: char Ident_string [n] = "ir_caractere" iar n poate fi este omis. Exemple: char Mesaj [100] = "Zarurile vor fi aruncate ..."; char Alt_Mesaj [] = {"Zarurile au fost aruncate !"};

3. Expresii
O expresie este format din operanzi, operatori i paranteze pentru prioritate, i are o valoare i un tip. Asocierea operatorilor se face de la stnga la dreapta, cu excepia operatorilor unari i de atribuire, care se asociaz de la dreapta la stnga. Operanzii pot fi: constante, constante simbolice, variabile simple sau structurate (tablouri, structuri, sau elemente ale acestora), funcii sau apeluri de funcii.

3.1. Operatori
Operatorii, n ordinea descresctoare a prioritii sunt urmtorii:

( ) (unar) + (unar) * / + << >> < <= == != & ^ | && || ?: (ternar) = *= ,

[ ] * (unar) & (unar) % >= >

++

(tip) sizeof

/=

%=

+=

= <<= >>= &=

^=

|=

Operatorii aritmetici sunt urmtorii: + , , * , / , % (mod), pentru adunare, scdere, nmulire, ct (mprire), rest. Exemple: int i, j ; int cat = i / j; int rest = i % j; // 13 / 5 = 2 // 13%5 = 3

Operatorii relaionali sunt urmtorii: < , <= , > , >= , == , != , pentru < , , > , , = , , rezultatul (valoarea expresiei relaionale) fiind 1 pentru adevrat, iar 0 pentru fals. Exemple: int i=1; int j=2 ; ... i<=j ... ... i==j ... Operatorii logici sunt: ! (Not) , && (And) , | | (Or). Exemplu: Xor = !x&&y || x&&!y // x Xor y = Not x And y Or x And Not y // == 1 // == 0

Deoarece nu exist tipul boolean, valoarea fals este reprezentat prin 0, iar adevrat prin orice valoare diferit de 0. Operaii pe bii se pot realiza utiliznd urmtorii operatori: ~ (complementul fa de FFFF, schimb fiecare bit), << (deplasare la stnga), >> (deplasare la dreapta), & (And bit cu bit), ^ (Xor bit cu bit), | (Or bit cu bit). Exemplu: // ASCII #include <stdio.h>; #include <conio.h>; int Cifra(int c) // cifra hexa: 01...9AB...F { if (c<10) return c | '0'; else return (c-9) | '@'; } int c; void main (void) { textbackground(BLUE); textcolor(WHITE); clrscr(); do { printf(" Dati un caracter #Esc : "); c=getch(); printf(" ... Hexa = %c%c \n",Cifra(c>>4),Cifra(c&0xF)); } while (c!=0x1B); }

Operaia de atribuire se realizeaz astfel: Var = Expresie; // expresie de atribuire cu tipul Var Exist posibilitatea realizrii de atribuiri multiple prin expresii de forma: Varn = ... = Var2 = Var1 = Expresie; Mai exist o facilitate utiliznd o operaie de atribuire de forma: Var = Expresie; avnd semnificaia: Var = Var Expresie; Exemple: v = e = 2.7181828; x += dx; y = dy; n <<= k; // v = (e = 2.7181828); // x = x+dx; y = y dy; // n = n*2k // unde {+, , *, /,%, &, ^, | , <<, >>}

Operatorii de incrementare / decrementare sunt ++ respectiv prin care se mrete, respectiv se micoreaz, valoarea operandului cu unu. Acetia pot fi utilizai:
n

forma prefixat: ++ operand ; respectiv operand ; respectiv operand ; // valoarea expresiei, dup aplicarea lor // valoarea expresiei, nainte de aplicare forma postfixat: operand ++;

Exemple: a = ++b; a = b ; // b=b+1; // a=b; a=b; b=b 1;

Operatorul de conversie explicit (expresie cast) realizeaz conversia unui operand ntr-un tip precizat astfel: ( Tip ) operand ; Exemplu: int a=12; int b=5; float c=a/b; printf(" a Div b = %5.2f \n", c); c=(float)a/b; printf(" a / b = %5.2f \n", c); // a Div b = 2.00 // a / b = 2.40

10

Conversiile implicite (realizate automat) se fac astfel:


a) b) c) d) e)

charint, floatdouble, (double,*)(double,double)=double, (long,*)(long,long)=long, (unsigned,*)(unsigned,unsigned)=unsigned.

Operatorul pentru dimensiune (sizeof) determin lungimea n octei a unei variabile simple sau structurate, precum i a unui tip de dat: sizeof ( Data) ; Exemplu: int a; printf(" SizeOf int = %d \n", sizeof(a)); // SizeOf int = 2 printf(" SizeOf short = %d \n", sizeof(short)); // SizeOf short =2

Operatorii condiionali ?

: sunt utilizai n construcii de forma: : Expresie3


;

Expresie1 ? Expresie2

Valoarea expresiei rezultat este Expresie2 dac Expresie1 este nenul, altfel este Expresie3 . Exemplu: Max = a>b ? a : b; // Dac a>b Atunci Max=a Altfel Max=b;

Operatorul virgul permite gruparea mai multor expresii ntr-una singur, aceasta avnd valoarea ultimei expresii: Expresie1 , Expresie2 , ... Exemplu: float x0,y0,r, x, y; printf(" Dati C(x0,y0,r) = "); scanf("%f %f %f",&x0,&y0,&r); // Cercul C printf(" Dati P(x,y) = "); scanf("%f %f", &x, &y ); // Punctul P printf(" %s",((x-=x0, y-=y0, x*=x, y*=y, x+y)==r*r) ? "P e pe C" : "P nu e pe C");

, Expresien ;

11

4.

Operaii de intrare/ieire

n limbajul C nu exist instruciuni de intrare/ieire, aceste operaii ralizndu-se prin funcii aflate n bibliotecile standard. Implicit, unui program i se ataeaz fiierele stdin (intrare standard), stdout (ieire standard ), stderr (ieire standard pentru erori), stprn (ieire pentru imprimant), stdoux (intrare/ieire serial).

4.1. Funcia Printf


Aceast funcie realizeaz afiarea dup un ablon, avnd urmtorul format: int printf (Control [, List_Expresii]); unde Control este ablonul (formatul) scris sub forma unui ir de caractere care conine mesaje i specificatori de format corespunztori valorile expresiilor din list. Un specificator de format se descrie astfel:
% [] [m[.n] ] [l]

[f]

unde:

[] [m] [.n] [ l] [f]

- determin alinierea la stnga, implicit fiind la dreapta, - precizeaz lungimea cmpului,


- precizeaz lungimea prii zecimale, respectiv numrul de caractere,

- conversia se va efectua din format intern long, - determin tipul conversiei precizat prin unul din urmtoarele caractere:

d o x X u c s f e E g G

- int zecimal extern, - int octal extern, - int hexa extern (0...9,a...f), - int Hexa extern (0...9,A...F), - unsigned zecimal extern (fr semn), - binar intern caracter (char), - string (ir de coduri ASCII terminat cu \0=NUL) ir de caractere, - float sau double zecimal extern [m[.n] ], implicit n=6, - float sau double zecimal extern forma exponenial (b*10e), - float sau double zecimal extern forma exponenial (b*10E), - se alege dintre variantele f sau e reprezentarea minim, - se alege dintre variantele f sau E reprezentarea minim.

Funcia printf returneaz numrul de octei afiai dac operaia a decurs corect, iar n caz contrar -1 (EOF): if (EOF = = printf (Control , List_Expresii )) ... eroare ... ;

12

Exemplu: short Zi=1; char Luna[]="Ianuarie"; unsigned An=2003; float Ina=1.8; printf(" Zi:%d, Luna:%3.3s., An:%u \n",Zi,Luna,An); // Zi:1, Luna:Ian., An:2003 printf(" Inaltime(m):%4.2f \n",Ina); // Inaltime(m):1.80

4.2. Funcia Scanf


Aceast funcie realizeaz citirea datelor dup un ablon, avnd urmtorul format: int scanf (Control , List_Adrese_de_Variabile ); unde Control este ablonul (formatul) scris sub forma unui ir de caractere care conine eventual texte (obligatorii la intrare) i specificatori de format corespunztori tipurilor variabilelor din list. Specificatorii de format sunt asemntori celor prezentai la funcia printf, realiznd ns conversiile inverse:

% [*] [m] [l]

[ f ] , unde:

[*] [m] [ l] [f]

- un caracter opional, - precizeaz lungimea maxim a cmpului, - conversia se va efectua din format intern long, - determin tipul conversiei precizat prin unul din urmtoarele caractere:

d o x X u c s f

- int zecimal extern, - int octal extern, - int hexa extern (0...9,a...f), - int Hexa extern (0...9,A...F), - unsigned zecimal extern (fr semn), - binar intern caracter (char), - string ir de caractere terminat la spaiu sau dimensiunea m, - float flotant extern.
(nu este necesar pentru tablouri).

Adresele variabilelor de intrare sunt date prin operatorul de adrese & plasat naintea identificatorului fiecrei variabile (simple!): [&] Variabil Exemplu: short Zi; char Luna[13]; unsigned An; float Ina; scanf(" %d %s %u %f ", &Zi, Luna, &An, &Ina);
// 1 Ianuarie 2003 1.80

Funcia scanf returneaz numrul de cmpuri citite corect. Sfritul de fiier (Ctrl/Z) poate fi verificat prin valoarea returnat EOF: if (EOF = = scanf (Control , List_Expresii)) ... Sfrit ... ; Exemplu: if (EOF==scanf(" %d %s %u %f", &Zi, Luna, &An, &Ina)) printf("Ctrl/Z"); else { printf(" Zi:%d, Luna:%3.3s., An:%u \n",Zi,Luna,An); printf(" Inaltime(m):%4.2f \n",Ina); }

13

4.3. Funcia PutChar


Aceast funcie realizeaz tiprirea unui caracter al crui cod ASCII este precizat printr-o expresie: putchar (Expresie);

4.4. Funcia GetChar


Aceasta, returneaz codul ASCII al caracterului citit (pentru Ctrl/Z EOF=-1): getchar ( ); Exemplu: char c; do putchar (((c=getchar())>'Z')? c^' ' : c); while (c!='.');
// Litere mici LITERE MARI // se termin cu .

Litere mici in Litere MARI ! LITERE MICI IN LITERE MARI ! Se termina la . (Punct) SE TERMINA LA . getchar putchar getchar putchar

4.5. Funcia GetCh e


Funcia returneaz codul caracterului citit direct i l afieaz (n ecou): int getche ( ); Exemplu: do putchar (((c=getche())>'Z')? c^' ' : c); while (c!='.');
// se termin cu .

LLiIt TeErReE mMiIcCiI iInN LLiIt TeErReE MMAARRII..

4.6. Funcia GetCh


Aceast funcie returneaz codul caracterului citit (direct) fr ca acesta s mai fie afiat: int getch ( ); Exemplu: do putchar (((c=getch())>'Z')? c^' ' : c); while (c!='.');
// se termin cu .

LITERE MICI IN LITERE MARI. // S-a tastat: Litere mici in Litere MARI.

14

5.

Instruciuni

n limbajul C instruciunile se termin cu ; mai puin cele care se termin cu }.

5.1. Instruciunea Vid


Aceast instruciune se utilizeaz n situaia n care este nescerar prezena unei instruciuni i care nu trebuie s execute nimic:

;
5.2. Instruciunea Expresie
Instruciunea are formatul general: Expresie ; Exemple: y = (x+1)*(x-1); f(x,y); c++; --c;
// Atribuire: v=Expresie ; // Apel de funcie: f(p1, p2,... , pn); // Incrementri/Decrementri (Pre/Post fixate)

5.3. Instruciunea Compus


Aceasta este format dintr-o succesiune de declaraii (proprii) i instruciuni, incluse ntre acolade:

{
Declaraii Instruciuni

}
Exemplu: { int i;
// Variabil local instruciunii; //

f (i); } ;

i se poate utiliza doar n aceast instruciune compus;

// Dup } nu se pune ;

15

5.4. Instruciunea If
Structura alternativ cu una sau dou ramuri poate fi scris astfel: if (expresie) instructiune1; [ else instructiune2; ] Exemplu: P(x,y) I-ul Cadran (Dac x sau y este negativ se schimb semnul ) float x, y; printf(" Dati P(x,y) = "); scanf("%f %f", &x,&y); // Punctul P if (x>0) if (y<0) y=-y; // C4 else_; (instruciunea vid) else { x=-x; // C2 sau C3 (x) if (y<0) y=-y; // C3 (y) } printf(" x=%5.2f, y=%5.2f \n", x,y) ; } // trebuie pus pentru C1 instruciunea vid: else_; {

5.5. Instruciunea Switch


Pentru structura alternativ cu mai multe ramuri Case (Select) se utilizeaz instruciunea Switch: switch (expresie)
{ case c1 : secven instructiuni 1 case c2 : secven instructiuni 2
...

[ break; ] [ break; ]

case cn : secven instructiu nin [ break; ] [ default : secven instructiuni n+1 ]


}

Instruciunea break realizeaz saltul la sfritul instruciunii switch, iar n absena ei se vor executa i urmtoarele secvene de instruciuni. Exemplu: while (scanf("%d %c %d",&o1,&o,&o2)!=EOF) switch (o & 0XFF) { case '+' : v=o1+o2; break; case '-' : v=o1-o2; break; case '*' : v=o1*o2; break; case '/' : v=o1/o2; break; default : printf (" Op. necunoscut!%c\n",o); } printf ("%d%c%d = %d\n",o1,o,o2,v); {
// O1 o O2

// Ctrl/Z

16

Exemplu: // Nr.Zile / lun \\


#include <iostream.h> #include <conio.h> void main (void) { int l,a; cout << " Dati anul : "; cin >> a; cout << " Numar de zile ... " << endl; for (l=1; l<=12; l++) { cout << l << " : "; switch (l) { case 2 : cout << (a&3 ? 28 : 29); break; case 4 : case 6 : case 9 : case 11 : cout << 30 ; break; default : cout << 31 ; } cout << endl; } }

// break; getche();

5.6. Instruciunea While


Structura repetitiv pretestat poate fi scris astfel: while (expresie) instructiu ne; Exemplu: // Program Exemplu While #include <stdio.h>; int i,n; long f; // f:=n! void main (void) { printf("\n Dati n : "); scanf ("%d", &n); i=(f=1)+1; while (i<=n) f*=i++; printf(" %d! = %u \n",n,f); i=(f=1); while (i< n) f*=++i; printf(" %d! = %u \n",n,f); scanf("\n"); }

5.7. Instruciunea Do_While


Structura repetitiv posttestat poate fi scris astfel: do instructiu ne while (expresie); Exemplu: do { r=a%b; a=b; b=r; } while (c); cmmdc=a; // c!=0

17

5.8. Instruciunea For


Structura repetitiv Pentru (!) poate fi descris astfel: for (expresie1; expresie2; expresie3) instructiu ne ; Instruciunea are acelai efect ca i: expresie1; while (expresie2) { instructiu ne; expresie3 ;} i invers (vezi while): for (;expresie;) instructiune ; Exemplu: int i,n; long f; // f:=n! printf("\n Dati n : "); scanf ("%d", &n); f=1; for ( i=1 ; i<=n; i++) f*=i; printf(" %d! = %u \n",n,f); f=1; for ( i=1 ; i<=n; ++i) f*=i; printf(" %d! = %u \n",n,f); f=i=1; for ( ; i<=n; i+=1) f*=i; printf(" %d! = %u \n",n,f); for (f=i=1; i<=n; ) f*=i++; printf(" %d! = %u \n",n,f);

5.9. Instruciunea Break


Aceast instruciune se folosete pentru a termina o structur repetitiv: break; Exemplu: for ( ; ; ) if (expr) break; { ...
... }

5.10. Instruciunea Continue


Aceast instruciune realizeaz saltul la sfritul unei structuri repetitive (pentru while sau do_while la reevaluarea expresiei, iar pentru for la expresie3), avnd formatul: continue; Exemplu: for (... ;... ; expr3) if (expr) continue; { ...
... }

5.11. Instruciunea GoTo


Aceast instruciune realizeaz saltul necondiionat i fr revenire la instruciunea ce poart eticheta specificat, avnd formatul: goto etichet ; Exemplu:

18

while (expr1) if (expr2) goto et;


...

{ ...
... } // instruciune

et: ...

5.12. Apelul unei funcii


Instruciunea de apel a unei funcii este un caz particular al instruciunii expresie: Nume_funcie (List_parametri_actuali); O funcie poate fi apelat i n cadrul unei expresii dintr-o instruciune:
...

Nume_funcie (List_parametri_ actuali) ... ;

O funcie poate fi utilizat doar dac a fost definit sau cel puin a fost declarat prototipul ei ntr-una din urmtoarele moduri: Tip_ funcie b) Tip_ f uncie c) Tip_ f uncie d) Tip_ f uncie
a)

Nume_ funcie (Lista_parametrilor_formali); Nume_ funcie (Lista_tipurilor_parametrilor_formali); Nume_ funcie (Void); // nu sunt parametri formali Nume_ funcie ( ); // nu se fac verificrile de tip

Apelul implicit pentru variabile simple (de baz) este prin valoare, iar pentru tablouri prin referin. Apelul prin referin se obine prin intermediul variabilelor de tip pointer i a operatorului de adres &. Revenirea dintr-o funcie se poate realiza fie prin instruciunea return, fie automat dup ultima instruciune a funciei (situaie n care nu se returneaz nici o valoare): return [ expresie ] ; fiind returnat valoarea expresiei (dac exist). Ex. 1:
#include <graphics.h> #include <math.h> int u1,v1, u2,v2; float a, b, c, d ; int u (float x) { return ((x-a)/(b-a)*(u2-u1)+u1); } int v (float y) { return ((y-d)/(c-d)*(v2-v1)+v1); } void InitGraf(void) { int Gd = DETECT, Gm; initgraph(&Gd, &Gm, "c:\\Bc\\Bgi"); } void ViewPort(int x1,int y1,int x2,int y2) {u1=x1; v1=y1; u2=x2; v2=y2; /*rectangle(u1,v1,u2,v2);*/ } void Window(float x1,float y1,float x2,float y2) { a=x1; d=y1; b=x2; c=y2; } void Rectangle(float x1,float y1,float x2,float y2) { rectangle(u(x1),v(y1),u(x2),v(y2)); } void Bar(float x1,float y1,float x2,float y2) { bar(u(x1),v(y1),u(x2),v(y2)); } void Linie(float x1,float y1,float x2,float y2) { line(u(x1),v(y1),u(x2),v(y2)); } void Muta(float x,float y) { moveto(u(x),v(y)); } void Trag(float x,float y) { lineto(u(x),v(y)); } void Rot(float &x,float &y, float x0, float y0, float Alfa) { float xp; xp=(x-x0)*cos(Alfa)-(y-y0)*sin(Alfa)+x0; y =(x-x0)*sin(Alfa)+(y-y0)*cos(Alfa)+y0; x = xp; }

Ex. 2: // Ultima cifr nenul a lui n! \\


#include <iostream.h>; #include <conio.h>; int Sf (int& f, int k) { int p=0;

19

while (!(f%k)) { f/=k; p++; } return p; } main () { clrscr(); int n; int f2=0; int Uc=1; cout << " n : "; cin >> n; for (int i=2; i<=n; i++) { int f=i; f2+=Sf(f,2); f2-=Sf(f,5); Uc=Uc*f%10; } cout << " Uc= " << Uc*((f2&=3,int(f2?f2*1.4:3))<<1)%10; getch(); }

Ex. 3: // Calc. A B, A B \\
#include <iostream.h>; #include <conio.h>; int Card(int A[]) { return A[0]; } int Apart (int x, int A[]) { for (int i=1; i<=Card(A); i++) if (x==A[i]) return 1; return 0; } void n (int A[], int B[], int C[]) { C[0]=0; for (int i=1; i<=Card(A); i++) if (Apart(A[i],B)) C[++C[0]]=A[i]; } void u (int A[], int B[], int C[]) { int i; for (i=0; i<=Card(B); i++) C[i]=B[i]; for (i=1; i<=Card(A); i++) if (!Apart(A[i],B)) C[++C[0]]=A[i]; } void Tip (char *Mult, int A[]) { int i; cout << Mult << '{' ; for (i=1; i<=Card(A); i++) cout << A[i] << ","; cout << "\b}" << endl; } void main (void) { clrscr(); int A[]={5, 1,3,5,7,9}; Tip (" A : ",A); int B[]={5, 1,2,3,4,5}; Tip (" B : ",B); int AuB[10]; u (A,B,AuB); Tip (" AuB = ",AuB); int AnB[10]; n (A,B,AnB); Tip (" AnB = ",AnB); getche(); }

20

6. Pointeri
O variabil p de tip pointer conine adresa unei variabile a crei valoare se obine utiliznd operatorul * (*p = valoarea variabilei de la adresa coninut n p). Adresa unei variabile v se poate obine prin operatorul & (&v = adresa variabilei v), deci putem atribui unui pointer p adresa unei variabile v astfel: p = &v;

6.1. Declararea unui Pointer


Definirea unei variabile de referin (legat de un Tip) se face astfel: Tip *Var_Referin ; Deci, tipul referin se obine prin urmtoarea construcie: Tip * Declararea unui pointer (care conine o adres nefiind ns legat de un anumit tip) se face astfel: void *Var_Pointer ; Exemplu:
#include <stdio.h>; #include <conio.h>;
#include "Crt.Cpp";

int Cifra(int c) { if (c<10) return c | '0'; else return (c-9)|'@'; } void Cifre(int b) { printf("%c%c",Cifra(b>>4),Cifra(b&0xF)); } void main (void) { int *Pointer_Int; void *p; unsigned *Pointer_Word; int x; printf(" Dati x : "); scanf("%d",&x); p=Pointer_Int=&x; Pointer_Word=(unsigned *) p; printf(" x =%u \n",*Pointer_Word); printf(" |x|=%d \n",sizeof *Pointer_Word); printf(" |&x|=%d \n",sizeof Pointer_Word); printf("*(&x)="); Cifre(*Pointer_Word>>8); Cifre(*Pointer_Word&0xFF); printf("\n"); }
getch();

Date: Rezultate :

Dati x : 43962 x =43962 |x| =2 |&x|=2 *(&x)=ABBA

Date: Dati x : -1 Rezultate : x = 65535

|x| =2 |&x|=2 *(&x)=FFFF

6.2. Operaii cu Pointeri


Aceste operaii sunt operaii cu adresele coninute n variabilele de tip pointer.

21

6.2.1.

Incrementare / Decrementare

Aceste operaii mresc/miocoreaz valoarea de adres spre urmtorul element (cu o valoare egal cu lungimea tipului referit): Var_Pointer + + ; Exemplu:
int Zile[]={31,28,31,30,31,30,31,31,30,31,30,31 }; int *Pointer_Int; int Luna; // 0,1,...,11 printf(" Dati luna (1-12):"); scanf("%d",&Luna); Pointer_Int=&Zile[Luna]; Pointer_Int--; // &Zile[Luna-1] printf(" Nr.Zile =%d \n",*Pointer_Int);

Var_Pointer ;

6.2.2.

Adunare / Scdere a unui numr ntreg

Aceste operaii mresc/miocoreaz valoarea de adres spre alt element (cu o valoare egal cu n lungimea tipului referit). Var_Pointer + n Exemplu:
int Zile[]={0,31,28,31,30,31,30,31,31,30,31,30,31 }; int *Pointer_Int; int Luna; printf(" Luna (1-12) : "); scanf("%d",&Luna); Pointer_Int=Zile+Luna; printf(" Nr.Zile=%d \n",*Pointer_Int); Pointer_Int=Zile; printf(" Nr.Zile=%d \n",*(Pointer_Int+Luna));

6.2.3.

Comparare

Doi pointeri ale elementului aceluiai tablou pot fi comparai utiliznd operatorii relaionali. Valoarea NULL marcheaz faptul c un pointer nu refer nici un element.
... p1

< p2 ... ;

... p1

= = p2 ... ;

... p1

!= p2 ... ;

... p

= = NULL ...;

Exemplu:
int Zile[]={0,31,29,31,30,31,30,31,31,30,31,30,31 }; int *luna; int Zi,Luna,An, NrZile; printf(" Zi, Luna, An : "); scanf("%d %d %d",&Zi,&Luna,&An); if (An&3) Zile[2]=28; if ((Zi>Zile[Luna]) || (Luna>12)) luna=NULL; else luna=Zile; if (luna!=NULL) { NrZile=Zi; do NrZile+=*(luna++); while (luna<Zile+Luna); printf(" A %d zi a anului \n",NrZile); } else printf(" Data calendaristica incorecta! \n");

6.2.4.

Diferen

Diferena a doi pointeri ai aceluiai tablou d ca rezultat diferena indicilor. Exemplu:


int Zile[]={0,31,29,31,30,31,30,31,31,30,31,30,31 }; int *luna; int Zi,Luna,An, Ziua; printf(" An, A cta zi din an:"); scanf("%d %d",&An,&Ziua); if (An&3) Zile[2]=28; for (luna=Zile+1; Ziua>*luna; luna++) Ziua=*luna; printf(" Zi:%d, Luna:%d, An:%d \n",Ziua,lunaZile,An);

22

Exemplu: // Operaii cu pointeri \\


#include <iostream.h> #include <conio.h>

void Tip (int *x, int n) { int *p=x; while ( p-x < n ) cout << *(p++); cout << endl; } void main (void) { int x[]={11,22,33,44,55,66,77}; int *p,*q; p=x; q=&x[7]; while (q-p) cout << *(p++); cout << endl; int &f=x[7]; p=&x[0]; q=&f; while (q>p) cout << *(p++); cout << endl; p=x; while (p-x<7) cout << *(p++); cout << endl; p=x; int n = (sizeof x) / (sizeof (int)); while ( p-x < n ) cout << *(p++); cout << endl; p=x; for (int i=1; i<=n; i++) cout << *(p+i-1); cout << endl; Tip (x,n); }

clrscr();

getche();

6.3. Alocare dinamic a memoriei


Pentru alocarea / dealocarea variabilelor dinamice sunt utilizate urmtoarele dou funcii definite n fiierele alloc.h i stdlib.h: malloc, care returneaz adresa zonei alocate de lungime dat n sau NULL dac nu se poate efectua alocarea: void *malloc (unsigned n);

free, care elibereaz o zon alocat, precizat prin adresa (pointerul) ei : void *free (void *adres);

Exemplu:
#include <stdio.h>; #include <malloc.h>;
#include <conio.h>; int Cifra(int c) void Cifre(int b) #include "Crt.Cpp"; { if (c<10) return c | '0'; else return (c-9)|'@'; } { printf("%c%c",Cifra(b>>4),Cifra(b&0xF)); }

void main (void) { unsigned *Pointer_Word; Pointer_Word=(unsigned *) malloc(sizeof (unsigned)); printf(" Dati x : "); scanf("%d",Pointer_Word); printf(" x =%u \n",*Pointer_Word);

printf(" |x|=%d \n",sizeof *Pointer_Word); printf(" |&x|=%d \n",sizeof Pointer_Word); printf("*(&x)="); Cifre(*Pointer_Word>>8); Cifre(*Pointer_Word&0xFF); printf("\n");

free(Pointer_Word);

getch();

6.4. Pointeri la funcii

23

Numele unei funcii fiind un pointer la acea funcie, ea poate fi parametru actual, i evident trebuie descris ca parametru formal:
...

tip (*f ) ( ), ... // Pointeri la func ii (1) \\

Exemplu:
#include <graphics.h> #include <conio.h> float Sin (float x) float Sqr (float x) #include <stdlib.h> #include <math.h> { return sin (x); } { return pow (x,2);} #include <stdio.h> #include "Graf.h" float Cos (float x) float Sqrt(float x)

#define Pi 3.1415926 { return cos (x); } { return sqrt(x); }

void Grafic(float(*f)(float),float a,float b,int u1,int v1,int u2,int v2) { float x, p, c,d, y; ViewPort (u1,v1,u2,v2); rectangle (u1,v1,u2,v2); p=(b-a)/(u2-u1)*5; x=a; c=d=(*f)(x); do { x+=p; y=(*f)(x); if (y<c) c=y; else if (y>d) d=y; } while (x<b); Window(a,d,b,c); x=a; MoveTo(x,(*f)(x)); do { x+=p; LineTo(x,(*f)(x)); } while (x<b);
} {

void main(void)

getch(); closegraph(); }

Grafic (Sin, -Pi,Pi,10,10, (int) getmaxx()/2-5, (int) getmaxy()/2-5); Grafic (Cos, -Pi,Pi,(int) getmaxx()/2+5,10,getmaxx()-10, (int) getmaxy()/2-5); Grafic (Sqr, -Pi,Pi,10,(int) getmaxy()/2+5, (int) getmaxx()/2-5, getmaxy()-10); Grafic (Sqrt, 0,Pi,(int) getmaxx()/2+5,(int) getmaxy()/2+5,getmaxx()-10, getmaxy()-10);

InitGraph ();

Urmtorul exemplu construiete un tabel cu valorile a patru funcii dintr-un interval dat [a,b] pentru o diviziune precizat (n): // Pointeri la func ii (2) \\
#include #include #include #include <iostream.h> <stdio.h> <conio.h> <math.h>

double X(double x) { return x; } typedef double (*Pointer_la_Functie)(double); Pointer_la_Functie Functia[] = { X, sin, char* Functii = {" x Sin int Nr_Functii=3; void main(void) { double a,x,b; int n; cout << " Dati a,b, n : "; cin >> a >> b >> n; cout << Functii << endl << endl; for (int i=0; i<=n; i++) { x=a+(b-a)/n*i; for (int j=0; j<=Nr_Functii; j++) printf ("%7.2f",(*Functia[j])(x)); cout << endl; } }

cos, Cos

tan }; Tg "};

clrscr(); clrscr();

getch();

24

6.5. Utilizarea parametrilor din linia de comand


Apelul unui program poate fi nsoit de o list de parametri: > Nume_Program List_Parametri care se poate accesa scriind antetul funciei principale astfel: main ( int ArgC, char *ArgV [ ] ) unde: ArgC este o variabil ntreag care conine numrul de parametri plus unu (!), ArgV este un tablou care conine adresele parametrilor din list: ArgV[0] - pointer la Nume_Program (!), ArgV[1] - pointer la primul parametru, ... ArgV[ArgC-1] - pointer la ultimul parametru Exemplu:
#include <stdio.h>; #include <stdlib .h>; // Calendar 2003

void main (int ArgC, char *ArgV[]) { char *Sapt[]={"Luni","Marti","Miercuri","Joi","Vineri","Sambata","Duminica"}; int Zile[]={31,28,31,30,31,30,31,31,30,31,30,31};int Zi,Luna,luna; if (ArgC==3) { Zi=atoi(ArgV[1]); Luna=atoi(ArgV[2]); for (luna=1; luna<Luna; luna++) Zi+=Zile[luna-1]; printf(" %s \n",Sapt[(Zi+1)%7]);
}

else printf (" Dati in linia de comada ziua si luna (din 2003) ! \n");
} //

>Calendar 15 3

6.6. Declararea c o n s t antelor


O alt modalitate de a defini o constant este modificatorul Const astfel:

[ Tip ] const Nume [ =

Valoare ] ;

sau

const [ Tip ] Nume [ = Valoare ] ;

Unui parametru formal declarat cu modificatorul Const nu i se mai poate schimba valoarea n subprogramul respectiv. Exemplu:
#include <stdio.h>; #include <conio.h>;

int Cifra(const int c) { const char Zero='0'; if (c<10) return c | Zero;


}

int const C40H=0x40; else return (c-9)|C40H;

void main (void) { const Blue=BLUE; const White=WHITE; const C0F=0xF; const Esc=0x1B; int c; textbackground(Blue); textcolor(White); clrscr(); do { printf(" Dati un caracter #Esc : "); c=getch(); printf(" ... Hexa = %c%c \n",Cifra(c>>4),Cifra(c& C0F)); } while (c!=Esc);
}

6 . 7 . S t i va

25

Prin stiv nelegem o list cu disciplina Last In First Out pentru care vom defini urmtoarele trei funcii: Push - adaug un element n stiv, Pop - extrage un element din stiv, Clear - iniializarea stivei (stiv vid), Vida - verific dac stiva este vid: // Fact.Cpp \\
#include <stdio.h> #include <conio.h> #include "Stiva.h" void main(void)
{

// Stiva.h \\
#define DimMax 13 static int Stiva[DimMax]; void Push(int x)
{

static Next=0;

int n; unsigned long f; printf(" Dati n : "); scanf("%d",&n); Clear(); while (n) Push(n--); f=1; while (!Vida()) f*=Pop(); printf(" n! = %15lu \n",f); getch();
}

if (Next<DimMax) Stiva[Next++]=x; else printf(" Depasire stiva \n");


}

int Pop() { if (Next>0) return Stiva[--Next]; else { printf(" Stiva vida \n"); return 0; }
}

void Clear() int Vida()

{ Next=0; } {

return (Next= =0); }

7. Recursiviate
Exist posibilitatea de a defini o funcie prin ea nsi (recursiv). Exemplu:
#include <conio.h> #include <iostream.h> #define Max (x,y) (x>y ? x : y) int a[100]; int Maxim(int n)
{ } {

if (n= =1) return a[1]; else return Max (Maxim(n-1),a[n]); int i,n; clrscr();

void main(void) cout << " Dati n : "; cin >> n; cout << " Dati A : "; for (i=1; i<=n; i++) cin >> a[i]; cout << " Max.= " << Maxim(n); getch();

26

8. Tipuri de date
Exist posibilitatea de a defini noi tipuri de date i chiar de a le denumi.

8.1. Definirea unui tip de dat (typedef )


Asignarea unei denumiri unui tip de dat se realizeaz astfel: typedef Exemplu: typedef int Integer ; Integer i,j; typedef float Real ; Real X[10]; tip Denumire_Tip ;

8.2. Tipul enumerare (enum )


Definirea acestui tip se face astfel: enum [Denumire] { Id0 [=Expr0], Id1[=Expr1],..., Idn[=Exprn] } [List_Var]; Implicit Expr0=0, iar Expri=Expri-1+1, iar dac se declar o list de variabile avnd acest tip atunci denumirea tipului enumerare definit poate lipsi. Exemplu:
#include <stdio.h>; // 2003 \\ #include <conio.h>; enum { False, True } Zi_Lucratoare; enum ZileSapt { Luni, Marti, Miercuri, Joi, Vineri, Sambata, Duminica }; enum ZileSapt Zi_Sapt; // sau ZileSapt Zi_Sapt; void main (void)
{

int Zile[]={31,28,31,30,31,30,31,31,30,31,30,31}; int Zi,Luna,luna; printf(" Zi, Luna : "); scanf("%d %d",&Zi,&Luna); for (luna=1; luna<Luna; luna++) Zi+=Zile[luna-1]; Zi_Sapt=Luni; Zi=(Zi+1)%7; while (Zi--) Zi_Sapt++; if (Zi_Sapt<Sambata) Zi_Lucratoare=True; else Zi_Lucratoare=False; if (Zi_Lucratoare) printf(" Este o zi lucratoare \n"); else printf(" Este o zi libera \n"); getch();
}

// sau Zi_Sapt=Zi_Sapt+1;

27

8.3. Definirea unei structuri (struct )


Definirea unei structuri (nregistrri) se face astfel: struct [Denumire] { List_Declaraii_Cmpuri } [List_Var]; Dac se declar o list de variabile avnd acest tip atunci denumirea structurii poate lipsi. Referirea componentelor unei structuri se face astfel: Denumire. Component; Exemplu:
#include <stdio.h>; #include <conio.h>; typedef float Real; struct Punct { Real x, y; }; struct Cerc { Punct Centru; Real Raza; }; Real Sqr(Real x) { return x*x; } void main (void)
{

Punct O = { 0, 0 }; Cerc C; printf(" \n Cerc : "); scanf("%f %f %f",&C.Centru.x,&C.Centru.y,&C.Raza); printf(" \n C(x0,y0,r)= %5.2f %5.2f %5.2f",C.Centru.x,C.Centru.y,C.Raza); if (Sqr(C.Centru.x-O.x)+Sqr(C.Centru.y-O.y)<=Sqr(C.Raza)) printf(" \n C contine O"); else printf(" \n C nu cont.O"); getch();
}

Referirea componentelor unei structuri definit printr-o variabil de tip referin (pointer) se efectueaz: ( *Var_Ref ). Component; Exemplu:
...

sau

Var_Ref >Component;

struct Cerc { float x, y; float Raza; }; void TipCerc( Cerc *C) { printf(" \n C(x,y,r)= %5.2f %5.2f %5.2f", ( * C).x, ( * C).y, C > Raza) ; } void main (void) { Cerc C={1,2,3}; TipCerc(&C); }

28

8.4. Redefinirea unei date ( union )


Redefinirea unei zone de memorie se poate face n cadrul unei uniuni astfel: union [Denumire] { List_Declaraii } [List_Var]; Toate componentele aflate n List_Declaraii ocum aceeai zon de memorie (se suprapun), lungimea uniunii fiind dat de maximul lungimilor declaraiilor . Referirea componentelor unei uniuni se face astfel: Denumire. Component; sau pentru o variabil de tip referin: ( *Var_Ref ). Component; Exemplu:
...

sau

Var_Ref >Component;

union U { float Real; long unsigned Hexa; } x;


int Cifra(int c) void Cifre(int b) void Print(unsigned x) { if (c<10) return c|'0'; else return (c-9)|'@'; } { printf("%c%c",Cifra(b>>4),Cifra(b&0xF)); } { Cifre(x>>8); Cifre(x&0xFF); }

void main (void)


{

do { printf(" Dati un numar : "); scanf("%f",&x.Real); printf(" ... Hexa = "); Print (x.Hexa>>16); Print(x.Hexa&0xFFFF); printf(" ... \n"); } while (x.Hexa!=0); getch();

8.5. Cmpuri de biti


Exist posibilitatea definirii unei structuri ale crei cmpuri s fie formate dintr-o secven de bii consecutivi (ai unui cuvnt). Aceste cmpuri au tipul unsigned avnd fiecare o lungime precizat (n numr de bii): struct [Denumire] { Cmp0; Cmp1; ... ; Cmpn; } [List_Var]; unde cmpurile Cmpi sunt de forma: unsigned [ Nume_Cmpi ] : Lungimei Exemplu:
#include <stdio.h>;

struct Camp_Biti { unsigned B__0__3 : 4; unsigned B__4__7 : 4; unsigned B__8_11 : 4; unsigned B_12_15 : 4; }; union { int Intreg; Camp_Biti Cifre_Hexa; } x ;
void Cifra(int c) { if (c<10) printf ("%c",c|'0'); else printf ("%c",(c-9)|'@'); }

void main (void) { do { printf(" Dati un numar : "); scanf("%d",&x.Intreg); printf("Hexa="); Cifra(x.Cifre_Hexa.B__0__3); Cifra(x.Cifre_Hexa.B__4__7); Cifra(x.Cifre_Hexa.B__8_11); Cifra(x.Cifre_Hexa.B_12_15); printf(" \n"); } while (x.Intreg!=0);
}

29

9. Structuri de date dinamice


Pentru a implementa structura liniar (lista simplu nlnuit) i structura de tip arbore binar vom apela la structuri definite recursiv.

9.1. List simplu nlnuit ordonat


Considerm o list nevid fiind format din primul element i sublista aflat la adresa de legtur memorat n fiecare element pe lng informaia propriuzs. n exemplul urmtor vom crea o list care va conine monoamele unui polinom n ordinea descresctoare a gradelor. Un element din list va conine pe lng informaia propriuzis (coeficientul i gradul monomului) i adresa urmtorului monom (adresa sublistei). De exemplu, pentru polinomul P(x)=120x12+77x7+130x3+22x2 lista va conine patru elemente avnd informaiile (20,12); (77,7); (130,3); (22,2), indiferent de ordinea introducerii monoamelor. Deoarece coeficienii sunt nenuli, introducerea datelor se termin la primul coeficient nul.
#include <stdio.h> #include <alloc.h> #include <iostream.h> #define Nil (NULL) struct Monom { int Coef, Grad ; }; struct Elem { Monom Inf; Elem* Leg; }; typedef Elem* Polinom; // List de monoame ordonate decresctor dup grad int Citit(Monom &M) { cin >> M.Coef; if (M.Coef) cin >> M.Grad; return M.Coef; } void Ado(Polinom &P, Monom M) { int lung=sizeof(Elem); Polinom Nou; if ((P==Nil)|(P->Inf.Grad<M.Grad)) {Nou=(Polinom) malloc(lung); Nou->Inf=M; Nou->Leg=P; P=Nou;} else Ado(P->Leg,M); } void Cre(Polinom &P) { Monom M; P=Nil; while (Citit(M)) Ado(P,M); } void Tip(Polinom P) { if (P!=Nil) { cout << P->Inf.Coef << "X^" << P->Inf.Grad; if (P->Leg!=Nil) cout << "+" ; Tip (P->Leg); } } void main (void) { Polinom P; cout << " P (Coef,Grad) : "; Cre (P); cout << " Polinomul P(X)="; Tip (P); getchar(); } Date : Rezultate : P (Coef,Grad) : 120 12 22 2 77 7 130 3 Polinomul P(X)=120X^12+77X^7+130X^3+22X^2 0

30

Exemplu:
// List simpl ordonat cresctor \\ #include <iostream.h> #include "Crt.Cpp" typedef int Info; struct Elem; typedef Elem* Lista; struct Elem {Info Inf; Lista Urm;}; int Citit(Info& inf) { cin >> inf; return inf; } void Ado(Lista& L, Info inf) { if (L && (L->Inf<inf)) Ado(L->Urm,inf); // else {Lista Nou=new Elem; Nou->Inf=inf; Nou->Urm=L; L=Nou;} //sau else {Elem el={inf,L}; Lista Nou = new Elem (el); L=Nou;} } void Cre(Lista& L) { Info El; L=NULL; while (Citit(El)) Ado(L,El); } void Tip(Lista L) { if (L) {cout << L->Inf << ','; Tip(L->Urm); } cout << "\b."; } void main (void) { ClrScr(); Lista L; cout << " Lista : "; Cre (L); cout << " Lista = "; Tip (L); Readln(); }

9.2. Abori binari


Considerm c un arbore binar nevid este format din rdcin, subarbore stng i subarbore drept. Exemplu:
// Arbore ordonat, traversat n inordine \\ #include <iostream.h> #include "Crt.Cpp" typedef int Info; struct Nod; typedef Nod* Arb; struct Nod {Info Inf; Arb LegSt,LegDr;}; int Citit(Info& inf) { cin >> inf; return inf; } void Ado(Arb& A, Info inf) { if (A) if (inf<A->Inf) Ado(A->LegSt,inf); else Ado(A->LegDr,inf); else { A=new Nod; A->Inf=inf; A->LegSt=NULL; A->LegDr=NULL;} } void Ado(Arb& A, Info inf) { if (A) if (inf<A->Inf) Ado(A->LegSt,inf); else Ado(A->LegDr,inf); // else { A=new Nod; A->Inf=inf; A->LegSt=NULL; A->LegDr=NULL;} //sau else { Nod n={inf,0,0}; A=new Nod (n); } } void Cre(Arb& A) { Info El; A=NULL; while (Citit(El)) Ado(A,El); } void Ino(Arb A) { if (A) { Ino(A->LegSt); cout << A->Inf << ','; Ino(A->LegDr); } } void main (void) { Arb A; ClrScr(); cout << " Arb : "; Cre (A); cout << " Arb = "; Ino (A); Readln(); }

31

n exemplul urmtor se citeste un arbore genealogic ascendent (dnd pentru fiecare persoan nume prinilor), apoi se va reprezenta grafic arborele construit ntr-o fereastr ecran precizat (u1,v1,u2,v2). Distana dintre dou nivele se calculeaz innd cont de adncimea arborelui.
#include #include #include #include #include #include <stdio.h> <alloc.h> <string.h> <iostream.h> <graphics.h> <conio.h>

typedef char TInf [13] ; struct Nod { Nod* Ls; } ; typedef Nod* Arb;

TInf Inf ; Nod* Ld;

// Radacin \\ // Sub.St, Sub.Dr

int Citit(TInf &Inf) { cin >> Inf; return (Inf[0]!='.'); } void Gen(Arb &A) { TInf Inf; int Lung=sizeof(Nod); if (Citit(Inf)) { A=(Arb) malloc(Lung); strcpy (A->Inf,Inf); // A->Inf=Inf; cout << " Mama lui " << Inf << " : "; Gen(A->Ls); cout << " Tatal lui " << Inf << " : "; Gen(A->Ld); } else A=NULL; } void Repr_Grafic(Arb A, int u1, int v1, int u2, int v2, int p) { int m; if (A!=NULL) { m=(u1+u2)/2; if (v1>20) lineto(m,v1-13); ellipse(m,v1,0,360,31,13); outtextxy(m,v1,A->Inf); moveto(m-2,v1+13); Repr_Grafic(A->Ls,u1,v1+p,m,v2,p); // St moveto(m+2,v1+13); Repr_Grafic(A->Ld,m,v1+p,u2,v2,p); } // Dr } int Max (int a, int b) { return (a>b ? a : b); } int Adi(Arb A) { if (A==NULL) return -1; else return Max(Adi(A->Ls),Adi(A->Ld))+1; } void main (void) { Arb A; cout << " Arbore genealogic ascendent pentru : "; Gen (A); int Gd = DETECT, Gm; initgraph(&Gd, &Gm, "c:\\Bc\\Bgi"); settextjustify(CENTER_TEXT,CENTER_TEXT); Repr_Grafic(A,50,20,getmaxx()-50,getmaxy()-20,(getmaxy()-40)/Adi(A)); getchar(); closegraph(); }

32

10. Utilizarea fiierelor


Prelucrarea fiierelor se poate efectua la dou nivele:

Nivelul inferior - face apel direct la sistemul de operare; Nivelul superior - utilizeaz proceduri speciale pentru operaii de intrare/ieire.

10.1. Nivelul inferior


Prelucrrile la acest nivel permit urmtoarele cinci operaii:

10.1.1.
unde:

Deschiderea unui fiier (Open/Creat)


int open ( const char * c a l e , int acces ) ;

c a l e - este specificatorul de fiier, acces - poate fi o combinaie (utiliznd operatorul |) a urmtoarelor valori: O_RDONLY (fiier deschis numai pentru citire), O_WRONLY sau O_CREAT (numai pentru scriere - creare), O_RDWR (citire/scriere), O_APPEND (deschis pentru adugare la sfrit), O_BINARY (pentru prelucrare binar), O_TEXT (pentru fiier de tip text).

Dac deschiderea fiierului s-a realizat corect, atunci funcia returneaz o valoare ntreag reprezentnd descriptorul de fiier (LUN, care va fi utilizat n continuare la celelelte operaii efectuate asupra acestui fiier), iar n caz de nereuit se va returna valoarea -1. Pentru a putea utiliza funcia Open trebuie incluse fiierele header io.h i fcntl.h. Exemplu:
... int Lun; Lun = open (Fisier.Dat,ORDONLY); ...

Pentru crearea unui fiier se va apela funcia Creat: int creat ( const char * c a l e , int mod ) ; unde:

mod - poate lua una dintre valorile: S_IREAD (fiierul se poate citi), S_IWRITE (scriere n fiier), S_IEXEC (execuia programului din fiierul specificat). Pentru a putea utiliza funcia Creat trebuie incluse fiierele io.h i stat.h. Fiierele text sunt implicite.

33

10.1.2.
unde:

Citirea dintr-un fiier (Read)


int read ( int L u n , void *buffer, unsigned lung ) ;

L u n - este descriptorul definit la deschidere (0= STDIN, 1=STDOUT, 2=STDERR,

3=STDPRN, 4=STDAUX), buffer - este zona de memorie n care se citete, l u n g - este lungimea (n octei) a nregistrrii citite.

Funcia returneaz numrul de octei citii (cel mult l u n g ), 0 la sfrit, sau -1 n caz de eroare. Automat, dup o citire (a articolului curent) se trece la urmtorul articol, implicit prima poziionare fiind la nceput de fiier (acces secvenial). Pentru a utiliza funciile Read, Write, LSeek sau Close trebuie inclus fiierul io.h.

10.1.3.

Scrierea ntr-un fiier (Write)


int write ( int L u n , void *buffer, unsigned lung ) ;

Funcia returneaz numrul de octei scrii n fiier, reprezentnd lungimea articolului = l u n g , sau -1 n caz de eroare.

10.1.4.

Poziionarea ntr-un fiier (LSeek)


long lseek ( int L u n , long *deplasament, int origine ) ;

Aceast funcie permite accesul aleator printr-un apel de forma: unde:


deplasament - reprezint numrul de octei peste care se deplaseaz capul de citire/scriere, origine - reprezint punctul din care se msoar deplasament- ul (0=nceputul fiierului, 1=poziia curent, 2=sfritul fiierului). Funcia returneaz poziia curent fa de nceputul fiierului, sau -1 la eroare.

10.1.5.

nchiderea unui fiier (Close)


int close ( int L u n ) ;

Funcia returneaz 0 la o nchidere corect, sau -1 la eroare.

10.1.6.

Stergerea unui fiier (UnLink)


int unlink (const char * c a l e ) ;

Funcia returneaz 0 la o tergere corect, sau -1 la eroare.

34

Exemple:
// #include <io.h> #include <fcntl.h> #include <stdio.h> #include <conio.h> #include <iostream.h> void main (void) { int Lun; clrscr(); Lun=open("Fis.Txt",O_CREAT|O_TEXT); if (Lun!=-1) { cout << "Open ..." << endl; write(Lun,"Primul...\n",10); write(Lun,"Al Doilea\n",10); } else cout << " Open Incorect ! "; close(Lun); getchar(); } Creare \\

// #include <io.h> #include <fcntl.h> #include <stdio.h> #include <conio.h> #include <iostream.h>

Citire

\\

void main (void) { int Lun; char Rand[10]; textmode(1); textbackground(BLUE); textcolor(WHITE); clrscr(); Lun=open("Fis.Txt",O_TEXT); if (Lun!=-1) { read(Lun,Rand,10); cout << Rand; read(Lun,Rand,10); cout << Rand; } else cout << " Open Incorect ! "; close(Lun); getchar(); }

35

10.2. Nivelul superior


La acest nivel sunt posibile urmtoarele operaii:

10.2.1.
unde:

Deschiderea unui fiier (FOpen)


FILE * fopen ( const char * c a l e , const char * mod ) ;

mod - poate fi r pentru deschidere n citire, w pentru scriere, a pentru adugare, r+ pentru modificare (citire/scriere), rb pentru citire binar, wb pentru scriere binar, sau r+b pentru citire/scriere binar.

Dac la deschiderea fiierului s-a ales modul w sau a, fiierul va fi creat (recreat). Funcia returneaz un pointer spre tipul FILE definit n fiierul stdio.h, iar n caz de nereuit se va returna valoarea NULL (stdin, stdout, stderr, stdaux i stdprn sunt pointeri spre tipul FILE permind transferuri fr a fi necesar deschiderea sau nchiderea lor). Exemplu:
...

FILE * Pf; Pf = fopen (Fisier.Dat,w);


...

10.2.2.
unde:

Prelucrarea pe caractere a unui fiier (PutC, GetC)


int putc ( int c , FILE * Pf ) ;

c - este codul caracterului scris, Pf - este valoarea returnat la deschidere sau stdin, stdout, stderr, stdaux, stdprn. Funcia returneaz valoarea lui c sau -1 la eroare. int getc (FILE * Pf ) ;

Funcia returneaz codul caracterului citit, sau valoarea EOF la sfritul fiierului, sau -1 la eroare. Exemplu:
#include <stdio.h>
void main (void)
{ }

int c; while ((c=getc(stdin))!=EOF) putc(c,stdout);

36

10.2.3.

nchiderea unui fiier (FClose)


int fclose ( FILE * Pf ) ;

Funcia returneaz 0 la nchiderea corect a fiierului sau 1 la eroare.

10.2.4.

Citirea/Scrierea cu format (FScanF, FPrintF)


int fscanf ( FILE * Pf , control, list_variabile) ;

Parametrii control i list_variabile au aceeai semnificaie ca i pentru funcia scanf. Funcia returneaz numrul de cmpuri citite sau EOF. int fprintf ( FILE * Pf , control, list_expresii) ;

Funcia returneaz numrul de caractere scrise n fiier sau -1 la eroare. Ex.1: // Creare fiier text cu Nume, Prenume \\
#include <stdio.h> #include <conio.h> int Citit(char *x, char*y) { printf (" Nume prenume : "); return (scanf(" %s%s",x,y)!=EOF); } void main (void) { char Nume[25], Prenume[15]; clrscr(); FILE *Pf=fopen("Fis_Text.Dat","w"); while (Citit(Nume,Prenume)) fprintf(Pf,"%s %s\n",Nume,Prenume); fclose (Pf); getche(); }

Ex.2: // Creare fiier text cu format (articole : (Den, Cant, Pre)) \\


#include <stdio.h> #include <conio.h> void main (void) { FILE *Produse; char Den[20]; int Cant; float Pret;

int n=0;

int Eof; textmode(1); textbackground(BLUE); textcolor(WHITE); clrscr();

if (Produse=fopen("Fis_Form.Txt","w")) { do { printf (" Articolul %d \n",++n); printf (" - Den. : "); Eof=(scanf("%s",Den)==EOF); if(!Eof){ printf (" - Cant.: "); scanf ("%d",&Cant); printf (" - Pret : "); scanf ("%f",&Pret); fprintf(Produse,"%-20s%4d%7.2f\n",Den,Cant,Pret);} } while (!Eof); fclose (Produse); } else printf (" Open incorect"); }

getchar();

// Listare fiier text \\ 37

#include <stdio.h> #include <conio.h> void main (void) { FILE *Produse; char Den[20]; int Cant; float Pret;

int n=0; textmode(1); textbackground(BLUE); textcolor(WHITE); clrscr();

if (Produse=fopen("Fis_Form.Txt","r")) { while (fscanf(Produse,"%s%d%f",Den,&Cant,&Pret)!=EOF) { printf (" Articolul %d : \n",++n); printf (" - Den. : %-20s \n",Den); printf (" - Cant.: %4d \n",Cant); printf (" - Pret : %7.2f \n",Pret); } fclose (Produse); } else printf (" Fisier Absent"); }

getchar();

10.2.5.
unde:

Intrri/Ieiri de iruri de caractere (FGetS, FPutS)


char * fgets ( char *s, int n, FILE * Pf ) ;

s - zona receptoare (tablou de tip char de dimensiune n, terminat cu NUL=\0), n-1 - numr maxim de caractere (n-1), Funcia returneaz adresa irului s, sau la EOF returneaz NULL. int fputs ( char *s, FILE * Pf ) ;

Funcia returneaz codul ultimului caracter scris sau -1 la eroare. Urmtorul program nlocuiete cuvintele din fiierul F_Niv_S.Cpp aflate n partea stng a dicionarului Dicio.Txt cu cele corespunztoare din partea dreapt, rezultatul fiind depus n fiierul F_Niv_S.Pas, aa cum se poate vedea n schema de mai jos.

Fin_Niv _S.Cp p

Dictio.Txt

Trad uce

Fin_Niv _S.Pas

38

#include <stdio.h> #include <iostream.h> #include <string.h>

// Traduce Fiier text - String \\

#include <conio.h> #include <process.h>

int Length(char* s) { return strlen(s); }

int Pos(char* s, char* S) { char* p = strstr(S,s); return p ? p-S : -1; }

/* int Pos(char* s, char* S) { for (int i=0; i<Length(S); i++) { int Ok=1; for (int j=0; j<Length(s); j++) if (S[i+j]!=s[j]) { Ok=0; break; } if (Ok) return i; } return -1; } */

void Delete(char* s, int p, int n) { for (int i=p; i<Length(s); i++) s[i]=s[i+n]; }

/* void Delete(char* s, int p, int n) { while (n) { n--; for (int i=p; i<Length(s); i++) s[i]=s[i+1]; } } */

void Insert(char* s, char *S, int p) {

/* void Insert(char* s, char *S, int p) { for (int l=0; l<Length(s); l++) { for (int i=Length(S); i>=p+l; i--) S[i+1]=S[i]; S[p+l]=s[l]; } } */

} void Subst (char* x, char* y, char* S) { int p=Pos(x,S); if (p>=0) { Delete(S,p,Length(x)); Insert(y,S,p); } } void main (void) { clrscr(); const Dd=20; typedef char Cuv[Dd]; struct Per { Cuv St, Dr; }; Per Dictio[20]; int NrCuv=1; FILE *Dic; Dic=fopen("Dictio.Txt","r"); if (Dic==NULL) { cout << "Dictio ?"; getche(); exit(1); } while (EOF!=fscanf(Dic,"%s%s",Dictio[NrCuv].St,Dictio[NrCuv].Dr)) cout << NrCuv << " : " << Dictio[NrCuv ].St << " -> " << Dictio[NrCuv++].Dr << endl; fclose(Dic); NrCuv--; getche(); FILE *FisI, *FisE; FisI=fopen("F_Niv_S.Cpp","r"); FisE=fopen("F_Niv_S.Pas","w"); if (FisI==NULL) { cout << "Fisier ?"; getche(); exit(1); } const Dm=100; char Rand[Dm]; while (fgets(Rand,Dm,FisI)) { // !=NULL for (int i=1; i<=NrCuv; i++) while (Pos(Dictio[i].St,Rand)>=0) Subst(Dictio[i].St,Dictio[i].Dr,Rand); fputs(Rand,FisE); cout << Rand; } fclose(FisI); fclose(FisE); getche(); }

for (int i=n; i>=p; i--) S[i+m]=S[i]; char* ps=S+p; while (*s) *ps++=*(s++);

int m=Length(s); int n=Length(S); if (p>n) p=n; else if (p<0) p=0;

10.2.6.

Poziionarea ntr-un fiier (FSeek, FTell)


int fseek (FILE * Pf, long deplasamnet, int origine ) ;

39

unde deplasamnet i origine au aceeai semnificaie ca i la funcia lseek. Funcia fseek returneaz 0 la poziionare corect sau o valoare 0 la eroare. long ftell ( FILE * Pf ); Funcia ftell returneaz poziia curent (fa de nceputul fiierului, n octei).

10.2.7.

Prelucrarea fiierelor binare (FRead, FWrite)

Acest tip de prelucrare permite transferul mai multor articole aflate ntr-o zon tampon astfel: unsigned fread (void *Pzt, unsigned dim, unsigned nrart, FILE * Pf) ; unde: Pzt - este adresa zonei tampon, dim - reprezint lungimea unui articol, nrart - reprezint numrul de articole care se transfer (citesc), unsigned fwrite (const void *Pzt, unsigned dim, unsigned nrart, FILE * Pf) ; Ambele funcii returneaz numrul de articole transferate sau -1 la eroare. Exemple:
#include <stdio.h> typedef struct { char Den[10]; int Cant; float Pret; Articol; int n,i;

} void main (void) { FILE *Pf; Articol Art;

if ((Pf=fopen("Fis_Tip.Dat","wb")) == NULL) printf (" Open incorect"); for (i=1; i<=n; i++)
printf printf printf printf (" (" (" (" scanf ("%d",&n);

printf ("\n Numarul de articole : "); Articolul %d - Den. : "); - Cant.: "); - Pret : ");

fwrite (&Art,sizeof(Articol),1,Pf);
fclose (Pf); }
...

: \n",i); scanf ("%s", Art.Den ); scanf ("%d",&Art.Cant); scanf ("%f",&Art.Pret);

getchar();

{...

if ((Pf=fopen("Fis_Tip.Dat","rb")) == NULL) printf (" Open incorect");


...

for (i=1; i<=n; i++)

fread

printf("Articolul %d : \n",i); printf("- Cant.: %d\n", Art.Cant);

(&Art,sizeof(Articol),1,Pf);

printf("- Den. : %s\n", Art.Den ); printf("- Pret : %f\n", Art.Pret); } fclose (Pf);

40

11. Funcii standard


11.1. Macrouri de clasificare
Macrourile din aceast categorie (aflate n fiierul ctype.h) verific dac un caracter este de un anumit tip:
int int int int int int int int int int

isascii isalpha isalnum isupper islower isdigit isxdigit isgraph isprint isspace

(int ca r ); (int ca r ); (int ca r ); (int ca r ); (int ca r ); (int ca r ); (int ca r ); (int ca r ); (int ca r ); (int ca r );

ca r ca r ca r ca r ca r ca r ca r ca r ca r ca r

[0,127] ? este codul unui caracter alfanumeric ? este codul unei litere ? este codul unei litere mari ? este codul unei litere mici ? este codul unei cifre zecimale ? este codul unei cifre hexa ? este codul unui caracter afiabil ? este codul unui caracter imprimabil ? este spaiu, tab, Cr, Lf, Vt sau Np ?

11.2. Macrouri de transformare a simbolurilor


Macrourile din aceast clas (aflate n fiierul ctype.h) transform un caracter astfel: toascii int toupper int tolower
int (int ca r ); (int ca r ); (int ca r );

[0,127] (returneaz ultimii 7 bii) ca r liter mare (transform din l n L) ca r liter mic (transform din L n l)
ca r

11.3. Conversii
Funciile care urmeaz (aflate n fiierul stdlib.h) realizeaz conversii far format.
Format intern Format (zecimal ) extern int atoi (const char *pt r ); binar (int) zecimal extern long atol (const char *pt r ); binar (long) zecimal extern double atof (const char *pt r ); virgul flotant (dubl precizie) zecimal extern Format extern Format intern char *itoa (int v, char *s, int b); s v b (valoarea v de tip int, scris n baza b) char *ltoa (long v, char *s, int b); s v b (valoarea v de tip long scris n baza b)

41

11.4. Funcii de prelucrare a irurilor de caractere


Funciile din aceast categorie se afl n fiierul string.h.

11.4.1.

Copiere (Str[n]Cpy)

char * str[n]cpy (char *destinaie, const char *sursa [, unsigned n ]) ; unde sursa este copiat n destinaie, eventual doar primii n octei (cel mult n).

11.4.2.

Concatenare (Str[n]Cat)

char * str[n]cat (char *destinaie, const char *sursa [, unsigned n ]) ; unde sursa este copiat la sfritul destinaiei, eventual doar primii n octei ai sursei.

11.4.3.

Comparare (Str[n][i]Cmp)

int str[n][i]cmp (char *ir 1 , const char *ir 2 [, unsigned n ]) ; unde ir 1 este comparat cu ir2 (eventual doar primii n octei, i eventual ignornd diferena dintre literele mari i cele mici), iar rezultatul comparrii este un numr negativ dac ir1<ir2, este un numr pozitiv dac ir1>ir2 sau zero dac ir1=ir2.

11.4.4.

Lungimea unui ir (StrLen)


unsigned strlen (char *ir) ;

returneaz lungimea irului (de caractere, fr caracterul NUL care l termin).

11.5. Funcii de calcul


Aceste funcii se afl n fiierul math.h (abs i labs i n stdlib.h *): Prototip
double sin (double x ); double cos (double x ); double asin (double x ); double acos (double x ); double atan (double x ); double sinh (double x ); double cosh (double x ); double tanh (double x ); double sqrt (double x ); double exp (double x );

Semnificaie sin(x) cos(x) arcsin(x) arccos(x) arctg(x) sh(x) ch(x) th(x) x ex

double log (double x ); double log10 (double x ); double ceil (double x ); double floor (double x ); double fabs (double x ); int abs (int x ); * long labs (long x ); * double atan2 (double y, double x ); double pow (double x, double y ); double cabs (struct complex z ); double poly (double x, int n, double a [] );

ln(x) lg(x) [x] trunc(x) |x| |x| |x| arctg(y/x) xy |z| P(x)

11.6. Funcii pentru controlul proceselor


Urmtoarele funcii se afl n fiierele stdlib.h i process.h .
void void

Prototip abort (void); exit (int cod_retur);

Semnifica ie
termin un program la eroare termin un program returnnd un cod de retur

42

int

system (const char *comand);

execut o comand i returneaz cod_retur (0=Ok).

11.7. Funcii pentru timp


Aceste funcii se refer la dat i or, i sunt definite n fiierul dos.h mpreun cu urmtoarele dou tipuri:
struct date {
int da_year; int da_day; int da_mon;

struct time

unsigned unsigned unsigned unsigned

char char char char

ti_min; ti_hour; ti_hund; ti_sec;

Semnifica ie Citete Data curent : Modific Data curent : Citete Ora Exact : Modific Ora Exact :

void void void void

Prototip getdate (struct date *Data); setdate (const struct date *Data); gettime (struct time *OraExact); settime (const struct time *OraExact);

Exemplu:
#include <stdio.h>; // Timp : Data, Ora \\ #include <dos.h>; void main (void) { struct date DataC; getdate(&DataC); struct time OraEx; gettime(&OraEx); printf(" Data : %2d %2d %4d \n", DataC.da_day,DataC.da_mon,DataC.da_year); printf(" Ora : %2d:%2d:%2d \n", OraEx.ti_hour,OraEx.ti_min,OraEx.ti_sec); }

11.8. Funcii diverse


Aceste funcii sunt definite n fiierul conio.h: Prototip void clrscr (double x ); void delay (unsigned ms ); Semnificaie
Clear Screen Wait (ms)
3. 4. 5.

1. 2.

void void void

sleep (unsigned sec ); sound (unsigned Hz ); nosound (void );

Wait (sec) Sound (Fr) NoSound

43

12. Ecranul n mod text


Exist posibilitatea de a defini urmtoarele moduri de lucru: void textmode ( int mod ) ; unde mod poate fi C40 (=1 pentru 40 coloane), C80 (=3 pentru 80 coloane), C4350 (=64 pentru 43/50 linii), i altele. Definirea unei ferestre ecran (implicit este tot ecranul) se realizeaz astfel: void window ( int u 1 , int v 1 , int u 2 , int v 2 ) ; tergerea unei ferestre ecran: void clrscr (void) ; Poziionarea cursorului: void gotoxy ( int x, int y) ; Poziia cursorului: int wherex ( void ) ; int wherey ( void) ; // col // lin // col, lin

Un caracter poate fi afiat pe ecran clipitor (BLINK=1), pe o culoare de fond (0-7) i ntr-o anumit culoare de scriere (0-15), culorile posibile fiind urmtoarele:

Colori nchise
0 1 2 3 4 5 6 7 = = = = = = = = BLACK BLUE GREEN CYAN RED MAGENTA BROWN LIGHTGRAY 8 9 10 11 12 13 14 15

Colori deschise
= = = = = = = = DARKGRAY LIGHTBLUE LIGHTGREEN LIGHTCYAN LIGHTRED LIGHTMAGENTA YELLOW WHITE

Culoarea de fond se poate stabili prin funcia: void textbackground ( int cul f ) ; // cul f {0,...,7}

Culoarea de scriere se poate schimba printr-un apel de forma: void textcolor ( int cul s ) ; // cul s {0,...,15}

13. Ecranul n mod grafic


Trecerea n modul grafic: void far initgraph ( int far * graphdriver, int far * graphmode, char far * path) ;

44

Ieirea din modul grafic: void closegraph (void) ; Setarea / Citirea culorii de fond: void far setbkcolor (int cul f ) ; Setarea / Citirea culorii de scriere: void far setcolor (int cul s ) ; Alte funcii: Semnifica ie Numr de pixeli ( Oriz./Vert.) Coordonatele LPR (Ultimul Punct Referit ) Mut LPR (Abs./Rel.) Traseaz segment din LPR Traseaz segment Deseneaz dreptunghi Deseneaz cerc Scrie mesaj [ din LPR ] Pagin activ / Pagin vizual Exemple:
#include <graphics.h> #include "graf.h" // Graficul unei suprafee \\

/ /

int far getbkcolor (void ) ;

int far getcolor (void ) ;

Funcii getmaxx (); getmaxy (); getx (); gety (); moveto (x,y); moverel (dx,dy); lineto (x,y); linerel (dx,dy); line (x1,y1, x2,y2); rectangle (x1,y1, x2,y2); circle (x,y,r); outtext[xy] ([x,y,] mesaj); setactivepage (pag); setvisualpage (pag);

# i n c l u d e < s t d l i b . h > # i n c l u d e < s t d i o . h > # i n c l u d e < con i o. h > # i n c l u d e < m a t h . h >

float Sqr (float x) { return x*x; } float z (float x, float y) { return sin(Sqr(x)+Sqr(y)); } void main(void) { float x; float y; float px; float py; int i; int j; int n=40; int m=40; InitGraf (); ViewPort (10,10,getmaxx()-10,getmaxy()-10); float l=3; float x1=-l; float x2=l; float y1=-l; float y2=l; DefPr(1./2,1); a=PrX(x1,z(x1,y1)); b=a; c=PrY(y1,z(x1,y1)); d=c; for (i=0; i<=m; i++) for (j=0; j<=n; j++) { x=x1+(x2-x1)*i/m; y=y1+(y2-y1)*j/n; px=PrX(x,z(x,y)); py=PrY(y,z(x,y)); if (px<a) a=px; else if (px>b) b=px; if (py<c) c=py; else if (py>d) d=py; };

// z=f(x,y)

// Dom (x,y) // DefPr (r,a)

45

Window(a,d,b,c); setbkcolor(BLUE); for (i=0; i<=m; i++) { x=x1+(x2-x1)*i/m; y=y1; Muta(PrX(x,z(x,y)),PrY(y,z(x,y))); for (j=1; j<=n; j++) { y=y1+(y2-y1)*j/n; Trag(PrX(x,z(x,y)),PrY(y,z(x,y))); } } setcolor(YELLOW); for (j=0; j<=n; j++) { y=y1+(y2-y1)*j/n; x=x1; Muta(PrX(x,z(x,y)),PrY(y,z(x,y))); for (i=1; i<=m; i++) { x=x1+(x2-x1)*i/n; Trag(PrX(x,z(x,y)),PrY(y,z(x,y))); } } getch(); closegraph(); } #include <graphics.h> // Graficul unei curbe \\ #include <conio.h> #include <math.h> #include "graf.h" float x (float t) { return cos(t); } float y (float t) { return sin(t); } float z (float t) { return t / 10; } void main(void) { float t, px,py; float t1=-50; float t2=50; float p=0.1; float Raza=0.5; float Alfa=1; InitGraf (); setgraphmode(1); ViewPort (20,20,getmaxx()-20,getmaxy()-20); DefPr(Raza,Alfa); // Pr.||(Raza,Alfa) t=t1; a=PrX(x(t),z(t)); b=a; c=PrY(y(t),z(t)); d=c; for (t=t1+p; t<=t2; t+=p*2) { px=PrX(x(t),z(t)); py=PrY(y(t),z(t)); if (px<a) a=px; else if (px>b) b=px; if (py<c) c=py; else if (py>d) d=py; }; Window(a,d,b,c); int Pag=0; setbkcolor(BLUE); enum { Rosu, Verde } Sem = Verde; do { clearviewport(); outtextxy(10,10,"Q OP"); outtextxy(10,20,"A"); t=t1; Muta(PrX(x(t),z(t)),PrY(y(t),z(t))); for (t=t1+p; t<=t2; t+=p) {Trag(PrX(x(t),z(t)),PrY(y(t),z(t)));} setvisualpage(Pag); Pag=1-Pag; setactivepage(Pag); char Rasp=getch(); switch (Rasp&0x5F) { case 'A' : Raza-=0.01; break; case 'Q' : Raza+=0.01; break; case 'P' : Alfa-=0.01; break; case 'O' : Alfa+=0.01; break; default : closegraph(); Sem=Rosu; } DefPr(Raza,Alfa); } while (Sem==Verde); } // Graf.h \\ #include <graphics.h> #include <math.h> int u1,v1, u2,v2;

// ViewPort

46

float a, b, c, d ; float Raza, Alfa; int u (float x) { return ((x-a)/(b-a)*(u2-u1)+u1); } int v (float y) { return ((y-d)/(c-d)*(v2-v1)+v1); } void InitGraf(void) { int Gd = DETECT, Gm; initgraph(&Gd, &Gm, "c:\\Bc\\Bgi"); } void ViewPort(int x1,int y1,int x2,int y2) { u1=x1; v1=y1; u2=x2; v2=y2; /* rectangle(u1,v1,u2,v2);*/ } void Window(float x1,float y1,float x2,float y2) { a=x1; d=y1; b=x2; c=y2; } void Muta(float x,float y) { moveto(u(x),v(y)); } void Trag(float x,float y) { lineto(u(x),v(y)); } void DefPr(float r, float a) { Raza=r; Alfa=a; } float PrX (float x, float z) { return x+Raza*z*cos(Alfa); } float PrY (float y, float z) { return y+Raza*z*sin(Alfa); }

// Window // Pr (r,)

47

14. Faciliti C++


Limbajul C++ ofer n plus fa de limbajul C unele faciliti noi. Un avantaj important l constituie noiunea de clas (prin care se definete un TAD), iar acestea pot forma o ierarhie, deci putem vorbi de o programare orientat obiect.

14.1. Extensii ale limbajului C


n C++ exist un nou tip de comentariu (deja utilizat n exemplele anterioare): ... // Comentariu Dac n limbajul C declaraiile erau scrise nainte de instruciuni, n C++ ele pot fi scrise oriunde. Dispozitivelor standard de intrare-ieire li s-au ataat streamurile standard cin (pentru stdin) i respectiv cout (pentru stdout), care permit efectuarea operaiilor de intrareieire aplicnd operatorul >> streamului cin, respectiv << streamului cout. Ierarhiile necesare sunt n fiierul iostream.h . Exemplu:
#include <stdio.h>; #include <conio.h>;

#include <iostream.h>;
void main (void)

{ int i;

cout cout double x; cout cout char s[10]; cout cout

<< " Dati i : "; cin >> i; << " Val. i = " << i << endl; << " Dati x : "; cin >> x; << " x + i = " <<x+i<< endl; << " Dati s : "; cin >> s; << " Sir. s = " << s << endl;

// endl=<Cr>

getch();

Dac n C conversia explicit se poate efectua prin (tip) expresie, n C++ se poate realiza i prin tip (expresie). Exemplu:
#include <stdio.h>; #include <conio.h>;

#include <iostream .h>;


void main (void) {

char c; cout << " Dati c : "; cin >> c; cout << " Car. c = " << c << endl; cout << " Val. c = " << (int) c << endl; cout << " Val. c = " << int (c) << endl; void *p; p=&c; cout << " Val. c = " << *(int *) p << endl; typedef int * Pint; cout << " Val. c = " << * Pint (p)<< endl; getch();

// Coninutul adresei // la care se afl un ntreg

48

14.2. Operatori
14.2.1. Operatorul de rezoluie (::)

Acest operator (::) se utilizeaz cnd dorim s referim o variabil global redefinit ntr-o funcie, astfel: :: Variabil Exemplu:
#include <conio.h>; #include <iostream.h>;

unsigned x; char y[10]; int i=99; void main (void) { unsigned x; int y; cout << " Dati doua numere : cout << " Cele doua numere = cout << " Cele doua numere = cout << " Cele doua numere =

// Variabile Globale (::)

clrscr(); // Variabile Locale "; cin >> ::x >> x; " << ::x << ' ' << x << endl; " << ++::x << ' ' << --x << endl; " << ::x << ' ' << x << endl;

cout << " Dati nume,varsta : "; cin >> ::y >> y; cout << " Numele si varsta = " <<

::y << ',' <<

y << endl; getche();

for (int i=11; i<::i; ::i-=11) cout << i <<"::"<< ::i << endl; }

14.2.2.

Operatorul de adres (&)

Acest operator (&) se poate utiliza i pentru a defini un tip referin printrdeclaraie de forma tip & (asemntor cu o construcie de forma tip *, pentru pointer). Cu ajutorul acestui operator putem redenumi o variabil, putem realiza un apel prin referin sau putem s declarm o variabil de referin astfel: tip & parametru_formal tip & nume_var_ref ; // par. ref. (adres) // var. de tip referin

49

Exemple:
#include <conio.h>; #include <iostream.h>;

// Redefinirea unei variabile

void main (void) { int a[1]; int * b = a; int & c = a[0]; cout << " Dati a : "; cin >> a[0]; cout << " a,b,c = " << a[0] << *b << c << endl; int x; int * y = &x; int & z = *y; int & w = x; cout << " Dati x : "; cin >> x; cout << " x,y,z,w = " << x << *y << z << w << endl;
}
#include <conio.h>; #include <iostream.h>;

getch();

// Redefinirea unei func ii

#include <math.h>; typedef double Functie (double); void main (void) { Functie & Sin=sin; double x; cout << " Dati x : "; cin >> x; cout << "Sin(" << x << ")=" << Sin(x) << endl;
}
#include <conio.h>; #include <iostream.h>;

getch();

// Apel prin Referin

void suma (int x,int y,int *z) // x,y z { *z = ++x * ++y; } void Suma (int x,int y,int &z) // x,y z { z = ++x * ++y; } void main (void) { int x,y,z; cout << " Dati x,y : "; cin >> x >> y; suma(x,y, &z); cout << "(x+1)*(y+1)=" << z << endl; Suma(x,y, z); cout << "(x+1)*(y+1)=" << z << endl; // mai simplu!
getch();

14.2.3.

Operatorii de alocare/dealocare (New/Delete)


new tip new tip ( Valoare_de_intiializare_a_variabilei_dinamice ) new tip [ Numrul_de_variabile_dinamice_alocate ]

Operatorul de alocare New se poate folosi n oricare dintre urmtoarele trei variante:

Dealocarea se realizeaz astfel: delete Variabil_de_referin ; sau delete [ Numrul_de_var_dinamice_alocate ] Variabil_de_referin ; Exemplu:
#include <stdio.h>; #include <conio.h>; #include <iostream.h>;

void main (void)

50

int *i = new int; int *j; j = new int (*i);

cout << " Dati v : "; cin >> *i; cout << " v = " << *i << endl;

cout << "*i ==*j = " << *j << endl; delete i; delete j; int *r; r = new int [2]; cout << " Dati v1 : "; cin >> * r; cout << " Dati v2 : "; cin >> *(r+1); cout << " v1 = " << * r << endl; cout << " v2 = " << *(r+1)<< endl; delete r;

getch();

n exemplul urmtor se va utiliza o matrice A cu numr variabil de coloane i o matrice B utiliznd adresele liniilor:
#include <iostream.h>; #include "Crt.Cpp"

typedef int Tip; const n=4; void main () { Tip* A[n+1], *p; int i,j; for (i=1; i<=n; i++) { p = A[i] = new Tip [i+1]; for (j=1; j<=i; j++) *(++p)=i*10+j; } for (i=1; i<=n; i++) { p=A[i]; cout << " " << i for (j=1; j<=i; j++) cout << *p++ << ' cout << endl; } for (i=1; i<=n; i++) { cout << " " << i << " for (j=1; j<=i; j++) cout << *(*(A+i)+j) << cout << endl; } int B[n+1][n+1]; for (i=1; i<=n; i++) for (j=1; j<=n; j++) B[i][j]=i*10+j; for (i=1; i<=n; i++) { cout << " " << i << " for (j=1; j<=n; j++) cout << *(*(B+i)+j) << cout << endl; } }

ClrScr();

<< " : "; '; : "; ' ';

// Aij

: "; ' ';

// Bij

Readln(); // R e z u l t a t e :
1 2 3 4 1 2 3 4 1 2 3 4 : : : : : : : : : : : : 11 21 31 41 11 21 31 41 11 21 31 41 22 32 33 42 43 44 22 32 42 12 22 32 42 33 43 13 23 33 43

44 14 24 34 44

51

14.3. Structur, uniune i enumerare


Referirea acestor tipuri se poate face n C++ fr a mai fi nevoie de cuvntul corespunztor struct, union, respectiv enum. De asemenea, parametrii i valoarea unei funcii pot fi structuri, pointeri la structuri sau referine la structuri. Sunt permise i atribuiri de structuri. Referirea componentelor unei uniuni anonime din interiorul unei structuri se face la fel ca i referirea componentelor structurii, iar prima component se poate iniializa. n C++, variabilelor de tip enumerare nu se mai pot atribui dect valori ale acestui tip (nu i numerele asociate acestor elemente). Exemple:
#include <stdio.h>; #include <conio.h>; #include <iostream.h>;

typedef float Real;

enum Figura { punct, cerc }; struct Punct { Real x, y; }; struct Cerc { Punct Centru; Real Raza; }; struct Obiect { Figura FIG; union { Punct PUNCT; Cerc CERC; }; }; Obiect Translatat ( Obiect o, Punct T ) { o.PUNCT.x = o.PUNCT.x + T.x; o.PUNCT.y = o.PUNCT.y + T.y; return o; } void main (void) { Punct P = { 3,7 }; Obiect O = { punct, { 1,2 } }; Obiect C; C.FIG=cerc; C.CERC.Centru=O.PUNCT; C.CERC.Raza=10; Obiect D; D=Translatat(C,P); cout << " D(" << D.CERC.Centru.x << "," << D.CERC.Centru.y << "," << D.CERC.Raza << ")" << endl; getch(); }

52

#include <iostream.h> #include "crt.h"

// Simetrizeaza cel mai apropiat punct fata de origine \\

struct Punct { float x, y; Punct& CitP (); void TipP (); float D2 () { return x*x + y*y; } Punct& SimO () { x=-x; y=-y; return *this; } }; Punct& Punct::CitP () { cin >> x >> y; return *this; } void Punct::TipP () { cout << x << ' ' << y << endl; } Punct& ApropO( Punct& P, Punct& Q ) { return P.D2()<Q.D2() ? P : Q; } void main (void) { ClrScr(); cout << " P : "; Punct P; //P.CitP(); cout << " Q : "; Punct Q; //Q.CitP(); cout << " M = "; ApropO(P.CitP(),Q.CitP()).SimO().TipP(); cout << " P = "; P.TipP(); cout << " Q = "; Q.TipP(); Readln() ; }
#include <iostream.h> #include "crt.h"

// Simetrizeaza cel mai apropiat punct fata de origine \\

struct Punct { float x, y; Punct () { cin >> x >> y; } void TipP() { cout << x << ' ' << y << endl; } float D2 () { return x*x + y*y; } Punct& SimO(); }; Punct& Punct::SimO() { x=-x; y=-y; return *this; } Punct& ApropO (Punct& P, Punct& Q) { return P.D2()<Q.D2() ? P : Q; } void main (void) { ClrScr(); cout << " P : "; Punct P=Punct(); cout << " Q : "; Punct Q=Punct(); cout << " M = "; ApropO(P,Q).SimO().TipP(); cout << " P = "; P.TipP(); cout << " Q = "; Q.TipP(); Readln() ; }

53

15. Funcii C++


15.1. Funcii Inline
Aceste macrouri se pot defini astfel: # define nume m ( List_parametri_formali ) ir_caractere Apelurile macrourilor se vor nlocui cu irul de caractere precizat, fr a face verificri de tipuri, ceea ce poate conduce la erori. Aceste erori pot fi eliminate dac utilizm funciile inline, caz n care se vor face conversiile de tip necesare. Aceste funcii se declar prin scrierea cuvntului inline la nceputul antetului, aa cum se pate vedea n exemplele urmtoare: Ex. 1:
#include <conio.h>; #include <iostream.h>;

#define Abs_G(x) (x)> 0 ? (x) : -(x) // Gresit ! #define Abs_g(x) ( x > 0 ? x : - x ) // gresit ! #define Abs_c(x) ( (x)> 0 ? (x) : -(x) ) // Macro corect inline long Abs (long x) // Functie Inline { return x > 0 ? x : - x ; } void main (void) { long x; cout << " x : " ; cin >> x; long y=-x; cout << " |x| = " << Abs_G(x); cout << endl; cout << " |x| = " << Abs_g(x) << endl; cout << " |x| = " << Abs_c(x) << endl; cout << " |x| = " << Abs (x) << endl; cout << " |10-y| = " << Abs_G(10-x); cout << endl; cout << " |10-y| = " << Abs_g(10-x) << endl; cout << " |10-y| = " << Abs_c(10-x) << endl; cout << " |10-y| = " << Abs (10-x) << endl; getch();
}

Ex. 2:
#include <iostream.h>;

#define max( x, y) (x>y ? x : y) // Gresit ! inline int Max(int x, int y) // F.Inline { return (x>y ? x : y); } void main (void) { int x,y,z; x=5; y=2; z=max(++x,++y); cout <<" max("<<x<<','<<y<<")="<<z<< endl; x=5; y=2; z=Max(++x,++y); cout <<" Max("<<x<<','<<y<<")="<<z<< endl; }

// Rezultatele
max(7,3)=7 Max(6,3)=6

54

15.2. Funcii de tip referin


Antetul unei funcii cu valoare de tip referin este: tip & numef ( List_parametri_formali ) Exemplu:
#include <time.h>; #include <stdlib.h>; #include <conio.h>; #include <iostream.h>;

int & Alba_Neagra ( int & Albe, int & Negre ) // Ref. la int { if (random(2)) return Albe; // Ref. la Albe else return Negre; // Ref. la Negre } void main (void) { int Albe=0; int Negre=0; int i,n; randomize(); cout << "Dati n:"; cin >> n; for(i=1;i<=n;i++) Alba_Neagra(Albe,Negre)++; cout <<"Albe ="<< Albe << endl; cout <<"Negre="<< Negre<< endl;
getch(); }

// Inc(Albe/Negre)

n urmtorul exemplu se dorete modificarea coordonatelor celui mai apropiat punct (dintre P i Q) fa de origine (nu doar coordonatele simetricului lui P sau Q):
// Simetrizeaz cel mai apropiat punct fa de origine
#include <iostream.h> #include "crt.h"

struct Punct { float x, y; }; float D2 ( Punct P ) { return P.x*P.x + P.y*P.y; } Punct SimO ( Punct& P ) { P.x=-P.x; P.y=-P.y; return P; } Punct& ApropO( Punct& P, Punct& Q ) { return D2(P) < D2(Q) ? P : Q; } Punct CitP ( ) { Punct P; cin >> P.x >> P.y; return P; } void TipP ( Punct P ) { cout << P.x << ' ' << P.y << endl; } void main { cout cout cout cout cout } (void) ClrScr(); << << << << << " " " " " P Q M P Q : : = = = "; "; "; "; "; Punct P = CitP (); Punct Q = CitP (); TipP (SimO (ApropO(P,Q)) ); TipP (P); TipP (Q); Readln();

55

// Ex. Referin \\
#include <iostream.h>; #include "Crt.Cpp" void suma (int x,int y,int *z) { *z = ++x * ++y; } void Suma (int x,int y,int &z) { z = ++x * ++y; } int* max (int& x, int& y) { return ( x > y ? &x : &y ); } int& Max (int& x, int& y) { return ( x > y ? x : y ); } struct Punct { int x,y; }; Punct Atrib (int x, int y) { Punct P; P.x=x; P.y=y; return P; } Punct sim (Punct P) { P.x=-P.x; P.y=-P.y; return P; } Punct& Sim (Punct& P) { P.x=-P.x; P.y=-P.y; return P; } Punct* Psim(Punct P) { P.x=-P.x; P.y=-P.y; return &P; } void Tip (Punct P) { cout << " P(" << P.x << ',' << P.y << ')' << endl; } void main (void) { int x,y,z; ClrScr(); cout << " Dati x,y : "; cin >> x >> y; suma(x,y,&z); cout << " (x+1)*(y+1) = " << z << endl; Suma(x,y, z); cout << " (x+1)*(y+1) = " << z << endl; cout << " x,y = " << x << ' ' << y << endl; cout << " max(x,y)+1 = " << ++ *max(x,y) << endl; cout << " x,y = " << x << ' ' << y << endl; cout << " Max(x,y)+1 = " << ++ Max(x,y) << endl; cout << " x,y = " << x << ' ' << y << endl; Punct P=Atrib(x,y); Tip(P); Tip(sim(P)); Tip(P); Tip(Sim(P)); Tip(P); cout <<"P(x,y)=("<< sim(P) .x <<','<< Sim(P) . y <<')'<< endl; cout <<"P(x,y)=("<<(*Psim(P)).x <<','<< Psim(P)->y <<')'<< endl; }

// R e z u l t a t e :

Readln();

Dati x,y : 1 5 (x+1)*(y+1) = 12 (x+1)*(y+1) = 12 x,y = 1 5 max(x,y)+1 = 6 x,y = 1 6 Max(x,y)+1 = 7 x,y = 1 7 P(1,7) P(-1,-7) P(1,7) P(-1,-7) P(-1,-7) P(x,y)=(1,7) P(x,y)=(-1,-7)

56

15.3. Suprancrcarea funciilor


Aceast proprietate d posibilitatea utilizrii unor funcii avnd acelai nume, dar diferite (nrudite, cu antete diferite). Exemple:
#include <math.h>; #include <complex.h>; #include <conio.h>; #include <iostream.h>;

double ArcTg (double x) { return atan (x); } double ArcTg (double y, double x) { return atan2(y,x); } double ArcTg (complex z) { return real (atan(z)); } void main (void) { complex w(1,0); cout << " Pi = " << 4*ArcTg(1.0) << endl; cout << " Pi = " << 2*ArcTg(1,0) << endl; cout << " Pi = " << 4*ArcTg( w ) << endl; getch();
}

#include "graf.h" #include <conio.h>

//

Roteste un Triunghi in jurul unui Punct

\\

struct Punct { float x,y; }; struct Triunghi { Punct A,B,C; }; Punct Init (float x, float y); Triunghi Init (Punct A, Punct B, Punct C); void Translat (Punct& P, Punct Q); void Translat (Triunghi& T, Punct Q); void Rot (Punct& P, float Alfa, Punct Q); void Rot (Triunghi& T, float Alfa, Punct Q); Punct Init (float x, float y) { Punct P = {x,y}; return P; } Triunghi Init (Punct A, Punct B, Punct C){ Triunghi T; T.A=A; T.B=B; T.C=C; return T; } void Translat (Punct& P, Punct Q) { P.x+=Q.x; P.y+=Q.y; } void Translat (Triunghi& T, Punct Q) { Translat(T.A,Q); Translat(T.B,Q);
Translat(T.C,Q); }

void Rot (Punct&

P,Punct Q,float Alfa)

Rot(P.x,P.y,Q.x,Q.y,Alfa); Rot(T.A,Q,Alfa); Rot(T.B,Q,Alfa);

Rot(P.x,P.y,Q.x,Q.y,Alfa); } Rot(T.C,Q,Alfa); }

void Rot (Triunghi& T,Punct Q,float Alfa){ void Muta(Punct P) void Trag(Punct P) void Des (Punct P) void Des (Triunghi T) void main(void)
{

{ { { {

Muta (P.x,P.y); } Trag (P.x,P.y); } circle(u(P.x),v(P.y),3);} Muta(T.A); Trag(T.B); Trag(T.C); Trag(T.A);}

Punct P = Init(10,10); Triunghi ABC = Init(Init(5,5),Init(20,7),Init(8,12)); InitGraf(); ViewPort (20,10,getmaxx()-20,getmaxy()-10); setbkcolor(BLUE); setwritemode(XOR_PUT); Window (-10,20,30,-10); Linie (-10, 0,20, 0); Linie ( 0,20, 0,-10); char Esc=0x1b; float Alfa; char Rasp='o'; Des(P); do { Des(ABC); if (Rasp=='o') Alfa=0.1; else Alfa=0.1; Rot(ABC,P,Alfa); } while ((Rasp=getche())!=Esc); closegraph();
}

57

15.4. Iniializarea parametrilor formali


Parametrii formali pot avea o valoare implicit, dac acetia lipsesc din lista parametrilor actuali, valoare dat de o expresie. n lista parametrilor formali, cei cu valoare implicit (iniializai) se vor scrie ultimii astfel: tip nume = expresie Exemplu:
#include <stdio.h>; #include <conio.h>; #include <iostream.h>;

struct int int Obiect {

Obiect { float x,y; float r; }; ELipsa () { return -1; } Este_Punct (Obiect o) { return o.r==ELipsa(); } Init( float x0=0, float y0=0, float raza=ELipsa() ) Obiect o; o.x=x0; o.y=y0; o.r=raza; return o;

} Tip ( Obiect o ) { if (Este_Punct(o)) cout << " Punct ( "; else cout << " Cerc ( "; cout << o.x << "," << o.y; if (Este_Punct(o)) ; else cout << "," << o.r; cout << " ) " << endl; } main () { Obiect O=Init(); Tip(O); // Originea (0,0) Obiect A=Init(7); Tip(A); // A Ox (7,0) Obiect P=Init(1,2); Tip(P); // P R2 (1,2) Obiect C=Init(3,4,5); Tip(C); // Cerc (3,4, 5) getch(); }

n exemplul care urmeaz se poate vedea cum se pot folosi parametrii implicii pentru a declara punctul O(0,0), un punct A pe axa Ox, un punct P n plan ( R2), un cerc C (n plan), extremitile unui segment din spaiu (Q,RR 3), precum i segmentele QR i RO:
#include <stdio.h>; #include <conio.h>; #include <iostream.h>; struct Punct { float x,y,z; }; Punct Init( float x0=0, float y0=0, float z0=0 ) { Punct P; P.x=x0; P.y=y0; P.z=z0; return P; } void Tip ( Punct P ) { cout << " P(" << P.x <<','<< P.y <<','<< P.z <<')'<< endl; }

58

struct Segment { Punct A, B; } ; Segment Init ( Punct A, Punct B = Init() ) { Segment AB = {{A.x,A.y,A.z},{B.x,B.y,B.z}}; return AB; } void Tip ( Segment AB ) { cout << " Segment : \n"; Tip(AB.A); Tip(AB.B); } void main () { clrscr(); Punct O=Init(); Tip(O); (0,0,0) Punct A=Init(7); Tip(A); (7,0,0) Punct P=Init(1,2); Tip(P); (1,2,0) Punct C=Init(3,4,5); Tip(C); (3,4,5) Punct Q =Init(1,2,3); Punct R =Init(4,5,6); Segment QR=Init(Q,R); Tip(QR); Segment RO=Init(R); Tip(RO); getche(); }

// Originea // A e Ox // P e R2 // Cerc // Q e R3 // R e R3 // QR e R3

15.5. Funcii membru pentru Structuri


Acestea se declar n cadrul structurii ca fincii inline sau prototipuri (urmnd n acest caz descrierea lor cu ajutorul operatorului de rezoluie (::).
#include <iostream.h> #include "crt.h"

// Simetrizeaza cel mai apropiat punct fata de origine \\

struct Punct { float x, y; Punct& CitP (); void TipP (); float D2 () { return x*x + y*y; } Punct& SimO () { x=-x; y=-y; return *this; } }; Punct& Punct::CitP () { cin >> x >> y; return *this; } void Punct::TipP () { cout << x << ' ' << y << endl; } Punct& ApropO( Punct& P, Punct& Q ) { return P.D2()<Q.D2() ? P : Q; } void main (void) { ClrScr(); cout << " P : "; Punct P; //P.CitP(); cout << " Q : "; Punct Q; //Q.CitP(); cout << " M = "; ApropO(P.CitP(),Q.CitP()).SimO().TipP(); cout << " P = "; P.TipP(); cout << " Q = "; Q.TipP(); Readln() ; } // Simetrizeaza cel mai apropiat punct fata de origine \\

59

#include <iostream.h> #include "crt.h"

struct Punct { float x, y; Punct () { cin >> x >> y; } void TipP() { cout << x << ' ' << y << endl; } float D2 () { return x*x + y*y; } Punct& SimO(); }; Punct& Punct::SimO() { x=-x; y=-y; return *this; } Punct& ApropO (Punct& P, Punct& Q) { return P.D2()<Q.D2() ? P : Q; } void main (void) { ClrScr(); cout << " P : "; Punct P=Punct(); cout << " Q : "; Punct Q=Punct(); cout << " M = "; ApropO(P,Q).SimO().TipP(); cout << " P = "; P.TipP(); cout << " Q = "; Q.TipP(); Readln() ; }

16. Tip Abstract de Dat


Programarea modular permite protejarea datelor prin memorie static, (accesul la date se poate efectua doar din locul declarrii pn la sfritul modulului, nu i n afara lui). Un tip abstract de dat (Domeniu, Operaii) conine o interfa (Tad.h) i o implementare (Tad.Cpp). Programul (Program.Cpp) care utilizeaz acest tip abstract de dat va avea acces doar la modulul de interfa, aa cum se poate vedea n schema de mai jos:

Prog ram .Cpp

Com pilare

Prog ram .Obj Link-editare

Tad.h Com pilare

Prog ram .Exe

Tad.Cpp

Prog ram .Obj

n proiect (meniul Project) vor fi incluse fiierele Program.Cpp i Tad.Cpp.

60

n exemplul urmtor, pentru Tad Mulime, fiierele vor fi PMult.Cpp, Mult.h i Mult.Cpp:
// PMult.Cpp \\ #include <conio.h> #include <iostream.h> #include "Mult.h" void main (void) { Multime A, B, C, D; Init(A); Init(B); Init(C); Init (D); cout << " A : "; CitM(A); cout << " A = "; TipM(A); //cout << "|A|: " << A->card << endl; cout << "|A|: " << Card(A) << endl; cout << " B : "; CitM(B); cout << " B = "; TipM(B); Init(C); Inters(A,B,C); cout << "AnB: "; TipM(C); Init(D); Reun (A,B,D); cout << "AuB: "; TipM(D); cout << (Inclus(A,B) ? " A<=B " : " !A<=B "); cout << (Egale (A,B) ? " A==B " : " A<>B "); }

clrscr();

// Nu se p.! // Se p.!

getche();

// Mult.h \\
#include "ElMult.h" struct Cet; typedef Cet *Multime; void Init (Multime &A); int Card (Multime A); int E_Vida (Multime A); void Vida (Multime A); void AdEl (TEl x, Multime A); void CitM (Multime A); void TipM (Multime A); int Apart (TEl x, Multime A); void Inters (Multime A, Multime B, Multime C); void Dif (Multime A, Multime B, Multime C); void Reun (Multime A, Multime B, Multime C); int Inclus (Multime A, Multime B); int Egale (Multime A, Multime B); Multime DifEl (Multime A, TEl a); Multime Difer (Multime A, Multime B);

// Sunt definite elementele mulimii

#include <iostream.h> #include <conio.h>

// PMult.Cpp \\

#include "ElMult.h" #include "Mult.h" typedef struct Cet

int card; TEl Elem[Cm]; };

61

int Card (Multime A) { return A->card; } void CitM (Multime A) { cin >> A->card; if (Card(A)>Cm-2) cout << Card(A) << Cm << "!"; else for (int i=1; i<=Card(A); i++) cin >> A->Elem[i]; cout << endl; } void TipM (Multime A) { for (int i=1; i<=Card(A); i++) cout << A->Elem[i] << ","; cout << "\b\n"; } int Apart (TEl x, Multime A) { for (int i=1; i<=Card(A); i++) if (x==A->Elem[i]) return 1; return 0; } void Inters (Multime A, Multime B, Multime C) { Vida(C); for (int i=1; i<=Card(A); i++) if (Apart(A->Elem[i],B)) AdEl(A->Elem[i],C); } void Dif (Multime A, Multime B, Multime C) { int i; Vida(C); for (i=1; i<=Card(A); i++) if (!Apart(A->Elem[i],B)) AdEl(A->Elem[i],C); } Multime DifEl (Multime A, TEl a) { if (Apart(a,A)) { Multime D; Init(D); AdEl(a,D); Dif(A,D,D); return D; } else return A; } Multime Difer (Multime A, Multime B) { Multime D; Init(D); Dif(A,B,D); return D; } Multime Difer (Multime A, Multime B) { Multime D; Init(D); Dif(A,B,D); return D; } void Reun (Multime A, Multime B, Multime C) { int i; *C=*A; Multime B_A; Init(B_A); Dif(B,A,B_A); for (i=1; i<=Card(B_A); i++) AdEl(B_A->Elem[i],C); // destroy B_A; } int Inclus (Multime A, Multime B) { int i; for (i=1; i<=Card(A); i++) if (!Apart(A->Elem[i],B)) return 0; return 1; } int Egale (Multime A, Multime B) { return Inclus(A,B) && Inclus(B,A); } int Egale (Multime A, Multime B) { return Inclus(A,B) && Inclus(B,A); }

62

void AdEl(TEl x, Multime A) { if (!Apart(x,A)) if (Card(A)>Cm-2) {cout << Card(A) << Cm << "!"; getch();} A->Elem[++(A->card)]=x; } void Vida(Multime A) { A->card=0; } void Init(Multime &A) { A = new Cet; Vida(A); } int E_Vida(Multime A) { return (A->card)==0; }

else

// ElMult.h \\
#define Cm 255 typedef int TEl; // Tipul elementelor mulimii

Un tip abstract de dat realizeaz o unificare (printr-o grupare de tip struct) ntre date (date membru) i operaiile (funcii membru) lor caracteristice. Funciile membru sunt considerate de tip inline iar definirea lor n afara structurii se face prin operatorul de rezoluie (::). n acest mod ns nu se realizeaz o protecie a datelor (accesul la date se poate face i prin alte funcii, nu numai prin cele membru), aceast protecie putnd fi realizat (aa cum vom vedea n cele ce urmeaz) cu ajutorul claselor. Exemplu:
#include <stdio.h>; #define Pi 3.141592 #include <conio.h>; #include <iostream.h>;

struct

{ float x,y; float r; void Init (float x0, float y0, float raza) { x=x0; y=y0; r=raza;} float Lung (); float Aria (); }; float Cerc::Lung () { return 2*Pi*r; } float Cerc::Aria () { return Pi*r*r; } void main (void) { Cerc C; C.Init(1,2,3); cout << "C(" << C.x << "," << C.y << "," << C.r << ")" << endl; cout << "Aria = " << C.Aria() << endl; cout << "Lung = " << C.Lung() << endl; getch(); }

Cerc

63

17. P rogramare o rientat o biect ( O O P )


OOP este o metod de implementare n care:
a) b) c)

Obiectele sunt elementele de baz, Orice obiect este o instan a unei clase, Clasele sunt legate (asociate) unele cu altele prin motenire.

Un limbaj este orientat obiect dac: a) Utilizeaz obiecte, b) Oblig obiectele s aparin unei clase, c) Permite motenirea. Limbajul C++ ofer noiunea de clas, prin care se pot forma ierarhii, deci putem vorbi de o programare orientat obiect (OOP). OOP nseamn realizarea unor programe alctuite dintr-o mulime de obiecte care interacioneaz pentru a rezolva problema propus, i permite reutilizarea elementelor descrise (a interfeei i a codului). Un obiect are o stare i un comportament (operaii descrise n interfaa obiectului) aceste dou componente fiind definite prin datele membru (variabile de instan) i respectiv prin funciile membru (metode).

OOP utilizeaz ormtoarele concepte:


clasa obiectul

- implementarea unui TAD, - instana unei clase, - mesajul prin care se asigur interfaa (operaiile).

metoda

OOP are urmtoarele caracteristici (proprieti) de baz:

ncapsularea motenirea

- gruparea datelor i a operaiilor definite pentru acestea, precum i protecia acestor date (ele neputnd fi accesate dect prin funciile membru). - pstrarea elementelor (date i funcii ale) unei clase (de baz), cu definirea de noi elemente construind o nou clas (derivat), formnd n felul acesta ierarhii de clase. Motenirea poate fi i multipl dac o clas motenete mai multe clase. - redefinirea (suprancrcarea) operaiilor (funciilor). ntr-o ierarhie pot fi mai multe funcii cu acelai nume, deci va fi efectuat operaia corespunztoare obiectului care o apeleaz. Determinarea operaiei se poate face la compilare (legare static) sau la execuie (legare dinamic, prin funcii vituale).

polimorfism

64

17.1. Definirea Claselor


O clas se declar ca i o structur, nlocuind cuvntul struct cu class. Protecia datelor se definete scriind modificatorul dorit (private, protected sau public) urmat de :. Descrierea unei clase conine att datele membru (variabilele de instan) ct i funciile membru (metodele), preciznd pentru acestea gradul de protecie, astfel: class Nume_clas {

{ [ Modificator_de_protecie: ] List_membrii }
}; unde:

Modificator_de_protecie { private, protected, public} private nu permite accesul din afara clasei,

, private fiind implicit, # +

protected permite accesul din clasele derivate, public permite accesul din afara clasei;

List_membrii { List_declaraii_date_membru, List_ declaraii _funcii_membru }

Datele de tip private () pot fi accesate doar de funciile membru sau funcii prietene (friend). O funcie membru a unei clase poate fi funcie prieten a altei clase, iar dac toate sunt prietene, atunci se poate declara clas prieten (friend). //

Vezi C8

Fiecare obiect al unei clase deine un set de date membru (variabile de instan). Funciile membru publice pot fi utilizate din orice funcie din program, pe cnd cele private doar din funciile membru ale clasei. Definirea funciilor membru (metodelor) se poate realiza: a) imediat (complet, antet plus corp) n definiia clasei (ca funcie inline) dac funcia nu conine multe instruciuni i nu conine structuri repetitive (apelul nu se face prin salt cu revenire), astfel: class Nume_clas { Tip_funcie Nume_metod ( ... ) { . . . }; }; // antet+corp

b)

ulterior (dac a fost declarat n definiia clasei doar prototipul funciei), utiliznd operatorul de rezoluie (de scop) astfel: Tip_funcie Nume_clas :: Nume_metod ( ... ) // :: operatorul de rezoluie { . . . }; // corpul funciei

65

Exemplu:
// // # include <conio.h> # include <iostream.h> Clasa Punct ----------------------------\\ \\

class Punct { float x, y; R2 public: Punct Punct Punct void CitP void TipP Punct& SimPb };

// ( ) (float x0, float y0) (Punct& P) (char* Mes); (char* Mes); ( );

private:

(x,y) e

{ x=0; y=0; } { x=x0; y=y0; } { x=P.x; y=P.y; }

void Punct::CitP (char* Mes) void Punct::TipP (char* Mes) Punct& Punct::SimPb( ) void { } main (void) . . .

{ cout << Mes; cin >> x >> y ; } { cout << Mes << x <<' '<< y << endl; } { float z=x; x=y; y=z; return *this; }

Un obiect este o instan a unei clase (o variabil de tipul clasei). Fiecare obiect aparine unei singure clase (aceasta putnd avea mai multe obiecte). Obiectele unei clase se declar astfel: Clas Exemplu:
// // # include <conio.h> # include <iostream.h> Obiecte Punct \\ ----------------------------\\

List_Obiecte;

class Punct { . . . }; . . . void { ); main (void) clrscr( Punct O,A(1,2); O.TipP(" O = "); A.TipP(" A = "); Punct B1; B1.CitP(" B1: "); Punct B2 (B1.SimPb()); B2.TipP(" B2= "); getche( ); }

66

Alocarea (i iniializarea) obiectelor se face cu o funcie membru specific numit constructor (cu numele Clas) iar dealocarea cu o funcie destructor (cu numele ~Clas). Exemplu:
// // # # # # # # include include include include include define Constructori - Destructori \\ ---------------------------- \\ <dos.h> <math.h> <conio.h> <graphics.h> <iostream.h> Cale "c:\\BorlandC\\Bgi"

class Grafic { int Gd, Gm; public: Grafic(int gd) { Gd=gd; initgraph(&Gd,&Gm,Cale);} ~Grafic( ) { closegraph(); } }; class Punct { float x, y; public: Punct Punct Punct Punct ~Punct // private: (x,y) e R2 ( ) (float x0, float y0) (Punct& P) (int, int, int); (); { x=0; y=0; } { x=x0; y=y0; } { x=P.x; y=P.y; }

int X0 () { return int(x); } int Y0 () { return int(y); } Punct& Transl(Punct&); }; Punct:: Punct(int x0,int y0,int c) { x=x0; y=y0; setcolor(c); circle(x,y,5);} Punct::~Punct( ) { setcolor(BLACK); circle(x,y,5);} Punct& Punct::Transl(Punct& T) { x+=T.x; y+=T.y; return *this; } void main (void) { Grafic Mod(DETECT); Punct C(getmaxx()/2,getmaxy()/2,WHITE); getche(); for (float Alfa=-1.57;Alfa<4.71;Alfa+=0.01) { float Raza=100; Punct M(Raza*cos(Alfa),Raza*sin(Alfa)); Punct P=M.Transl(C); Punct D(P.X0(),P.Y0(),YELLOW); delay(5); } getche(); }

// Centru

67

Componentele claselor (datele i funciile membru) se refer prin operatorul

sau

>, ca i n cazul unei structuri. Funciile membru refer direct componentele clasei (fr aceti operatori, utiliznd poinetrul this declarat automat ca pointer la obiectul curent). Exemplu:
// // # # # # # # include include include include include define Operatorii i > \\ ---------------------------- \\

<dos.h> <math.h> <conio.h> <graphics.h> <iostream.h> Cale "c:\\BorlandC\\Bgi"

class Grafic { int Gd, Gm; public: Grafic(int gd) { Gd=gd; initgraph(&Gd,&Gm,Cale);} ~Grafic( ) { closegraph(); } }; class Punct { float x, y; public: Punct ( ) { x=0; y=0; } Punct (float x0, float y0) { x=x0; y=y0; } Punct (const Punct& P) { x=Px; y=Py; } Punct (int, int, int); ~Punct (); Punct* Init (float x0, float y0) { x=x0; y=y0; return this; } int X0 () { return int(x); } int Y0 () { return int(y); } Punct* Transl(const Punct*); }; Punct:: Punct(int x0,int y0,int c) { x=x0; y=y0; setcolor(c); circle(x,y,5);} Punct::~Punct( ) { setcolor(BLACK); circle(x,y,5);} Punct* Punct::Transl(const Punct* T){ x+=T>x; y+=T>y; return this; } void main (void) { Grafic Mod(DETECT); Punct* C = new Punct(getmaxx()/2,getmaxy()/2,WHITE); float Raza=100; Punct* M = new Punct; for (float Alfa=-1.57;Alfa<4.71;Alfa+=0.02)

getche(); // { M C

M=M>Init(Raza*cos(Alfa),Raza*sin(Alfa)) >Transl(C); Punct *P=new Punct(M>X0(),M>Y0(),YELLOW); delay(3); // Desen. P delete P; } // Sterge P delete M; getche(); delete C; getche(); }

68

17.2. Constructori i Destructori


Un obiect este creat de un constructor al clasei i este ters (distrus) de ctre destructor. Constructorii permit iniializarea obiectelor cu (mai multe) funcii membru omonime (avnd acelai nume cu clasa i care difer prin lista parametrilor formali), fr a returna o valoare. Constructorul este apelat automat la crearea unui obiect. O clas trebuie s conin cel puin doi constructori:

un constructor implicit (fr parametri, care iniializeaz obiectele cu o valoare implicit), un constructor de copiere (care iniializeaz cu valoarea unui obiect existent, de acelai tip).

Exemplu:
// Constructori String \\
# include <Conio.h> # include <String.h> # include <Iostream.h>

class String { char* s; public: String (); // Constructor implicit String (const String&); // Constructor de copiere String (const char*); // Constructor de conversie String& operator=(const String&); // Operator de atribuire ~String (); // Destructor int Length (); // Lungimea sirului void Print (); // Tipareste sirul }; String::String () { s=new char; s[0]=0; } String::String (const String& S) { s=new char[S.Length( )+1];strcpy(s,S.s);} String::String (const char* S) { s=new char[ strlen(S)+1];strcpy(s,S); } String& String::operator=(const String& S) { if (s!=S.s) {delete []s; s=new char[S.Length()+1]; strcpy(s,S.s);} return *this;} String::~String () { delete []s;} int String::Length () { return strlen(s); } void String::Print () { cout << s << endl; } void main () { clrscr(); String Vid; Vid.Print (); String Prop (" Constructori pentru clasa String."); Prop.Print(); String Rand(Prop); Rand.Print(); String Rind=Rand; Rind.Print(); getche(); }

69

Antetul unui constructor al unei clase ce conine ca date membru obiecte alte altor clase este de forma: Clas (List_par_formali) : Obiect1(List_par_formali1),...,Obiectn(List_par_formalin) Exemplu:
#include <stdio.h>; #include <conio.h>; #include <iostream.h>; class P3D { float x,y,z; public: P3D () {x=0;y=0;z=0;} P3D (float x0, float y0, float z0) {x=x0;y=y0;z=z0;} void Tip(){ cout <<"P("<<x<<","<<y<<","<<z<<")"<<endl; } }; class Cerc { P3D x_y_r; public: Cerc () { }; Cerc (P3D C) { x_y_r=C; } Cerc (const Cerc & C0) { x_y_r = C0.x_y_r; } void Tip(){ cout << " Cerc "; x_y_r.Tip();} };

Cerc (float x0, float y0, float z0) : x_y_r(x0,y0,z0) { }

void main (void) { Cerc O; O.Tip(); Cerc C(4,5,6); C.Tip(); P3D P(1,2,3); P.Tip(); Cerc D(P); D.Tip(); Cerc E(D); E.Tip(); }

getch();

// Constructor implicit P3D O(0,0,0) // Constructor pentru obiect P3D // Constructor P3D // Constructor Cerc // Constructor de copiere

Destructorii realizeaz automat dealocarea obiectelor globale la sfritul programului, iar a celor locale la sfritul funciei. Obiectele alocate dinamic (cu new) se vor dealoca cu operatorul delete. Numele destructorului este compus din caracterul ~ urmat de numele clasei ( ~ Cl as ( ) ). Destructorii nu returneaz o valoare. Exemplu:
#include <iostream.h>; class Cerc { float x,y,r; public: Cerc (float x0, float y0, float r0) {cout << "Alocare ..." << endl; x=x0;y=y0;r=r0;} ~Cerc () {cout << "Dealocare..." << endl; } void Tip () {cout << " C("<<x<<","<<y<<","<<r<<")" << endl; } }; void main (void) { Cerc C(1,2,3); C.Tip(); }

// Rezultatele afiate:
Alocare ... C(1,2,3) Dealocare...

70

n exemplul urmtor se poate urmrii momentul n care acioneaz constructorul i destrucorul: / / Obiecte alocate dinamic ( operatorul d e l e t e )
#include <string.h>; #include <iostream.h>;

class

Natural { public:

char* Numar; Natural (char* Nr); ~Natural (); };

Natural::Natural(char* Nr) { Numar = new char[strlen(Nr)+1]; strcpy(Numar,Nr); cout << " Constr.Ob. ..." << Numar << endl; } Natural::~Natural() { cout << " ... Distr.Ob. " << Numar << endl; delete Numar; } void f(Natural x) { cout << " ... f(x) ... " << endl; } Natural x("123"); void main (void) { cout << "*Start*" << endl; Natural y("456"); f("789"); cout << "*Stop*" << endl; }
Constr.Ob. ...123 *Start* Constr.Ob. ...456 Constr.Ob. ...789 ... f(x) ... ... Distr.Ob. 789 *Stop* ... Distr.Ob. 456 ... Distr.Ob. 123

// Rezultatele afiate:

71

18. Specificarea claselor Limbajul UML(Unified Modeling Language)


UML specific entitile (clasele) dintr-un program i relaiile dintre ele astfel: Specificarea entitilor : numele clasei, date membru - protecie nume_dat : tip funcii membru - protecie nume_funcie (tip par.formali) : tip_funcie ( protecie poate fi (private), # (protected) sau + (public) ). numele claseidate membrufuncii membru Exemplu: Punct- x : float - y : float+ Punct ( ) + Punct (Punct&) +~Punct ( )

Specificarea relaiilor dintre clase : relaia de asociere : relaia de derivare : // prietenie // motenire

Punct- x : float - y : float+ Punct ( ) + Punct (Punct&) +~Punct ( )

Persoan- Nume : String+ Persoan ( ) + Persoan (Persoan &) +~Persoan ( )

Segment- A : Punct - B : Punct+ Segment ( ) + Segment (Segment&)


+~Segment ( )

Student- Facultate: String - Varst : int+ Student () + Student (Student &) +~Student ( )

72

19. Funcii i Clase Prietene (Friend)


O funcie este prieten cu o clas dac are acces la datele membru private ale acelei clase. O funcie prieten poate fi o funcie global sau chiar o funcie membru a altei clase. O clas este prieten cu o alt clas dac ea are acces la datele membru ale acesteia. O funcie, respectiv o clas prieten se declar utiliznd cuvntul friend astfel: friend Tip_funcie Nume_funcie ( List_parametri_formali ); // Funcie friend global b) friend Tip_funcie Nume_clas::Nume_funcie(List_par._formali); // Funcie friend membru c) friend Nume_clas; // Clas friend
a)

Urmtorul exemplu, nu este corect, deoarece elementul C.y nu este accesibil:


# include <math.h> #include <iostream.h>

// Funcie friend membru

class Punct {
public:
};

float x,y;

// private:
Punct ( ) { x= 0, y= 0; } Punct (float x0, float y0) { x=x0, y=y0; }

class Cerc

public:

Punct C;

Cerc (Punct O, float raza) { C=O, r=raza;}

float r;

};

int TaieOx() { return fabs(C.y)<r; } //inaccesibil

void main () { Punct C(10,10);

Cerc c(C,4); if (c.TaieOx()) cout << " Cercul c intersecteaza axa Ox "; else cout << " Cercul c nu intersecteaza axa Ox ";
// secret world

O soluie pentru a rezolva aceast problem, ar putea fi declararea funciei membru TaieOx ca funcie prieten a clasei Punct. Aceast modificare nu este suficient deoarece clasa Cerc nu a fost nc (deja!) definit, deci aceasta trebuie mai nti declarat, iar pentru c aceasta refer clasa Punct vom declara (pur i) simplu clasa Punct pentru a putea referi centrul cercului ca pointer la Punct. Pentru c y nu este dat membru pentru cerc, funcia TaieOx nu poate fi definit imediat, ci doar ulterior, dup declararea complet a clasei Punct.
# include <math.h> #include <iostream.h>

// Funcie friend membru

class Punct; class Cerc { public:


};

Punct* C; float r; Cerc (Punct O, float raza) { *C=O; r=raza;} int TaieOx(); float x,y;
Punct ( ) { x= 0, y= 0; } Punct (float x0, float y0) { x=x0, y=y0; }

class Punct {
public:
};

friend int Cerc ::TaieOx();

int Cerc::TaieOx() { return fabs(C->y)<r; }


void main () { Punct C(10,10); Cerc c(C,14); if (c.TaieOx()) cout << " Cercul c intersecteaza axa Ox "; else cout << " Cercul c nu intersecteaza axa Ox "; }

73

Exemple:

//
# # # # # include include include include define

Functie globala friend

\\

class Grafic { int Gd, Gm; public: Grafic(int gd) { Gd=gd; initgraph(&Gd,&Gm,Cale);} ~Grafic( ) { closegraph(); } }; class Punct { int x, y; public: Punct (int x0=0,int y0=0) { x=x0; y=y0; putpixel(x,y,x+y);} Punct (Punct& P) { x=P.x; y=P.y; } void Muta () { moveto(x,y); } void Trag () { lineto(x,y); } ~Punct () { } friend Punct Mijloc(Punct,Punct); // Functii globale friend Punct Afin (Punct,Punct,float); // friend }; Punct Mijloc (Punct A, Punct B) { Punct M (int((A.x+B.x)/2), int((A.y+B.y)/2)); return M; } Punct Afin (Punct A, Punct B,float t) { Punct M (int((1-t)*A.x+t*B.x+0.5), int((1-t)*A.y+t*B.y+0.5)); return M; } class Segment{Punct A, B; // Capetele Segm. public: Segment ( ) : A(), B() { } Segment (Punct P, Punct Q) { A=P; B=Q; A.Muta();B.Trag(); } Segment (Segment& AB) { A=AB.A; B=AB.B; } ~Segment () { A.Muta();B.Trag(); } Punct Mijlocs () { return Mijloc(A,B);} //::Mijloc Punct Afins (float t) { return Afin(A,B,t);} //::Mijloc }; void main (void) { Grafic Mod(DETECT); setwritemode(XOR_PUT); setbkcolor(BLUE); Punct* A = new Punct (300,100); // A Punct* B = new Punct (100,300); // B Punct* C = new Punct (500,300); // C Segment* AB = new Segment (*A,*B); // AB Segment* BC = new Segment (*B,*C); // BC Segment* CA = new Segment (*C,*A); // CA for (float Alfa=0; Alfa<1; Alfa+=0.01) { Punct* P=new Punct(AB->Afins(Alfa)); Punct* Q=new Punct(CA->Afins(Alfa)); Segment*PQ = new Segment (*P,*Q); PQ->Mijlocs(); delay(22); // [Punct M=] delete PQ; delete P; delete Q; } delete AB; delete A; delete B; getche(); delete BC; delete CA; }

<dos.h> <conio.h> <graphics.h> <iostream.h> Cale "c:\\BorlandC\\Bgi"

74

# # # # # #

include include include include include define

<dos.h> <math.h> <conio.h> <graphics.h> <iostream.h> Cale "c:\\BorlandC\\Bgi"

//

Functie membru friend

\\

float Sqr (int x) int Sqrt (float x) class Grafic { int Gd, public: };

{ return float(x)*x; } { return ceil (sqrt(x)+0.5); } Gm; Grafic(int gd) { Gd=gd; initgraph(&Gd,&Gm,Cale); setbkcolor(BLUE); } ~Grafic( ) { getche(); closegraph(); }

class Punct; class Segment{Punct *A, *B; public: Segment Segment Segment ~Segment Punct Mijloc }; class Punct { int x, y; public: Punct Punct Muta Trag ~Punct friend Punct void void

// Capetele Segm. ( ) : A(), B() { } (Punct*,Punct*); (Segment&); (); (); (int x0=0,int y0=0) { x=x0; y=y0; putpixel(x,y,x+y);} (Punct& P) { x=P.x; y=P.y; } () { moveto(x,y); } () { lineto(x,y); } () { } Segment::Mijloc();

}; Segment:: Segment (Punct *P, Punct *Q) { A=P; B=Q; A->Muta(); B->Trag(); } Segment:: Segment (Segment& AB) { A=AB.A; B=AB.B; } Segment::~Segment ( ) { A->Muta(); B->Trag(); } Punct Segment::Mijloc() { Punct M ( int((A->x+B->x)/2), int((A->y+B->y)/2)); return M; } void main (void) { Grafic Mod(DETECT); setwritemode(XOR_PUT); int Lung=400; Punct* O = new Punct; // Originea Punct* X = new Punct(Lung); Punct* Y = new Punct(0,Lung); Segment* OX = new Segment(O,X); // Axa Ox; Segment* OY = new Segment(O,Y); // Axa Ox; for (int x=1; x<Lung; x++) { Punct* P = new Punct (x); Punct* Q = new Punct (0,Sqrt(Sqr(Lung)-Sqr(x))); Segment* PQ = new Segment(P,Q); PQ->Mijloc(); delay(9); delete PQ; delete P; delete Q; } getche(); delete OX; delete OY; delete O; delete X; delete Y; }

75

# include <dos.h> # include <math.h> # define Cale "c:\\BorlandC\\Bgi"

//

# include <conio.h>

Clasa friend

# include <graphics.h>

# include <iostream.h>

\\

struct palettetype pal;

class Grafic { int Gd, Gm; getpalette(&pal); }

float Pi=3.1416, Alfa;

public: Grafic(int gd) { Gd=gd; initgraph(&Gd,&Gm,Cale); { getche(); closegraph(); }

public: Punct (float x0=0,float y0=0) { x=int(x0);y=int(y0); } Punct (float x0,float {x=int(x0+0.5);y=int(y0+0.5);putpixel(x,y,c);} Punct (Punct& P) { x=P.x; y=P.y; } void Muta () { moveto(x,y); } void Trag () { lineto(x,y); } ~Punct () { }

class Punct { int

};

~Grafic( )

x, y;

y0,int

c)

friend Segment; friend Cerc; friend Triunghi; }; class Segment{Punct A, B; int Cul;

friend Triunghi; }; Punct Segment::Mijloc () { Punct M(int((A.x+B.x)/2),int((A.y+B.y)/2)); return M;} class Cerc { int x, y, r;
public: Cerc (int x0=0,int y0=0,int r0){ x=x0;y=y0;r=r0; circle(x,y,r);} Cerc (Punct P, int r0) { x=P.x; y=P.y; r=r0; circle(x,y,r);} Cerc (Cerc& C) { x=C.x; y=C.y; r=C.r; } Punct PeCerc(float a){ Punct M(x+r*cos(a),y-r*sin(a)); return M;} ~Cerc () { /*circle(x,y,r);*/ }

public: Segment ( ) : A(), B() { } Segment (Punct P, Punct Q){ Cul=getcolor();setcolor (Cul); A=P; B=Q; A.Muta();B.Trag(); } Segment (Segment& AB) { A=AB.A; B=AB.B; } ~Segment () { setcolor(Cul);A.Muta();B.Trag(); } Punct Mijloc ();

// Capetele Segm.

}; class Triunghi { Punct A, B, C;

public: Triunghi ( ) : A(), B(), C() { } Triunghi (Punct,Punct,Punct); Triunghi (Triunghi& ABC) { A=ABC.A; B=ABC.B; C=ABC.C;} ~Triunghi (){}

// Varfuri

Punct CentruGr(){ Punct G((A.x+B.x+C.x)/3,(A.y+B.y+C.y)/3,15); return G; } { A=P; B=Q; C=R; Segment BC(B,C); Segment CA(C,A); AAP(A,BC.Mijloc()); CCP(C,AB.Mijloc());
g b 0, Cf); ,63-Cf,0); Cf, 63); Cf, Cf);

}; Triunghi::Triunghi(Punct P,Punct Q,Punct R) setcolor(YELLOW); Segment AB(A,B); setcolor(LIGHTBLUE); Segment Segment BBP(B,CA.Mijloc());Segment
int Cf=int((Pi-fabs(Alfa-Pi))/Pi*63); // setrgbpalette(pal.colors[BLUE], setrgbpalette(pal.colors[YELLOW], setrgbpalette(pal.colors[LIGHTBLUE], setrgbpalette(pal.colors[WHITE], delay(int(pow((fabs(Alfa-Pi)+0.3)*Pi,2)));

void
{

main (void)

r 0, 63 0, Cf, }

Punct O(300,250); Cerc c(O,200); // centru, cerc float uA=Pi/2, uB=Pi+Pi/6, uC=-Pi/4; for (Alfa=0; Alfa<2*Pi; Alfa+=0.01) { Triunghi ABC(c.PeCerc(Alfa+uA),c.PeCerc(Alfa+uB),c.PeCerc(Alfa+uC)); ABC.CentruGr(); }

Grafic Mod(DETECT); setwritemode(XOR_PUT); setbkcolor(BLUE);

76

20. M e m b r i s t a t i c i ( S t a t i c )

// $ :

Fiecare obiect dintr-o clas deine toate datele membru (atributele) acesteia. Exist ns posibilitatea ca toate instanele unei clase s dein anumite atribute comune tuturor obiectelor clasei respective. Aceti membri (date, funcii) statici au acelai regim de protecie ca i ceilali membrii.

20.1. Atribute (Date membru) Statice

// $ :

Datele membru statice, care urmeaz s fie utilizate de ctre toate obiectele clasei, se definesc prin specificatorul static astfel: class Nume_clas { }; Datele membru statice, se declar (se iniializeaz) explicit n afara clasei: Tip_dat_membru Nume_clas :: Dat_membru [ = Valaore ]; Referirea (utilizarea) datelor membru statice se poate face astfel: Nume_clas :: Dat_membru // Referire natural (global) la clas b) Obiect Dat_membru // Referire particular la un obiect c) Pointer_Obiect >Dat_membru // Referire particular prin pointer
a)

static

List_Declaraii_date_membru ;

// $ :

n urmtorul exemplu, se numr cte Puncte sunt utlizate la un moment dat n program, utiliznd ca dat comun pentru toate punctele (ntreaga clas) Nr_Ob: // Membru Static
# include <conio.h> # include <iostream.h>

class Punct { public:

float

x, y; { x=0; y=0; Nr_Ob++; { this->x=x; this->y=y; Nr_Ob++; { x=P.x; y=P.y;Nr_Ob++; { Nr_Ob--; } } } } // $: // se iniializeaz

Punct () Punct (float x,float y) Punct (Punct& P) ~Punct () static }; int Punct::Nr_Ob=0; int Nr_Ob;

77

void main (void) { Punct A,B; cout << "Initial:" << Punct::Nr_Ob << endl; for (int i=1; i<=5; i++) { Punct M(i,i); Punct Q(M); cout << "i>> "<<i<<":"<< Punct::Nr_Ob <<endl; if (i%2==0) { Punct* N=new Punct(i,i); Punct R(*N); cout <<"i<<"<<i<<":"<< Punct::Nr_Ob <<endl; cout <<"i<<"<<i<<":"<< R .Nr_Ob <<endl; cout <<"i<<"<<i<<":"<< N->Nr_Ob <<endl; delete N; } cout << "i..." <<i<< ":"<< Punct::Nr_Ob <<endl; } cout << "Final..." << Punct::Nr_Ob << endl; }

clrscr();

// Cl::Static. // Ob .Static! // Ob->Static!

getche();

n exemplul urmtor, sunt utilizai membri statici a,b,c,d pentru a memora domeniul minim care conine toate punctele curbei (definite parametric) care se deseneaz:
# include <math.h> # include <conio.h> # include <graphics.h> # define Cale "c:\\BorlandC\\Bgi" class Grafic { int Gd, Gm; public: Grafic(int gd) { Gd=gd; initgraph(&Gd,&Gm,Cale); setbkcolor(BLUE);} ~Grafic( ) { getche(); closegraph();} }; int u (float); int v (float);

// Membri Statici

class Punct { float x, y; public: Punct () { x=0; y=0; } void Atrib (float x,float y) { this->x=x; if if this->y=y; if if
void void Punct Muta Trag ~Punct (Punct& P) { x=P.x; y=P.y; } () { moveto(u(x),v(y)); } () { lineto(u(x),v(y)); } () { }

(x<a) (x>b) (y<c) (y>d)

a=x; else b=x; c=y; else d=y; }

static float a,b, c,d; // Fereastra Real }; float Punct::a, Punct::d, Punct::b, Punct::c; // Fereastra Real int u1=110, v1=20, u2=500, v2=430; // Fereastra Ecran int u (float x) { return ((x-Punct::a)/(Punct::b-Punct::a)*(u2-u1)+u1); } int v (float y) { return ((y-Punct::d)/(Punct::c-Punct::d)*(v2-v1)+v1); }
float x (float t) float y (float t)

void main (void) { int i,n=1000; float Pi=3.14153; Grafic Mod(DETECT); Punct P[1001]; Punct::b=Punct::a=x(0); Punct::d=Punct::c=y(0); for (i=0; i<=n; i++) { float Alfa=2*Pi*i/n; P[i].Atrib(x(Alfa),y(Alfa));} P[0].Muta(); setcolor(WHITE); for (i=1; i<=n; i++) P[i].Trag(); }

{ return cos(2*t)*cos(t); } { return cos(4*t)*sin(t); }

// x(t) // y(t)

78

20.2. Metode (Funcii membru) Statice

// $ :

Metodele (Funciile membru) statice, acioneaz doar asupra atributelor statice (ale claselor), deci nu pot aciona asupra atributelor obiectului curent (deoarece nu li se transmite poinetrul this). De asemenea ele pot apela doar metodele statice. Pot ns aciona asupra atributelor unui anumit obiect prin operatorii sau >. Metodele statice, se definesc prin specificatorul static astfel: class Nume_clas { static Tip_funcie Nume_funcie ( List_par_formali ) // $ : }; Referirea (utilizarea) metodelor statice se face astfel: a) Nume_clas :: Funcie_membru (List_par_actuali) // Referire natural la clas b) Obiect Funcie_membru (List_par_actuali ) // Referire la un obiect c) Pointer_Obiect > Funcie_membru (List_par_actuali) // Referire prin pointer n urmtorul exemplu, se determin fereastra real (definit prin cele dou puncte diagonal opuse St_Sus, Dr_Jos) utiliznd funciile statice MinX, MaxX, MinY, MaxY pentru a determina domeniul minimal care include punctele din grafic.
# include <math.h> # include <conio.h> # define Cale "c:\\BorlandC\\Bgi" class Grafic { int Gd, Gm; public: Grafic(int gd) { Gd=gd; initgraph(&Gd,&Gm,Cale); setbkcolor(BLUE);} ~Grafic( ) { getche(); closegraph();} }; int u (float); int v (float); class Punct { float x, y; public: Punct () { x=0; y=0; }

// Funcii Statice

# include <graphics.h>

void

Atrib (float x,float y){ this->x=x; if (x<MinX()) St_Sus.x=x; else if (x>MaxX()) Dr_Jos.x=x; this->y=y; if (y<MinY()) Dr_Jos.y=y; else if (y>MaxY()) St_Sus.y=y; }
Punct (Punct& P) Muta () Trag () ~Punct () { } { x=P.x; y=P.y; } { moveto(u(x),v(y)); } { lineto(u(x),v(y)); }

void void

}; Punct Punct::St_Sus, Punct::Dr_Jos;


int u1=110, v1=20, float x (float t) float y (float t) u2=500, v2=430;

static static static static static

Punct float float float float

St_Sus, Dr_Jos; MinX() { return MaxX() { return MinY() { return MaxY() { return

St_Sus.x; Dr_Jos.x; Dr_Jos.y; St_Sus.y;

} } } }

// // // //

Metod Metod Metod Metod

// Fereastra Reala Static Static Static Static // Fereastra Reala


// Fereastra Ecran

int u (float x) { return ((x-Punct::MinX())/(Punct::MaxX()-Punct::MinX())*(u2-u1)+u1); } int v (float y) { return ((y-Punct::MaxY())/(Punct::MinY()-Punct::MaxY())*(v2-v1)+v1); }


void main (void) { int i,n=1000; Punct P[1001];
{ return cos(2*t)*cos(t); }// x(t) { return cos(4*t)*sin(t); }// y(t)

Punct::St_Sus=Punct::Dr_Jos=P[0]; for (i=1; i<=n; i++) { float Alfa=2*Pi*i/n; P[i].Atrib(x(Alfa),y(Alfa));} P[0].Muta(); setcolor(WHITE); for (i=1; i<=n; i++) P[i].Trag();

float Pi=3.14153; P[0].Atrib(x(0),y(0));

Grafic Mod(DETECT);

21. Pointeri la Metode


O metod a unei clase poate fi referit (apelat) i printr-un pointer la ea.

79

Definirea unui pointer la o metod se poate face astfel: Tip_funcie (Nume_clas :: *Nume_Pointer ) ( List_par_formali )
// sau cu typedef

Iniializarea unui pointer la o metod se poate realiza astfel: Nume_Pointer = & Nume_clas :: Nume_Metod;
// se pot realiza i la definire

Referirea unui pointer la o metod (apelarea metodei) :

(Nume_Obiect . *Nume_Pointer ) ( List_par_actuali )

De exemplu, pentru programul anterior, modificrile necesare pentru a putea apela cele dou metode Muta i Trag ale clase Punct pot fi urmtoarele:

// Pointeri la metode
x, y; Atrib
Punct (Punct& P) { } public: Punct () { }

class Punct { float void

void void

~Punct () { } static Punct St_Sus, Dr_Jos; static float MinX() { return St_Sus.x; }

Muta () Trag ()

{ moveto(u(x),v(y)); } { lineto(u(x),v(y)); }

// Metod Static

}; void main (void) {

typedef void (Punct :: *P_Met)(); P_Met Pm[2] = {&Punct::Muta,&Punct::Trag};

// Definire // Iniializare // Def+Ini // Apel Muta // Apel Trag

// sau: // void (Punct :: *Pm[2])() = {&Punct::Muta,&Punct::Trag}; (P[0].*Pm[0])(); setcolor(WHITE); for (i=1; i<=n; i++) (P[i].*Pm[1])();
}

80

Un alt exemplu, care utilizeaz pointeri la metode ( Triun, Drept i Romb) este urmtorul:
# include <math.h> # include <conio.h> # include <graphics.h> # define Cale "c:\\BorlandC\\Bgi" class Grafic { int Gd, Gm; public: Grafic(int gd) { Gd=gd; initgraph(&Gd,&Gm,Cale); setbkcolor(BLUE);} ~Grafic( ) { getche(); closegraph();} }; int u (float); int v (float);

// Pointeri la *Metode

class Punct { float x, y; public: Punct () { x=0; y=0; } void Atrib (float x,float y) { this->x=x; if (x<MinX()) St_Sus.x=x; else if (x>MaxX()) Dr_Jos.x=x; this->y=y; if (y<MinY()) Dr_Jos.y=y; else if (y>MaxY()) St_Sus.y=y; } Punct (Punct& P) { x=P.x; y=P.y; }

void void void void

Muta () Triun () Drept ()

Romb ()
() { } St_Sus, Dr_Jos; MinX() { return MaxX() { return MinY() { return MaxY() { return

}; Punct Punct::St_Sus, Punct::Dr_Jos; // Fereastra Reala int u1=110, v1=20, u2=500, v2=430; // Fereastra Ecran int u (float x) { return ((x-Punct::MinX())/(Punct::MaxX()-Punct::MinX())*(u2-u1)+u1); } int v (float y) { return ((y-Punct::MaxY())/(Punct::MinY()-Punct::MaxY())*(v2-v1)+v1); } float x0 (float t) { return cos(4*t)*cos(t); } // x(t) float y0 (float t) { return cos(2*t)*sin(t); } // y(t) float x1 (float t) { return cos(2*t)*cos(t); } // x(t) float y1 (float t) { return cos(4*t)*sin(t); } // y(t) float x2 (float t) { return cos(t); } // x(t) float y2 (float t) { return sin(t); } // y(t)

~Punct static Punct static float static float static float static float

{ moveto(u(x),v(y)); } { setcolor(WHITE); Muta(); moverel(0,-3); linerel(-2,5); linerel(4,0); linerel(-2,-5);} { setcolor(LIGHTRED); Muta(); moverel(-2,-2); linerel(0,4); linerel(4,0); linerel(0,-4);linerel(-4,0);} { setcolor(YELLOW); Muta(); moverel(0,-3); linerel(-2,3); linerel(2,3); linerel(2,-3);linerel(-2,-3);}
St_Sus.x; Dr_Jos.x; Dr_Jos.y; St_Sus.y; } } } } // Fereastra Reala

void main (void) { int i,j, n=300; float Pi=3.14153; Grafic Mod(DETECT); Punct P[3][301]; typedef float (*Functie)(float); Functie x[3]={&x0,&x1,&x2} ,y[3]={&y0,&y1,&y2}; for (j=0; j<=2; j++) P[j][0].Atrib((*x[j])(0),(*y[j])(0)); Punct::St_Sus=Punct::Dr_Jos=P[0][0]; for (j=0; j<=2; j++) for (i=0; i<=n; i++) { float Alfa=2*Pi*i/n; P[j][i].Atrib((*x[j])(Alfa),(*y[j])(Alfa)); } void (Punct::*Desen[3])()={&Punct::Triun,&Punct::Drept,&Punct::Romb}; for (j=0; j<=2; j++) for (i=0; i<=n; i++) (P[j][i].*Desen[j])(); } // Mummers Dance

81

22. Suprancrcarea operatorilor


Anumite operaii se pot exprima mult mai bine prin operatori. Nu se pot defini operatori noi, dar se pot suprancrca cei existeni ( +, <, ++, +=, >, [ ], ( ), new, delete, , mai puin operatorii
*,

:: , ?: ), fr a modifica ns aritatea, prioritatea sau

asociativitatea. Suprancrcarea se poate face cu: a) funcii membru - numrul parametrilor fiind egal cu aritatea operatorului minus unu, deoarece un operand este chiar obiectul curent pentru care se apeleaz metoda (acesta putnd fi referit prin pointerul this), b) funcii prietene - numrul parametrilor fiind egal cu aritatea operatorului. Redefinirea unui operator se realizeaz printr-o funcie (prieten sau membru) al crei nume este compus din cuvntul operator urmat de operatorul propriuzis (+, <, ) . Exemplu:
# include <Conio.h> # include <String.h>

//

Op erat ori de c on c at en are + &

\\
# include <Iostream.h>

class String { char* s; public: String (); String (const String&); String (const char*); String& operator=(const String&);

// // // //

Constructor Constructor Constructor Operator de

implicit de copiere de conversie atribuire

friend

String operator+(String&); String operator&(String&,String&);

// Operator + (concatenare) // Operator & (concatenare)


// Destructor // Lungimea sirului // Tipareste sirul

a) b)

~String (); int Length (); void Print ();

}; String::String () { s=new char; s[0]=0; } String::String (const String& S) { s=new char[S.Length( )+1];strcpy(s,S.s);} String::String (const char* S) { s=new char[ strlen(S)+1];strcpy(s,S); } String& String::operator=(const String& S) { if (s!=S.s) {delete []s; s=new char[S.Length()+1]; strcpy(s,S.s);} return *this; } String String::operator+(String& S) // funcie membru a) { char* sS=new char[this->Length()+S.Length()+1]; strcpy(sS,s); strcpy(sS+this->Length(),S.s); String Rez(sS); delete sS; return Rez; } String::~String () { delete []s;} int String::Length () { return strlen(s); } String operator&(String& s,String& S) // funcie prieten b) { char* sS=new char[s.Length()+S.Length()+1]; strcpy(sS,s.s); strcpy(sS+s.Length(),S.s); String Rez(sS); delete sS; return Rez; } void String::Print () { cout << s << endl; }
void main () { String Nume("Popescu"), Prenume("Ionel"); String Nume_Prenume=Nume+" "+Prenume; Nume_Prenume.Print(); String Prenume_Nume=Prenume&" "&Nume; Prenume_Nume.Print(); } clrscr();

getche();

82

22.1. Operatorul de asignare ( atribuire ) i iniializare (=)


Operatorul de atribuire (=) se poate utiliza i pentru obiecte, acesta fiind suprancrcat implicit i realizeaz copierea datelor membru. Dac ns datele membru sunt referine (pointeri) la nite variabile dinamice, atunci prin copiere se vor obine dou obiecte care refer acceai zon de memorie, iar la dealocare se va elibera aceeai zon de dou ori, iar alta niciodat, ceea ce ne oblig, n aceast situaie, la redefinirea (suprancrcarea) acestui operator. Prin aceasta, coninutul variabilelor dinamice sunt identice, dar la adrese diferite, astfel nct dac un obiect i modific valorile, cellalt obiect rmne neschimbat. Pentru o declaraie de tipul Clas Obiect; se va apela constructorul implicit, sau cel cu toi parametrii implicii, iar pentru o declaraie de forma Clas Obiect=Ob; se va apela constructorul de copiere (i nu operatorul de atribuire) ca i la o declaraie de forma Clas Obiect(Ob); . Constructorul de copiere se mai poate apela dac parametrul unei funcii este un obiect sau dac funcia returneaz un obiect. Exemplu:
//
# include <Conio.h> # include <String.h> # include <Iostream.h>

C l asa Nu m ar Nat u ral

(Op.

= ) \\

class Natural { char* s; int Lung(unsigned long); public: Natural ( ); Natural (const Natural&); Natural (unsigned long); Natural& operator= (const Natural&); Natural operator+ (const Natural&); Natural operator- (const Natural&); int int int int int int ~Natural int Length void Input void Print }; operator< (const operator<=(const operator> (const operator>=(const operator==(const operator!=(const (); (); (); (); Natural&); Natural&); Natural&); Natural&); Natural&); Natural&); // Constructor implicit // ... de copiere // ... de conversie // Operator de atribuire // Operator de adunare // Operator de scadere // // // // // // // // // // ... ... ... ... ... ... relational ... ... ... ... ... < <= > >= == <>

Destructor Numarul de cifre Citeste numar Tipareste numar

83

Natural::Natural ( ) { s=new char[2]; s[0]='0'; s[1]=0; } Natural::Natural (const Natural& S) { s=new char[strlen(S.s)+1];strcpy(s,S.s);} Natural::Natural (unsigned long S) { int n=Lung(S); s=new char[n+1]; s[n]=0; for(int i=n-1;i>=0;i--) {s[i]=S%10+48; S/=10;} } Natural& Natural::operator = (const Natural& S) { if (s!=S.s) { delete []s; s=new char[strlen(S.s)+1]; strcpy(s,S.s);} return *this; } char* Suma (const char*, const char*); Natural Natural::operator + (const Natural& S) { Natural Sum; Sum.s=Suma(s,S.s); return Sum; } char* Dif(const char*, const char*); Natural Natural::operator - (const Natural& S) { Natural D; D.s=Dif(s,S.s); return D; } int Natural::operator< (const Natural& S) { if (strlen(s)<strlen(S.s)) return 1; else if (strlen(s)>strlen(S.s)) return 0; else return strcmp(s,S.s)<0; } int Natural::operator<=(const Natural& S) { return !(*this>S); } int Natural::operator> (const Natural& S) { return S< *this; } int Natural::operator>=(const Natural& S) { return S<=*this; } int Natural::operator==(const Natural& S) { return strcmp(s,S.s)==0; } int Natural::operator!=(const Natural& S) { return strcmp(s,S.s)!=0; } int Natural:: Length () { return strlen(s); } void Natural:: Print () { cout << s << endl; } void Natural:: Input () { char* x=new char[100]; cin >> x; delete []s; s=new char[strlen(x)+1]; strcpy(s,x); delete x; } Natural::~Natural() { delete []s; } int Natural::Lung(unsigned long n) { if (n<10) return 1; else return Lung(n/10)+1;} char* Suma (const char* a, const char *b) { int m=strlen(a), n=strlen(b), i=m-1, j=n-1, t=0; if (m<n) return Suma(b,a); char* c=new char[m+1]; c[m]=0; for ( ; i>=0; i--) { if (j>=0) c[i]=a[i]+b[j]+t-48; else c[i]=a[i]+t; if(c[i]>'9'){ c[i]-=10; t=1 ; } else t=0; j--; } if (!t) return c; char* d=new char[m+2]; for (i=0,d[0]='1'; i<=m; i++) d[i+1]=c[i]; delete []c; return d; } char* Dif (const char* a, const char *b) { int m=strlen(a), n=strlen(b), i=m-1, j=n-1, t=0; char* c=new char[m+1]; c[m]=0; for ( ; i>=0; i--) { if (j>=0) c[i]=a[i]-b[j]-t+48; else c[i]=a[i]-t; if(c[i]<'0'){ c[i]+=10; t=1 ; } else t=0; j--; } char *d=c; while((*d=='0') && *(d+1)) d++; strcpy(c,d); return c; }

void main () { Natural a,b; cout << " a : "; a.Input(); cout << " b : "; b.Input(); cout << " a+b = "; (a+b).Print(); ; cout << "|a-b|= "; if (a>=b) (a-b).Print(); else (b-a).Print(); }

clrscr();

getche();

84

22.2. Operatorii de atribuire += , = , * = , /=


Aceti operatori (+=, =, *=, /=) nu sunt suprancrcai automat, deci dac dorim s-i utilizm va trebui s i redefinim (aa cum se poate vedea n exemplul urmtor suprancrcarea operatorilor +=, =). Exemplu:
//
# include <Conio.h> # include <String.h>

C l asa Nu m ar Nat u ral

(Op.

+=, -= ) \\
# include <Iostream.h>

class Natural { char* s;


int Lung(unsigned long); public: Natural Natural Natural Natural& Natural Natural ( ); (const Natural&); (unsigned long); operator= (const Natural&); operator+ (const Natural&); operator- (const Natural&); // // // // // // Constructor implicit ... de copiere ... de conversie Operator de atribuire Operator de adunare Operator de scadere // ... de ad.&.atr. // ... de sc.&.atr. // ... relational < // ... ... <= // ... ... > // ... ... >= // ... ... == // ... ... <> // Destructor // Numarul de cifre // Tipareste numar

Natural& operator+=(Natural&); Natural& operator-=(Natural&);


int int int int int int ~Natural int Length void Print }; operator< (const operator<=(const operator> (const operator>=(const operator==(const operator!=(const (); (); (); Natural&); Natural&); Natural&); Natural&); Natural&); Natural&);

Natural::Natural ( ) { } Natural::Natural (const Natural& S) { } Natural::Natural (unsigned long S) { } Natural& Natural::operator= (const Natural& S){ } char* Suma (const char* a, const char *b) { } char* Dif (const char* a, const char *b) { }

Natural Natural::operator+ (const Natural& S){ Natural Sum; Sum.s=Suma(s,S.s); return Sum;} Natural Natural::operator- (const Natural& S){ Natural D; D.s=Dif(s,S.s); return D;}

Natural& Natural::operator +=(Natural& S){return *this = *this + S;} Natural& Natural::operator -=(Natural& S){return *this = *this - S;}
int Natural::operator< (const Natural& int Natural::operator<=(const Natural& int Natural::operator> (const Natural& int Natural::operator>=(const Natural& int Natural::operator==(const Natural& int Natural::operator!=(const Natural& int Natural:: Length () { } void Natural:: Print () { } Natural::~Natural() { } int Natural::Lung(unsigned long n) { } S) S) S) S) S) S) { { { { { { } } } } } }

void main () { Natural a(125),b(175); while (a!=b) if (a>b) a-=b; else b-=a; if (a==1) cout << " Prime intre ele "; else { cout << "Cmmdc="; a.Print(); } }

clrscr(); getche();
.

85

22.3. Operatorii de incrementare (++) i decrementare ( )


Continund cu exemplul anterior, dorim s suparancrcm operatorii de incrementare si decrementare, mai nti cei prefixai ( ++x, x), unde nu sunt probleme deosebite, apoi ce postfixai (x++, x). Pentru a suprancrca i operatorii de incrementare postfixai vom aduga cte o funcie membru avnd un parametru de tip int (care nu se va folosi, i care automat la un apel va lua valoarea zero). Exemplu:
# include <Conio.h> # include <String.h> public:

//

C l asa Nu m ar Nat u ral (Op . ++x, - - x, x+ +, x- -) \\


# include <Iostream.h> int Lung(unsigned long); ( ); (const Natural&); (unsigned long); operator= (const Natural&); operator+ (const Natural&); operator- (const Natural&); // // // // // // Constructor ... de ... de Operator de Operator de Operator de implicit copiere conversie atribuire adunare scadere

class Natural { char* s;


Natural Natural Natural Natural& Natural Natural

Natural& Natural Natural& Natural

operator operator operator operator

++(); ++(int); --(); --(int);

// // // //

int operator < (const Natural&); ~Natural (); int Length ();

... prefixat incr ... postfixat ... ... prefixat decr ... postfixat ... // ... relational < // Destructor // Numarul de cifre

ostream& Tip (ostream& S); istream& Cit (istream& S);


Natural::Natural ( ) { } Natural::Natural (const Natural& S) { } Natural::Natural (unsigned long S) { } Natural& Natural::operator= (const Natural& S){ Natural Natural::operator+(const Natural& S) { Natural Natural::operator-(const Natural& S) { int Natural::operator< (const Natural& S) { Natural::~Natural() { }

// cout << x // cin >> x

};

} } } } // ++x // --x // x++ // x--

Natural& Natural::operator++() { Natural& Natural::operator--() { Natural Natural::operator++(int){ Natural Natural::operator--(int){

return *this=*this+1; } return *this=*this-1; } Natural x(*this); *this=*this+1; return x;} Natural x(*this); *this=*this-1; return x;}

ostream& Natural::Tip (ostream& S) { S << s; return S; } istream& Natural::Cit (istream& S) { char* x=new char[256]; S>>x; delete[]s; s=new char[strlen(x)+1]; strcpy(s,x); delete x; return S; } ostream& operator << ( ostream& S, Natural s ) { return s.Tip(S); } istream& operator >> ( istream& S, Natural& s ) { return s.Cit(S); } void main () { Natural i, n=1001, k; cout << " Limita : "; cin >> k; for (i=101; i<n; i++) if (i<k) cout << i << endl; }

// cout // cin // << // >> clrscr(); getche();

86

23. Conversii utilizator


Conversiile sunt executate automat dac: a) operanzii nu sunt de acelai tip (char, enum int double, ..., iar la atribuire se face conversia valoarii expresiei n tipul variabilei); b) parametrul actual nu are tipul parametrului formal (se face conversia primului); c) tipul valorii returnate de o funcie difer de tipul acesteia (se face conversia valorii).

23.1. Conversii implicite


23.1.1. Conversia dintr-un tip predefint ntr-un tip abstract
Conversiile dintre un tip predefinit i un tip abstract se pot realiza printr-un constructor care s conin un parametru avnd acel tip predefinit, iar ceilali vor fi iniializai. Exemplu: // Numere raionale: Q
#include <string.h>; #include <iostream.h>; long Cmmdc(long, long); #include <conio.h>;

class Q { long m, n; // m / n public: Q (long, long); // constructor implicit Q& operator ~(); // operator de simplificare friend Q operator *(Q, Q); // functie prieten void Tip(const char* Mes=""); // tiparire (mesaj) }; inline Q::Q(long p=0, long q=1 ) { m=p; n=q; } Q& Q::operator ~() { long d=Cmmdc(m,n); m/=d; n/=d; return *this; } Q operator *(Q r, Q s) {return ~Q(r.m*s.m, r.n*s.n); } // friend inline void Q::Tip (const char* Mes) { if (n) cout << Mes << m << "/" << n << endl; else cerr << " Numitor nul " ;}; long Cmmdc(long a, long b) { if (b) return Cmmdc(b,a%b); else return a; }; void main () { clrscr(); Q x(3,2); x.Tip(" x : "); Q y(2,9); y.Tip(" y : "); Q z(2); z.Tip(" z : "); z=x*y; z.Tip(" x*y = "); Q w(2,1); w.Tip(" w : "); z=x*w; z.Tip(" x*w = "); z=x*2; z.Tip(" x*2 = "); z=2*x; z.Tip(" 2*x = "); getch(); }

// R e z u l t a t e :
x y z x*y w x*w x*2 2*x : : : = : = = = 3/2 2/9 2/1 1/3 2/1 3/1 3/1 3/1

87

O alt variant n care se evit utilizarea unei funcii prietene este de a defini o funcie membru (Produs) care se va apela de ctre funcia de suprancrcare a operatorului de nmulire. Exemplu: // Numere raionale: Q
#include <string.h>; long Cmmdc(long, long); #include <iostream.h>; #include <conio.h>;

class Q { long m; long n; public: Q (long, long);


Q& operator ~();

Q void };

Produs (Q);

Tip(const char* Mes="");

// m / n // constr. implicit // operator de simplificare // Produs // tiparire (mesaj)

inline Q::Q(long p=0, long q=1 ) { m=p; n=q; } Q& Q::operator ~() { long d=Cmmdc(m,n); m/=d; n/=d; return *this; }

inline Q Q::Produs (Q r) { return ~Q(m*r.m, n*r.n); } Q operator *(Q p, Q q) { return p.Produs(q); } // operator de inmultire
inline void Q::Tip (const char* Mes) { if (n) cout << Mes << m << "/" << n << endl; else cerr << " Numitor nul " ;}; long Cmmdc(long a, long b) { if (b) return Cmmdc(b,a%b); else return a; };

void main () { Q x(3,2); Q y(2,9); Q z(4,2); Q w; w=x*y; w=x*z; w=x*2; w=2*x; }

clrscr();

x.Tip(" y.Tip(" z.Tip(" w.Tip(" w.Tip(" w.Tip(" w.Tip("

x : "); y : "); z : "); x*y= x*z= x*2= 2*x= "); "); "); ");

getch();

// R e z u l t a t e :
x : y : z : x*y= x*z= x*2= 2*x= 3/2 2/9 4/2 1/3 3/1 3/1 3/1

23.1.2. Conversia dintr-un tip abstract ntr-un alt tip abstract


O alt problem pe care o vom aborda n cele ce urmeaz este de a realiza o conversie dintr-un tip abstract n altul. Pentru aceasta vom defini un constructor pentru realizarea conversiei dorite. n programul urmtor am definit tipul complex n cele dou forme: a) algebric - clasa C, b) trigonometric (polar) - clasa T. Conversia realizat face trecerea din forma b) n forma a). Pentru a putea verifica rezultatele, se utilizeaz i tipul complex predefinit.

88

Exemplu: // Numere complexe: TC


#include <iostream.h> #include <conio.h> #include <math.h>

#include <complex.h>
// class C; class T { public: // float float void class C { public: float Ro, Fi; // forma polara T (float Modul=0, float Arg=0); T (C w); // Conversie C->T Re (); Im (); Tip (const char* Mesaj); }; float Re, Im; // forma algebrica C (float a=0, float b=0);

float float float void

C (T z); // Conversie prin constructor C<-T float Modul (); float Arg (); void Tip (const char* Mesaj); }; C::C ( float a, float b ) { Re=a; Im=b; } C::C (T z) { Re=z.Re(); Im=z.Im(); } // Conversie prin constructor C<-T C::Modul( ) { return sqrt(Re*Re+Im*Im); } C::Arg ( ) { return atan2 (Im,Re); } C::Arg ( ) { return atan2 (Im,Re); } C::Tip ( const char* Mesaj) { cout << Mesaj << Re << "+" << Im << "i" << endl; } T::T ( float Modul, float Arg) { Ro=Modul; Fi=Arg; } T::T (C w) { Ro=w.Modul(); Fi=w.Arg(); } // Conversie C->T T::Re ( ) { return Ro*cos(Fi); } T::Im ( ) { return Ro*sin(Fi); } T::Tip(const char* Mesaj) { cout << Mesaj << Ro << "," << Fi << ";" << endl; }

// float float void

void main () { clrscr(); T y(2,3); y.Tip(" (r,u) = "); C x; x=y; x.Tip(" (a,b) = "); complex z(y.Re(),y.Im()); cout << " z = " << z << endl; cout << " (x,y) = " << real(z) << "+" << imag(z) << "i" << endl; cout << " (x,y) = " << sqrt(norm(z)) << "," << arg(z) << ";" << endl; getch(); }

// R e z u l t a t e :
(r,u)=2,3; (a,b)= -1.979985+0.28224i z =(-1.979985,0.28224) (x,y)= -1.979985+0.28224i (r,u)=2,3;

89

23.2. Conversii explicite


23.2.1. Conversia dintr-un tip abstract ntr-un tip predefinit
Conversia dintr-un tip abstract de dat ntr-un tip predefinit se poate realiza prin suprancrcarea operatorului de conversie explicit corespunztor, printr-o funcie membru definit astfel: class Clas { ... public: ... operator Tip_Predefinit ( ); ... }; Clas :: operator Tip_Predefinit ( ) { ... return Expresie_de_Tip_Predefinit; } n exemplul urmtor se va realiza o conversie dintr-un numr raional ntr-un numr real: // Conversie Tad-Q double
#include <string.h>; #include <iostream.h>; #include <conio.h>;

class Q { public:

void inline inline inline Q

long m; long n; Q (long, long); operator double(); Q operator *(Q); Tip (const char* Mes);

// m / n // constr. implicit // Q double // inmultire // tiparire

}; Q::Q(long p, long q) { m=p; n=q; } Q::operator double () { return double(m) / n; } Q::operator * (Q r) { return Q(m*r.m, n*r.n); }

inline void Q::Tip(const char* Mes) {cout << Mes << m << "/" << n << endl;} void main () { Q x(2,5); Q y(3,7); Q z=x*y; z.Tip(" z = "); double a, b; a=x*4.5; cout << " a = " << a << endl; b=4.5*x; cout << " b = " << b << endl; }
clrscr();

getch();

// R e z u l t a t e : z = 6/35 a = 1.8 b = 1.8

90

23.2.2. Conversia dintr-un tip abstract ntr-un alt tip abstract (prin operatori)
Acest tip de conversie se poate realiza i prin oparatori (dar nu simultan i prin constructori). n programul urmtor este realizat conversia (prin operatorul de conversie) din trigonometric (clasa T) n forma algebric (clasa C): // Numere complexe: TC
#include <iostream.h> #include <conio.h> #include <math.h>

#include <complex.h>
class C { public: float float void C::C ( float C::Modul( float C::Arg ( void C::Tip ( { class T { public: operator float float void float Re, Im; // forma algebric C (float a=0, float b=0); Modul (); Arg (); Tip (const char* Mesaj); }; float a, float b ) { Re=a; Im=b; } ) { return sqrt(Re*Re+Im*Im); } ) { return atan2 (Im,Re); } const char* Mesaj) cout << Mesaj << Re << "+" << Im << "i" << endl; } float T C Re Im Tip

Ro, Fi; // forma polar (float Modul=0, float Arg=0); (); // Operatorul de conversie (); (); (const char* Mesaj); }; T::T ( float Modul, float Arg) { Ro=Modul; Fi=Arg; } T::operator C() { return C(Re(),Im()); } // Op. Conv.

float T::Re ( ) { return Ro*cos(Fi); } float T::Im ( ) { return Ro*sin(Fi); } void T::Tip (const char* Mesaj) { cout << Mesaj << Ro << "," << Fi << ";" << endl; } void main () { clrscr(); T y(2,3); y.Tip("(r,u)="); C x; x=y; x.Tip("(a,b)="); complex z(y.Re(),y.Im()); cout << " z =" << z << endl; cout << "(x,y)=" << real(z) << "+" << imag(z) << "i" << endl; cout << "(r,u)=" << sqrt(norm(z)) << "," << arg(z) << ";" << endl; getch(); }

// R e z u l t a t e :
(r,u)=2,3; (a,b)= -1.979985+0.28224i z =(-1.979985,0.28224) (x,y)= -1.979985+0.28224i (r,u)=2,3;

91

24. Clase ablon ( Template )


Clasele Template (parametrizate sau generice) permit descrierea unor categorii de clase, care difer prin tipul unor atribute, acesta fiind descris generic (nu este precizat la descrierea clasei ci doar la instanierea obiectelor). O astfel de clas abstract va fi particularizat ntr-o clas concret nlocuind tipul general cu un anumit tip ales.

24.1. Funcii ablon ( Template )


Funciile Template (generice) conin i parametri formali generici care vor fi nlocuii cu parametri de un anumit tip concret. Exemplu:
#include <iostream.h> #include <conio.h>

//

Funcii

T e m p l a t e (1) \\

template <class T> T Max (T x, T y) { return (x>y)? x : y; } clrscr(); void main () { int a,b; cout << " Dati a,b : "; cin >> a >> b; cout << " Maximul = " << Max(a,b) << endl; float x,y; cout << " Dati x,y : "; cin >> x >> y; cout << " Maximul = " << Max(x,y) << endl; getche(); }
//N&d-Eusorsgreeti!

Se observ c putem folosi ca parametri actuali parametri de diverse tipuri, pentru care ns este definit operatorul > . Dac acest operator nu este definit pentru un tip de dat cu care dorim s lucrm, sau nu corespunde cerinelor noastre, acesta va trebui redefinit sau chiar funcia va fi rescris conform cerinelor. Exemplu:
#include <iostream.h> #include <conio.h>

//

Funcii

T e m p l a t e (2) \\

#include <string.h>

template <class T> T Max (T x, T y) { return (x>y)? x : y; }

char* Max(char* x, char* y) { return (strcmp(x,y)>0) ? x : y; } void main () { char* a=new char[10]; char* b=new char[10]; cout << " Dati a,b : "; cin >> a >> b; cout << " Maximul = " << Max(a,b) << endl; }

clrscr(); getche();

92

24.2. Clase Template


O clas Template este un model (ablon) din care se vor genera diverse clase concrete prin particularizarea atributelor cu tip ambiguu ( generic). O astfel de categorie de clase care difer prin tipurile atributelor sunt specificate printr-o clas template pentru ca apoi s fie generate diverse clase specifice corespunztoare anumitor tipuri necesare aplicaiei. Exemplu:
#include <iostream.h> #include <conio.h>

//

Clase T e m p l a t e \\

template <class T> class Vect { T* X; int Dim; public: Vect (int n) { X = new T [Dim=n]; } ~Vect ( ) { delete [ ] X; } void CitV ( ); T MaxV ( ); }; template <class T> void Vect<T>::CitV () { for (int i=0; i<Dim; i++) cin >> X[i]; } template <class T> T Vect<T>::MaxV () { T max=X[0]; for (int i=1; i<Dim; i++) if (X[i]>max) max=X[i]; return max; } void main () { int m; cout << " Dati nr.el. X : "; cin >> m; Vect<int> X(m); cout << " Dati elem. X : "; X.CitV(); cout << " Maximul este " << X.MaxV() << endl; int n; cout << " Dati nr.el. Y : "; cin >> n; Vect<float> Y(n); cout << " Dati elem. Y : "; Y.CitV(); cout << " Maximul este " << Y.MaxV() << endl; }

clrscr();

getche();

Se observ c n exemplul anterior s-au utilizat nu numai clase template ci i funcii membru template. Argumentele pot fi tipuri de date (class Nume_Parametru), de exemplu:
template <class T, int Dim>
Nume_Tip)

sau constante (Tip

93

24.3. Implementarea elementelor Template


n cele ce urmeaz ne vom referi la poziia codului (care se expandeaz conform cerinelor utilizatorului) corespunztor obiectelor template. Codul template (corpul funciilor membru) trebuie s fie vizibil acolo unde sunt utilizate elemente template. Exist dou metode (posibiliti) de implementare: a) template smart tot codul unei clase template este scris n fiierul header (definiii de clase, funcii precum i implementarea funciilor), acest mod putnd fi precizat fie prin opiunea de compilare Jg, fie prin meniul Options , Compiler , C ++ options , opiunea Template Generation : Smart , programul urmnd s includ acest fiier cu toate descrierile. b) template manual doar declaraiile elementelor template sunt scrise n fiierul header iar implemetarea fcndu-se separat, n alt fiier. Acest mod trebuie precizat prin directiva #pragma option, utiliznd opiunea de compilare Jgd (urmeaz o definire public a instanierilor unor elemente template) i opiunea Jgx (urmeaz o declaraie extern a instanierilor template). Acest mod este ilustrat n urmtorul exemplu simplu:
#include <conio.h> // Program Template ... Manual \\ #include <iostream.h>

# include "C_Templ4.h" # pragma option -Jgx

void main ()
{ Vint10 X; X.CitV("X"); cout << " Maximul este " << X.MaxV( ) << endl; Vflo13 Y; Y.CitV("Y"); cout << " Maximul este " << Y.MaxV( ) << endl; }
#include <conio.h> // Cpp Template ... Manual \\ #include <iostream.h>

clrscr(); getche();

#include "C_Templ4.h" template <class T, int Dim> void Vect<T,Dim>::CitV (char *Mes) { cout << " Dati nr. elem.: "; cin >> n; cout << " Dati elem." << Mes << " : "; for (int i=0; i<n; i++) cin >> X[i]; } template <class T, int Dim> T Vect<T,Dim>::MaxV () { T max=X[0]; for (int i=1; i<n; i++) if (X[i]>max) max=X[i]; } template <class T, int Dim>
class Vect { T int public: void T

return max;

// Header Template ... Manual \\ X[Dim]; n; CitV (char*); MaxV ( ); };

# pragma option Jgd typedef Vect<int, 10> Vint10; typedef Vect<float,10> Vflo13;

94

25. Relaii ntre clase


La elaborarea modelului obiectual al unei aplicaii se disting urmtoarele dou etape:
a) identificarea claselor corespunztoare conceptelor aplicaiei (substantivele), b) stabilirea relaiilor dintre clase corespunztoare specificaiilor aplicaiei (verbele).

n cele ce urmeaz ne vom referi la urmtoarele tipuri de relaii ntre clase: 1) Asociaie relaie de cooperare ntre clase corespunztoare unui verb oarecare din specificaie, diferit de relaia parte-ntreg (de exemplu relaia Student Facultate). Relaia corespunztoare dintre obiecte aparinnd unor clase asociate se numete legtur. O asociaie poate fi simpl sau multipl (dac un obiect asociant este pus n legtur, de exemplu prin pointeri, cu mai multe obiecte asociate, de acelai tip). Aceast relaie se reprezint grafic (dup metodologia OMT) n plan orizontal astfel:
C1 simpl C2 C1 multipl k C2

2) Agregare relaie de asociaie prin care obiectul agregat este inclus n obiectul agregant (verbul caracteristic este a avea), i evident c poate fi simpl sau multipl:
C1 simpl C2 C1 multipl k C2

3) Specializare (generalizare, motenire) relaie prin care sunt pstrate ( motenite) caracteristicile unei clase (de baz) i sunt adugate diferenele specifice, formnd o nou clas (derivat). Motenirea permite reutilizarea de cod definit n clasa de baz (superclas) i n noua clas (sublas). Deci, o subclas este o specializare a unei superclase (verbul caracteristic fiind a fi), iar o superclas este o generalizare a unei subclase. Aceast relaie este tranzitiv, iar structura format de mulimea claselor aflate n aceast relaie (construit pe vertical) se numete ierarhie de clase. Att specializarea ct i motenirea poate fi simpl sau multipl, reprezentarea fcndu-se n plan vertical astfel:
C1 C1 C1 C2

C2 Specializare simpl

C2

C3

C3 Motenire multipl

Specializare multipl

Se pot obine n felul acesta i ierarhii spaiale de clase, avnd relaii att pe orizontal ct i pe vertical.

25.1. Relaia de Asociaie


95

Prin aceast relaie dintre clase se modeleaz o legtur ntre obiectele instaniate (care depind unul de cellalt). Traversarea unei asociaii se face printr-un rol (nume dat extremitatii unei asociaii). Implementarea unei asociaii se poate realiza astfel: a) printr-un pointer clasa asociant conine un atribut de tip pointer spre clasa asociat, b) printr-o clas cu atribute i comportare proprie, fiecare legtur fiind o instan a acestei clase.

instaniere

C1 C1 rol1

asociaie rol2

C2 C2
instaniere

O1

legtur

O2

Asociaiile pot fi unidirecionale sau bidirecionale, iar relaiile de asociaie pot fi binare, ternare sau n-are. Pe de alt parte, asociaiile pot fi simple sau multiplicative (acestea din urm putnd fi eventual i cu restricii de ordonare sau de calificare). Asociaiile multiplicative sunt caracterizate prin numrul de instane ale claselor care se afl n asociaie, iar pentru a reprezenta direcia de asociaie se pot utiliza sgei. O asociaie multiplicativ poate s fie neordonat (instanele formeaz o mulime), sau poate s fie ordonat (instanele formeaz o list ordonat). O relaie multiplicativ cu restricie de calificare pune n relaie dou clase printr-un calificant (atribut care reduce multiplicitatea asociaiei printr-un criteriu pe care trebuie s-l ndeplineasc obiectele asociate pentru a intra n relaie).
C1 asociaia
{ordonata}

C2

C1

asociaia
calificant

C2

La implementarea relaiilor de asociaie putem aplica cele dou metode amintite anterior: a) prin pointeri spre clasa asociat ncuibrii n clasa asociant n funcie de tipul relaiei de asociere astfel: pentru relaia de asociaie simpl se adaug clasei asociante nc un atribut de tip pointer spre clasa asociat, mpreun cu relaxarea ncapsulrii pentru traversarea asociaiei alegnd o metod convenabil dintre urmtoarele variante: modificarea proteciei datelor membru implicate n public, utilizarea de metode sau clase friend, extinderea interfeei prin metode de acces la componente. pentru relaia de asociaie multipl se adaug clasei asociante mai multe atribute de tip pointer n funcie de tipul asociaiei i ordinul de multiplicitate astfel: dac este relativ mic, se vor aduga pointeri distinci, iar n caz contrar se poate utiliza un ir de pointeri; dac relaia este supus unor restricii de ordonare, se pot utiliza liste ordonate. b) prin clase distincte care realizeaz abstractizarea asociaiilor dac legturile au m n
C1 C2 Cas.

96

proprieti i operaii proprii (nemaifiind necesar adugarea de atribute claselor care se asociaz), aceast metod utilizndu-se n special n cazul asociaiilor bidirecionale de tip m-n), sau o legtur poate conecta obiecte de clase diferite. Exemplu:
//
#include <conio.h> #include <iostream.h>

Clase asociate \\

#include "VectCaut.h" void main (void) { int n; cout << " Dati n : "; cin >> n; VectSort X(n); // X.Sort (); VectCaut x(&X); X.Print(); int a,p; do { cout << " Dati a : "; cin >> a; if (p=x.CautSec(a)) cout << " Pe poz." << p << endl; else if(a) cout << " Inexistent! " << endl; } while (a); cout << " Dati m : "; cin >> n; VectSort* Y=new VectSort(n); Y->Sort(); VectCaut* y=new VectCaut(Y); Y->Print(); do { cout << " Dati b : "; cin >> a; if (p=y->CautBin(a)) cout << " Pe poz." << p << endl; else if(a) cout << " Inexistent! " << endl; } while (a); } // Clas #include "VectSort.h" class VectCaut { VectSort *v; public: VectCaut (VectSort*); int CautSec (int a); int CautBin (int a); }; //

clrscr();

getche();

asociant \\

<< VectCaut.h >>

Clas asociat \\

<< VectSort.h >>

class VectSort { int *v, n; public: VectSort (int = 10); void Sort ( ); void Print( ); int* Adr ( ); int Dim ( ); ~ VectSort ( ); };

97

// # include "VectCaut.h"

Clas asociant \\

<< VectCaut.Cpp >>

VectCaut::VectCaut (VectSort *p) { v = p; } int VectCaut::CautSec(int a) { int i=1, n=v->Dim(), *x=v->Adr(); while ((i<=n) && (x[i]-a)) i++; return i%(n+1); } int VectCaut::CautBin(int a) { int St=1, Dr=v->Dim(), *x=v->Adr(); while (St<=Dr) { int m=(St+Dr)/2; if (x[m]-a) if (x[m]<a) St=m+1; else Dr=m-1; else return m; } return 0; } // # include <iostream.h> # include "VectSort.h" VectSort::VectSort (int k) { n = k; v = new int[k+1]; for (int i=1; i<=n; i++) cin >> v[i]; } void VectSort::Sort( ) { int k=1; enum {Nu,Da} Sortat; do { Sortat=Da; for (int i=1; i<=n-k; i++) if (v[i]>v[i+1]) { int Temp=v[i]; v[i]=v[i+1]; v[i+1]=Temp; Sortat=Nu; } k++; } while (!Sortat); } void VectSort::Print ( ) { for (int i=1; i<=n; i++) cout << v[i] << ','; cout << endl; } int* VectSort::Adr ( ) { return v; } int VectSort::Dim ( ) { return n; } VectSort::~VectSort ( ) { delete []v; }

Clas asociat \\

<< VectSort.Cpp >>

98

25.2. Relaia de Agregare


Relaia de agregare este cea mai puternic relaie de asociaie, n care o clas este o component a altei clase, deci relaia este binar, unidirecional, iar relaiile multiplicative sunt de tip 1-n. Prin aceast relaie dintre clase, un obiect al clasei agregate este parte constituent, atribut, al clasei agregante, deci verbul caracteristic este a avea (conine). Obiectele constituente pot fi independente sau doar componente ale obiectului care le include.

instaniere

C1 C1

Conine

C2 C2
instaniere

O1

conine

O2

Aceast relaie (notat cu simbolul avnd semnificaia conine) are urmtoarele dou proprieti de baz: a) tanzitivitate : Dac Cx Cy i Cy Cz, atunci Cx Cz ,
b) antisimetrie : Dac Cx Cy atunci Cy / Cx .

Relaia de agregare poate fi: a) fix numrul i tipul componentelor sunt fixe, b) variabil permite un numr variabil de obiecte de acelai tip, c) recursiv accept acelai tip ca tip agregat i agregant . Exemplu:
// Relaia de agregare \\ #include <conio.h> #include <iostream.h> #include "Vect_Agr.h" void main (void) { int n; cout << " Dati n : "; cin >> n; VectCaut X(n); X.Print(); int a,p; do { cout << " Dati a : "; cin >> a; if (p=X.CautSec(a)) cout << " Pe poz." << p << endl; else if(a) cout << " Inexistent! " << endl; } while (a); cout << " Dati m : "; cin >> n; VectCaut* Y=new VectCaut(n); Y->Sort(); Y->Print(); do { cout << " Dati b : "; cin >> a; if (p=Y->CautBin(a)) cout << " Pe poz." << p << endl; else if(a) cout << " Inexistent! " << endl; } while (a); }

clrscr();

getche();

99

// Clas #include "VectSort.h" class VectCaut { VectSort V; public: VectCaut (int=10); void Sort (); void Print(); int CautSec (int); int CautBin (int); }; // # include "Vect_Agr.h" VectCaut::VectCaut (int n) : V(n) { } void VectCaut::Sort () { V.Sort(); } void VectCaut::Print () { V.Print(); } int VectCaut::CautSec(int a) { int i=1, n=V.Dim(), *x=V.Adr(); while ((i<=n) && (x[i]-a)) i++; return i%(n+1); }

Agregant \\

<< Vect_Agr.h >>

Clas Agregant \\

<< Vect_Agr.Cpp >>

int VectCaut::CautBin(int a) { int St=1, Dr=V.Dim(), *x=V.Adr(); while (St<=Dr) { int m=(St+Dr)/2; if (x[m]-a) if (x[m]<a) St=m+1; else Dr=m-1; else return m; } return 0; } // class VectSort { int *v, n;
public: VectSort (int = 10); void Sort ( ); void Print( ); int* Adr ( ); int Dim ( ); ~ VectSort ( );

Clas Agregat \\
//

<< VectSort.h >> A fost descris la clase asociate. \\

}; // # include <iostream.h> # include "VectSort.h"


//

Clas Agregat \\

<< VectSort.Cpp >>

A fost deja descris la clase asociate.

\\

100

n urmtorul exemplu se va folosi o clas Iterator pentru list simplu nlnuit care utilizeaz clasa Elem pentru un nod al listei i clasa Lista:
// #include <conio.h> #include <iostream.h> # define Tel int class Elem { Tel Inf; Elem* Leg; public: Elem (Tel inf, Elem* leg=0) { Inf=inf; Leg=leg; } friend class Lista; friend class Iterator;

Iterator List \\

}; class Lista { Elem* Cap; public: Lista ( ) { Cap=0; } void Ad (Tel); friend class Iterator; }; void Lista::Ad (Tel elem) { if (Cap) { Elem* p=Cap; while (p->Leg) p=p->Leg; p->Leg=new Elem(elem,0);} else Cap=new Elem(elem,0); } class Iterator { Elem* p; public: Iterator(Lista& L) Tel operator () ( ) void operator ++ ( ) int operator ! ( ) };

{ { { {

p = L.Cap; return p->Inf; p = p->Leg; return p!=0;

} } // elementul curent } // avanseaza in lista } // exista element

void main (void) { Lista L; L.Ad (11); L.Ad (22); L.Ad (33); Iterator l(L); while (!l) { cout << l() <<" "; l++; } }

clrscr();

getche();

101

25.3. Clase ncuibate(imbricate)


Exist posibilitatea definirii unei clase (ncuibate) n interiorul altei clase (ca i atribut al cesteia). Aceast posibilitate exist de fapt i la structuri (struct) i uniuni (union). Declararea obiectelor din clasa ncuibat se poate realiza utiliznd operatorul de scop (::) aa cum se poate vedea n exemplul urmtor:
class Cerc { C l as e Im bri ca t e \\ // Cerc(x,y,r) float r; // class Punct { // Punct(x,y) float x,y; /* ... */ }; /* ... */ //

Raza Centrul

}; void main () { Cerc C; Cerc::Punct P; // ... }

Utilizarea obiectelor din clasa ncuibat se poate realiza utiliznd operatorul de apartenen (.) dup cum se vede n urmtorul exemplul:
//
#include <conio.h> #include <iostream.h>

C l as e In cu i b at e

\\ // Cerc(x,y,r)

class Cerc {

float class

r; Punct {

float public: Punct void Print }; Punct Centru; public: Cerc (Punct P, float void Print() }; void main () { Cerc::Punct O(1,2); Cerc C(O,3); }

// Punct(x,y) x,y; (float x0=0, float y0=0) { x=x0; y=y0; } () { cout <<' '<< x <<' '<< y <<' '; } raza) { Centru=P; r=raza; } { Centru.Print(); cout << r; }

O.Print(); C.Print();

clrscr(); cout << endl; cout << endl; getch();

102

Evident c din clasa ncuibat (Punct) nu avem acces la elementele clasei din care face parte (Cerc). Dac se dorete acest lucru, atunci se poate proceda ca i n urmtorul exemplu:
//
#include <conio.h> #include <iostream.h>

C l as e In cu i b at e

\\

// Cerc(x,y,r) float r; public: Cerc (float raza) { r=raza; } class Punct; friend Punct; class Punct { // Punct(x,y) float x,y; public: Punct (float x0, float y0) { x=x0; y=y0; } void Print (Cerc c){cout <<' '<<x<<' '<<y<<' '<<c.r;} }; }; // void Cerc::Punct::Print (Cerc c) { cout <<' '<<x<<' '<<y<<' '<<c.r; } void main () { Cerc c(3); Cerc::Punct O(1,2); } clrscr(); O.Print(c); getch();

class Cerc {

Se poate observa n exemplul dat c referirea atributului r al clasei Cerc nu este permis din interiorul clasei ncuibate (vezi funcia Print descris n ambele variante), motiv pentru care clasa Punct a fost declarat prieten. n urmtorul exemplu sunt imbricate clasele R R2 R3 :
#include <conio.h> #include <iostream.h>

//

C l as e In cu i b at e

\\

class R

double x; public: R (double x) { this->x=x; } class R2; friend R2; class R2 { double y; public: R2 (double y) { this->y=y; } class R3; friend R3; class R3 { double z; public: R3 (double z) { this->z=z; } void Print (R,R2); }; void Print (R); }; };

void R::R2::Print (R a) {cout <<' '<<a.x;} void R::R2::R3::Print (R a, R2 b) {b.Print(a); cout <<' '<<b.y<<' '<<z;} void main () { R OX (1); R::R2 XOY(2); R::R2::R3 XYZ(3); } clrscr(); XYZ.Print(OX,XOY);

getch();

103

25.4. Relaia de derivare


Prin aceast relaie putem modela similitudinile dintre clase dou sau mai multe clase. Pornind de la o clas de baz (general) se pot deriva noi clase (prin diferenele specifice). Obiectele clasei derivate motenesc atributele i metodele clasei de baz la care se vor aduga noile elemente caracteristice (vor fi umflate), ceea ce permite reutilizarea resurselor deja pregtite n clasele de baz (pentru obiectele similare). Verbul caracteristic al acestei relaii de specializare este a fi ( este un fel de <a kind of>). Motenirea permite pstrarea elementelor (date i funcii ale) unei clase de baz (superclas), cu definirea de noi elemente construind o nou clas derivat (subclas), formnd n felul acesta ierarhii de clase. Motenirea poate fi i multipl dac o clas motenete mai multe clase. Deoarece aceast relaie este tranzitiv se utilizeaz i termenii de strmo i descendent.

generalizare

este o

Cb

C1

C1

C1

C2

Cd
C2 Specializare simpl C2 C3 C3 Motenire multipl

25.4.1.

Specializare multipl

Clase derivate

Relaia de derivare se poate descrie prin construcii speciale fr a mai fi nevoie de o relaxare a ncapsulrii, aa cum a fost necesar la relaiile prezentate anterior. Dac ntr-o aplicaie se poate utiliza relaia de derivare, este de preferat n locul asociaiei sau agregrii pentru c avem instrumente specializate n limbajul de programare. O clas derivat se declar astfel: class Clas_Derivat : List_clase_de_baz { Date i Funcii membru noi };

este un

Ob

Od

specializare

104

Lista claselor de baz poate s conin i modificatorii de protecie (Mod_Pr) public, protected sau private, deci o derivare poate s fie public, protejat sau privat, accesul rezultat fiind redat n urmtoarele tabele.
Accesul n clasa de bazMod_PrAccesul n clasa derivatprivate*Privateprivateprotected sau publicProtectedprotectedPublicneschimbat (protected sau public)

d\b#+ +#+###

De exemplu, dac cele dou clase sunt descrise astfel:


class Cl_Baz { private: protected: public: }; public: a b c Cl_Derivat

by

cz

a protected: Cl_Derivat x

class Cl_Derivat : Mod_Pr Cl_Baz { private: a protected: b public: c };

bcy

atunci protecia membrilor din private: clasa derivat este redat n schema bcx y z alturat. Cl_Derivat Ordinea de executare a constructorilor la instanierea obiectelor dintr-o clas derivat: prima dat se execut constructorul clasei de baz, apoi constructorul clasei derivate (se construite cadrul, apoi se adaug diferenele specifice). Ordinea de executare a destructorilor la distrugerea obiectelor dintr-o clas derivat: prima dat se execut destructorul clasei derivate, apoi destructorul clasei de baz. Constructorul clasei derivate transmite parametrii necesari constructorului clasei de baz prin apelul direct al acestuia astfel: Clas_Derivat ( ) : Clas_de_baz ( ) { }; // inline sau Clas_Derivat :: Clas_Derivat ( ) : Clas_de_baz ( ) { }; //inline

105

Deoarece relaia de derivare este poate cea mai important relaie dintre clase, sunt oferite faciliti de implementare, care permit urmtoarele faciliti: economia de cod reutilizarea codului scris o singur dat dup care se motenete, extensibilitate re-specializare prin derivarea de noi ramuri dintr-o ierarhie, polimorfism ntr-o ierarhie de clase se poate implementa o comportare polimorfic, ncapsularerelaxare relaia de derivare ofer posibilitatea nchiderii resurselor simultan cu deschiderea spre modificare i extensie. Relaiile de derivare (de fapt i celelalte relaii dintre clase) sunt stabilite la compilare, deci nu se mai pot modifica pe parcursul execuiei. Mai trebuie cunoscut faptul c prin derivare nu se pot moteni constructorii, destructorii, elementele prietene (funcii, clase sau metode friend) i nici operatorii redefinii. Exemplu:
//
#include <conio.h> #include <string.h> #include <iostream.h>

Relatia de derivare \\

class N { protected: char* c; public: N (char* s) { c=new char[strlen(s)+1]; strcpy(c,s); } ~N ( ) { delete [ ] c; } char* Modul ( ) { return c; } }; void Print (N n) { cout << n.Modul() << endl; } class Z : public N { private: public: char };

char Semn; Z (char* s) : ~Z ( ) Semnul( )

N(s+1)

{ Semn=s[0]; } { } { return Semn; }

void Print (Z n) { cout << n.Semnul() << n.Modul() << endl; } void main (void) { N n("1234"); Print (n); Z k("-123"); Print (k); N* i = new N("567"); Print (*i); Z* j = new Z("-89"); Print (*j); } clrscr();

getche();

106

Conversia unui obiect dintr-o clas derivat ntr-un obiect aparinnd clasei de baz este permis, invers ns nu (sursa trebuie s acopere destinaia): Contra_Exemplu: // Conversii la derivare ? \\
void main (void) { clrscr();

N Z N* Z*

n("1234"); Print (n); k(n); Print (k); i = new N(k); Print (*i); j = new Z(i); Print (*j);

Error CONVCDCB.CPP 28: Could not find a match for 'Z::Z(N)' Error CONVCDCB.CPP 30: Could not find a match for 'Z::Z(N *)'
getche();

Pentru o funcie care are ca parametru formal un obiect al clasei de baz este permis apelul avnd ca parametru un obiect al clasei derivate, invers nu (o funcie care are ca parametru formal un obiect al clasei derivate, nu poate fi apelat avnd ca parametru actual un obiect al clasei de baz). Exemplu: // Conversie la derivare \\
#include <conio.h> #include <string.h> #include <iostream.h>

class N { protected: public: N N N ~N char* Modul }; class Z : public N { private: public: char }; void Print char* ( (char* (N& ( ( c; ) s) n) ) ) { { { { { c=new char[2]; c[0]='0'; c[1]=0; } c=new char[strlen(s)+1]; strcpy(c,s); } c=new char[strlen(n.c)+1]; strcpy(c,n.c); } delete [ ] c; } return c; }

void Print (N n) { cout << n.Modul() << endl; }

char Z( Z (char* ~Z ( Semnul(

Semn; ) : N( ) s) : N(s+1) ) )

{ Semn='+' ; { Semn=s[0]; { { return Semn;

} } } }

(Z n) { cout << n.Semnul() << n.Modul() << endl; }

void WriteAbs (N n) { Print( n); } void WriteAbs_(N*n) { Print(*n); } void main (void) { Z k("+123"); N n(k); WriteAbs(n); WriteAbs(k); Z* p=new Z("-456"); N* q; q = p; WriteAbs(*p); WriteAbs(*q); } clrscr(); Print (k); Print (n); Print (*p); Print (*q); WriteAbs_(p); WriteAbs_(q);

getche();

n exemplul urmtor se pornete de la clasa de baz VectBaza i se construiete clasa derivat Vect_Der :

107

#include <conio.h> #include <iostream.h>

//

Relaia de derivare \\
clrscr();

#include "Vect_Der.h" void main (void) { int n; cout << " Dati n : "; cin >> n; Vect_Der X(n); X.Print(); int a,p; do { cout << " Dati a : "; cin >> a; if (p=X.CautSec(a)) cout << " Pe poz." << p << endl; else if(a) cout << " Inexistent! " << endl; } while (a); cout << " Dati m : "; cin >> n; Vect_Der* Y=new Vect_Der(n); Y->Sort(); Y->Print(); do { cout << " Dati b : "; cin >> a; if (p=Y->CautBin(a)) cout << " Pe poz." << p << endl; else if(a) cout << " Inexistent! " << endl; } while (a); }

getche();

// Clas class VectBaza { protected: int *v, n; public: VectBaza (int = 10); void Sort ( ); void Print( ); ~ VectBaza ( ); };

de baz \\

<< VectBaza.h >>

// Clas de baz \\ << VectBaza.Cpp >> # include <iostream.h> # include "VectBaza.h" VectBaza::VectBaza (int k) { n = k; v = new int[k+1]; for (int i=1; i<=n; i++) cin >> v[i]; } void VectBaza::Sort( ) { int k=1; enum {Nu,Da} Sortat; do { Sortat=Da; for (int i=1; i<=n-k; i++) if (v[i]>v[i+1]) { int Temp=v[i]; v[i]=v[i+1]; v[i+1]=Temp; Sortat=Nu; } k++; } while (!Sortat); } void VectBaza::Print ( ) { for (int i=1; i<=n; i++) cout << v[i] << ','; cout << endl; } VectBaza::~VectBaza ( ) { delete []v; }

108

// Clas #include "VectBaza.h" class Vect_Der : public VectBaza { public: Vect_Der (int=10); int CautSec (int); int CautBin (int); }; //

Derivat \\

<< Vect_Der.h >>

Clas

Derivat \\

<< Vect_Der.Cpp >>

# include "Vect_Der.h" Vect_Der::Vect_Der (int n) : VectBaza(n) { } int Vect_Der::CautSec(int a) { int i=1; while ((i<=n) && (v[i]-a)) i++; return i%(n+1); } int Vect_Der::CautBin(int a) { int St=1, Dr=n; while (St<=Dr) { int m=(St+Dr)/2; if (v[m]-a) if (v[m]<a) St=m+1; else Dr=m-1; else return m; } return 0; }

n exemplul care urmeaz, datele x,y (din clasa de baz Punct) au fost declarate protected deoarece clasa derivat (Cerc) le refer. La clasa derivat am utilizat modificatorul public pentru a putea utiliza i pentru Cerc operaia Contine (PC).
// Program Fct_NeVirtuala; \\

#include <stdio.h>; #include <conio.h>; #include <iostream.h>; #include <math.h>; float Sqr (float x) { return x*x; }

class

Punct (float x0=0, float y0=0); float Dist (Punct P); int Contine(Punct P); }; Punct::Punct (float x0, float y0) { x=x0; y=y0; } float Punct:: Dist (Punct P) {return sqrt(Sqr(x-P.x)+Sqr(y-P.y)); } int Punct:: Contine (Punct P) {return Dist (P)==0; } class Cerc : public Punct { float r; public: Cerc (float x0=0, float y0=0, float raza=0) {x=x0; y=y0; r=raza;} float Dist (Punct P) {Punct C(x,y); return C.Dist(P)-r; } }; void main (void) { Punct P(3,4); Cerc C(0,0,5); if (C.Contine (P)) cout << " Cercul C contine punctul P." << endl; else cout << " Cercul C nu contine punctul P." << endl;

Punct { protected : float public:

x,y;

// R e z u l t a t e : Cercul C nu contine punctul P.

getch();

Se observ n exemplul de mai sus c rezultatul nu este cel dorit. Acest neajuns l vom rezolva mai trziu declarnd Distana ca funcie virtual (pentru legare dinamic).

109

Fa de motenirea simpl, n care dintro singur clas de baz se deriveaz una sau mai multe clase derivate (specializate), motenirea multipl presupune existena mai multor clase de baz din care un sau mai multe clase motenesc diverse caracteristici.

Cb

Cb1

Cb2

Cd1

Cd2

Cd
Motenire multipl

Motenire simpl

Declararea unei clase derivate din mai multe clase de baz se face astfel: class Clas_de_baz_1 { }; class Clas_de_baz_2 { }; class Clas__derivat : Mod_Pr Clas_de_baz_1, Mod_Pr Clas_de_baz_2 { }; unde Mod_Pr { public, protected, private }. Datorit motenirii multiple o clas de baz poate fi prezent n mai multe exemplare ntr-o clas derivat, aa cum se poate vedea n exemplul alturat, unde datele membru ale clasei Animal vor fi motenite n dou exemplare de ctre clasa Cine (unul prin clasa Domestic, altul prin clasa Mamifer) i pot fi referite prin operatorul de rezoluie ( :: ) aplicat clasei prin care se face motenirea (Nume). Aceast motenire repetitiv a unei clase de baz este corect i se poate utiliza astfel:

Anim al

Mam ife r

Do m e stic

Cine

Cl_Baz

Cl_Baz

Cl_Der1

Cl_De r2

Cla s _De riv a t

class Cl_Baz { protected: Atribut }; class Cl_Der1 : public Cl_Baz { }; class Cl_Der2 : public Cl_Baz { }; class Clas_Derivat : public Cl_Der1, Cl_Der2 { Cl_Der1::Atribut Cl_Der2::Atribut };

110

Dac dorim realizarea unei singure copii a atributelor motenite, vom folosi motenirea multipl virtual:
Cl_Baz

Cl_Der1

Cl_De r2

Cla s _De riv a t

class class class class

Cl_Baz { protected: Atribut }; Cl_Der1 : virtual public Cl_Baz { }; Cl_Der2 : virtual public Cl_Baz { }; Clas_Derivat : public Cl_Der1, Cl_Der2 { Atribut };

111

Aa cum se poate vedea n exemplul urmtor, vom avea un nume de mamifer i un nume domestic. //
#include <iostream.h> #include <conio.h> #include <string.h>

Program Clase NeVirtuale;

\\

class Animal { protected: char* Nume; public: Animal (char *nume) { strcpy(Nume,nume); } }; class Mamifer : public Animal { protected: int Greu; public: Mamifer (char* nume,int gr) : Animal(nume) { Greu=gr;} }; class Domestic: public Animal { protected: int Pret; public: Domestic(char* nume,int pr) : Animal(nume) { Pret=pr;} }; class Caine : public Mamifer, public Domestic { protected: int Lant; public: Caine(char* numeM,char* numeD, int gr, int pr, int l) : Mamifer(numeM,gr), Domestic(numeD,pr) { Lant=l;} void Tip() { cout << " Nume Mamifer : " << Mamifer::Nume << endl << " Nume Domestic: " << Domestic::Nume << endl << " Greutate : " << Greu << endl << " Pret : " << Pret << endl << " Lant : " << Lant << endl ;} }; void main (void) { Caine c ("Cane","Nero",13,1300,8); }

clrscr(); c.Tip(); getch(); // Rezultate:

Nume Mamifer : Nume Domestic: Greutate : Pret : Lant :

Cane Nero 13 1300 8

112

Dac dorim ca datele membru s fie prezente ntr-un singur exemplar n clasele derivate, atunci vom utiliza clase virtuale. O clas de baz devine virtual prin motenire dac se declar aceasta prin cuvntul virtual plasat naintea clasei (devenind astfel clas virtual fa de clasa derivat). Programul anterior modificat astfel nct numele s fie memorat ntr-un singur exemplar este urmtorul: //
#include <iostream.h> #include <conio.h> #include <string.h>

Program Clase Virtuale;

\\

class Animal { protected: char* Nume; public: Animal (char* nume) { strcpy(Nume,nume); } }; class Mamifer : virtual public Animal { // Animal este clas virtual pentru Mamifer protected: int Greu; public: Mamifer (char* nume,int gr) : Animal(nume) { Greu=gr;} }; class Domestic: virtual public Animal { // Animal este clas virtual pentru Domestic protected: int Pret; public: Domestic(char* nume,int pr) : Animal(nume) { Pret=pr;} }; class Caine : public Mamifer, public Domestic { protected: int Lant; public: Caine(char* nume, int gr, int pr, int l) : Animal(nume), Mamifer(nume,gr), Domestic(nume,pr) {Lant=l;} void Tip() { cout << " Nume Animal : " << Nume << endl << " Greutate : " << Greu << endl << " Pret : " << Pret << endl << " Lant : " << Lant << endl ;} }; void main (void) { clrscr(); Caine c ("Lup",13,1300,8); c.Tip();
getch();

// Rezultate:
Nume Animal Greutate Pret Lant : : : : Lup 13 1300 8

113

Pentru o ierarhie ca cea din figura alturat, n care avem clase virtuale () i nevirtuale (), se execut mai nti constructorii claselor de baz virtuale apoi cei ai claselor nevirtuale, iar constructorul clasei de baz se va executa pentru o singur dat toate exemplarele virtuale i cte o dat pentru fiecare exemplar nevirtual.

D G

Exemplul:
// Program Ierarhie Clase Virtuale/Nevirtuale; \\

#include <iostream.h> #include <conio.h>

class A { public: A (char* a) { cout << " A : " << a << endl; } class B: virtual public A { public: B (char* b) : A(b) { cout << " B : " << b << endl; } class C: virtual public A { public: C (char* c) : A(c) { cout << " C : " << c << endl; } class D: public A { public: D (char* d) : A(d) { cout << " D : " << d << endl; } class E { public: E (char* e) { cout << " E : " << e << endl; } class F { public: F (char* f) { cout << " F : " << f << endl; } class G: public B, public C, public D, public E, virtual public F { public: G (char* g) : A(g), B(g), C(g), D(g), E(g), F(g) { cout << " G : " << g << endl; } void main (void) { clrscr(); G Ob("Ob."); getch(); }

// Rezultate:
A F B C A D E G : : : : : : : : Ob. Ob. Ob. Ob. Ob. Ob. Ob. Ob.

114

26. Polimorfism
Suprancrcarea (overloading), prin redefinirea unor funcii sau metode, permite alegerea la compilare-link_editare a funciei sau a metodei dorite prin semntura acesteia, fr a mai putea alege la execuie. Polimorfismul permite ca la execuie s se decid ce metod s fie apelat, oferind o facilitate a metodelor din clase aflate n relaie de derivare. Prin polimorfism se execut aciuni diferite prin mesaje cu semnturi identice asupra obiectelor de tip diferit (obiecte din clase diferite rspund diferit la acelai mesaj). Dou obiecte sunt compatibile dac aparin aceleai clase (evident) dar i dou variabile
a) de tip pointer la clasa de baz, respectiv pointer la clasa derivat, b) de tip referin (pointer constant) la clasa de baz, respectiv referin la clasa derivat .

Metodele unei clase pot fi:

Clasice metode legate static, la compilare-link_editare fiind fixat adresa de apel a metodei, fr posibilitatea de a o schimba la rularea aplicaiei, Polimorifice metode legate dinamic, care permit ntrzierea deciziei referitoare la adresa de apel a metodei, pn la execuie.

Legarea unei metode (binding), nelegnd prin aceasta cenexiunea logic dintre o entitate i o proprietate a acesteia (corespondena dintre un mesaj trimis unui obiect, adic ordinul de apel, i metoda care se execut ca rspuns la acesta) poate fi:

Timpurie (static early-binding) compilatorul i editorul de legturi vor fixa adresa metodei care se execut, fr ca aceasta s mai poat fi modificat pe parcursul execuiei; Trzie (dinamic late-binding) compilatorul va construi un tablou de adrese ale metodelor posibile de apel, iar determinarea adresei metodei dorite se va efectua doar la execuie. n funcie valoarea pointerului spre clasa de baz, care poate conine i adresa unui obiect al clasei derivate, se va alege metoda corespunztoare.

115

26.1. Funcii membru Vi r t u al e


Implicit, o metod este legat static ( early, la compilare), iar dac se dorete o legare dinamic (late, la execuie) se va declara virtual prin scrierea cuvntului virtual naintea metodei. O metod virtual a unei clase de baz, poate fi motenit ntr-o clas derivat sau poate fi redefinit (nlocuit - overriding). O metod se declar vitual n clasa de baz (nu se poate declara virtual doar ntr-o clas derivat. Se poate observa n exemplul urmtor c dac dorim ca rezultatul s fie Baza/Derivata i la apelul funciei g, trebuie s declarm funcia f virtual, altfel rezultatul ar fi Baza/Baza.
# include <conio.h> # include <iostream.h>

//

Met od vi r t u al

\\

class Cb { public: virtual void f() { cout << " Baza }; class Cd : public Cb { public: }; void
{

" << endl; }

void f() { cout << " Derivata " << endl; }

g(Cb* p) { p->f(); }
clrscr();

void main () Cb* Pb = new Cb; Pb->f(); g(Pb); delete Pb;


}

Cd* Pd = new Cd; Pd->f(); g(Pd); delete Pd;

// Legare Statica // Legare Dinamica


getche();

n exemplul urmtor vom utiliza variabile de tip referin la clasa de baz, respectiv la clasa derivat.
# include <conio.h> # include <iostream.h>

//

Met od vi r t u al

\\

class Cb { public: virtual void f() { cout << " Baza }; class Cd : public Cb { public: }; void
{

" << endl; }

void f() { cout << " Derivata " << endl; }

g(Cb& r) { r.f(); }
clrscr();

void main () Cb Ob; Ob.f(); g(Ob);


}

Cd Od; Od.f(); g(Od);

// Legare Statica // Legare Dinamica

getche();

116

n urmtorul exemplu se poate deduce necesitatea legrii dinamice, pentru a putea calcula corect distana de la un punct la un cerc i respectiv la un segment (la o dreapt). Din pcate pentru c metoda Contine exist n dublu exemplar (Stanga i Dreapta) apelul nu se poate efectua cum ar fi de dorit!
#include <conio.h>; #include <iostream.h>; #include <math.h>;

//

Met od vi r t u al

\\

float class

Sqr (float x) { return x*x; } Punct { protected: float x,y; public: Punct (float x0, float y0) { x=x0; y=y0; } Punct (Punct &P) { x=P.x; y=P.y; } virtual float Dist (Punct P) {return sqrt(Sqr(x-P.x)+Sqr(y-P.y)); int Contine(Punct P) {return Dist(P)==0; }; }; Cerc : public Punct { float r; public: Cerc (float x0, float y0, float R):Punct(x0,y0){r=R;} float Dist (Punct P) {Punct C(x,y); return C.Dist(P)-r; } }; Stanga : public Punct { public:Stanga (float x0, Stanga (Punct& P) }; Dreapta: public Punct { public:Dreapta(float x0, Dreapta(Punct& P) }; float y0) : Punct(x0,y0) { } : Punct(P) { } float y0) : Punct(x0,y0) { } : Punct(P) { }

class

class

class

class

Segm : public Stanga, Dreapta { public: Segm(Punct St, Punct Dr) : Stanga(St), Dreapta(Dr) { } float Dist (Punct C) { Punct A(Stanga::x, Stanga::y); Punct B(Dreapta::x,Dreapta::y); float a=B.Dist(C); float b=A.Dist(C); float c=A.Dist(B); float p=(a+b+c)/2; float S=sqrt(p*(p-a)*(p-b)*(p-c)); return 2*S/c; } }; clrscr(); C contine punctul P." ; C nu contine punctul P." ; " Segm. AB contine punctul P." ; " Segm. AB nu contine punctul P." ; getche();

void main (void) { Punct P(3,4); Cerc C(0,0,5); if (C.Contine(P)) cout << " Cercul else cout << " Cercul Punct A(0,0), B(6,8); Segm AB(A,B); if (AB.Stanga::Contine(P)) cout << else cout << }

117

Aproape orice metod poate fi virtual, chiar i metodele inline, metodele friend (dar nu i funciile friend) operatorii (dac nu se redefinesc prin funcii friend) i destructorii, n schimb constructorii i metodele statice nu pot fi virtuale. n exemplul prezentat n continuare, al doilea produs ( 2/3 * 4/5 = 8/15) nu va fi afiat dac operatorul de nmulire a dou numere raionale nu este declarat virtual , (deoarece operatorul *= va apela operatorul de nmulire pentru Q n loc de F cum ar trebui, a i b fiind din clasa F). Se observ c la nmulirea a dou obiecte din clasa Q nu sunt tiprite fraciile care se nmulesc, pe cnd la nmulirea a dou obiecte din clasa F fraciile care se nmulesc sunt tiprite.
//
#include <conio.h>;

Program Operator Virtual;

\\
#include <iostream.h>;

class Q { protected: int p,q; public: Q (int m=0, int n=1) { p=m;q=n; } virtual Q operator * (Q& r) { return Q(p*r.p, q*r.q); } Q& operator *= (Q& r) { return *this=*this * r; } void Tip (char* Ms) { cout << Ms << p << "/" << q; } }; class F : public Q { public: F (int m=0, int n=1) : Q (m,n) { } Q operator * (Q& r) { Q f = Q(*this) * r; this->Tip(""); r.Tip(" * "); f.Tip(" = "); cout << endl; return f; } }; void main (void) { Q p(2,3), q(4,5), r; p.Tip(" p = "); cout r=p*=q; p.Tip(" p = "); cout F a(2,3), b(4,5); Q a.Tip(" a = "); cout d=a*b; d=a*=b; }

clrscr();

<< endl; << endl; d; << endl;

q.Tip(" q = "); cout << endl; r.Tip(" r = "); cout << endl; b.Tip(" b = "); cout << endl; d.Tip(" d = "); cout << endl; d.Tip(" d = "); cout << endl;
getch();

// R e z u l t a t e :
p = 2/3 q = 4/5 p = 8/15 r = 8/15 a = 2/3 b = 4/5 2/3 * 4/5 = 8/15 d = 8/15 2/3 * 4/5 = 8/15 d = 8/15

118

26.2. Clase abstracte - funcii membru virtuale p u r e


n clasa de baz se poate declara o comportare generic avnd un nume i o semntur unic (urmnd ca fiecare specializare s ofere propria metod specific) prin:
a) metode nule care se declar astfel:

virtual Tip_met Nume_met (List_Par_Formali) { }


b) metode pure declarate n forma:

virtual Tip_met Nume_met (List_Par_Formali) = 0; Ambele variante permit nlocuirea acestei metode cu o metod proprie clasei specializate derivat din clasa de baz, permind astfel solicitarea unui comportament general, dar propriu fiecrei specializri. Metodele pure nu pot fi apelate, rolul lor fiind doar de a declara tipul, numele i parametrii unei metode abstracte care urmeaz s fie redefinit concret n fiecare clas specializat. O clas este abstract dac ea conine cel puin o funcie membru virtual pur. O funcie membru virtual este pur dac ea este declarat (virtual antet = 0) dar nu este definit n clasa din care face parte ci ntr-o clas derivat. Deoarece clasele abstracte conin funcii membru nedefinite (virtuale pure), nu se pot crea obiecte aparinnd acestora (nu pot fi instaniate, dar se pot defini variabile de tip pointer sau referin la o clas abstract), iar dac funciile virtuale nu sunt definite nici n clasele derivate, atunci i aceste clase devin abstracte (o clas derivat dintr-o clas abstract rmne abstract dac nu s-au redefinit toate metodele pure motenite, iar n caz contrar devine clas concret). O clas abstract realizeaz implementarea unei noiuni care nu poate fi concretizat (i atunci nu poate fi dect enunat), dar surprinde o caracteristic comun a claselor specializate din aceasta (care vor conine implementrile efective). Deci, o clas abstract va generaliza (abstractiza) comportamentul subclaselor specializate. ntr-o ierarhie, clasa de baz poate avea nite proprieti care nu se pot defini dect n clasele derivate (anumite caracteristici depind de clasa derivat). n exemplul alturat, cu toate c se cunoate greutatea unui animal, nu se poate spune c este slab sau gras dect pentru o clas derivat).

Anim al

Porum b e l

Urs

Cal

119

n exemplul urmtor vom da trei caracterizri pentru un anumit animal n funcie de greutatea lui i cea medie (slab/gras), vrsta lui i cea medie (tnr/btrn), i viteza lui (de deplasare) i cea medie (lent/rapid), acestea pentru un Porumbel, Urs sau Cal. // Clas e A bs tr ac te - Me to de Pur e \\
#include <iostream.h> #include <conio.h>

class Animal { protected: double Greut, Varsta, Viteza; public: Animal (double Kg, double Ani, double Km_H) {Greut= Kg; Varsta=Ani, Viteza=Km_H;} virtual double Greut__Medie () = 0; virtual double Varsta_Medie () = 0; virtual double Viteza_Medie () = 0; int Slab () { return Greut < Greut__Medie(); } int Tanar() { return Varsta< Varsta_Medie()/2; } int Lent () { return Viteza< Viteza_Medie(); } void Tip () { cout << ( Slab ()? "slab, " : "gras, " ) << ( Tanar()? "tanar, " : "batran," ) << ( Lent ()? "lent \n" : "rapid\n" );} }; class Porumbel:public Animal { public: Porumbel (double Kg, double Ani, double Km_H) : Animal(Kg, Ani, Km_H) { } double Greut__Medie () { return 0.5; } double Varsta_Medie () { return 6.0; } double Viteza_Medie () { return 90.0; } }; class Urs: public Animal { public: Urs (double Kg, double Ani, double Km_H) : Animal(Kg, Ani, Km_H) { } double Greut__Medie () { return 450; } double Varsta_Medie () { return 43; } double Viteza_Medie () { return 40; } }; class Cal: public Animal { public: Cal (double Kg, double Ani, double Km_H) : Animal(Kg, Ani, Km_H) { } double Greut__Medie () { return 1000; } double Varsta_Medie () { return 36; } double Viteza_Medie () { return 60; } }; void main (void) { clrscr(); Porumbel p (0.6, 1, 80); p.Tip(); Urs u (500,40, 46); u.Tip(); Cal c (900, 8, 70); c.Tip(); getch(); }

// Rezultate:
gras, gras, slab, tanar, lent batran, rapid tanar, rapid

120

n exemplul urmtor vom apela o funcie Draw pentru a desena o figur oarecare (Punct, Ptrat sau Cerc) i o funcie Arie care va aplica formula caracteristic fiecrei figuri geometrice: // Clas A bs tr ac t - M et od e Pur e \ \
# # # # include include include include <Conio.h> <Process.h> <Iostream.h> <Graphics.h>

Figur

Punct

Ptrat

Cerc

class Figura { { }

protected: public: virtual virtual

int x,y; Figura (int u=0, int v=0) { x=u; y=v; } void Draw () = 0; // Pura sau Nula int int Arie () = 0; Pret () { return Arie()*100+1; }

class Punct

}; : public

Figura { int Cul; public:

Punct

(int u, int v, int { Cul=c;

c=WHITE):Figura(u,v) } void Draw() { putpixel(x,y,Cul); } int Arie() { return 0; } class Patrat Figura(u,v) { Lat=L; } void Draw() { moveto(x,y); linerel(0,+Lat); linerel(+Lat,0); linerel(0,-Lat); linerel(Lat,0); } int class Cerc }; : public Arie() { return Lat*Lat; } Figura { int Raza; public: Cerc (int u, int v, int R=1) : Figura(u,v) { Raza=R;} void Draw() { circle(x,y,Raza); } int Arie() { return 3*Raza*Raza; } }; : public Figura { int Lat; public:

Patrat (int u, int v, int L=1) :

}; void InitGraf(void) { int Gd = DETECT, Gm; initgraph(&Gd, &Gm, "C:\\BorlandC\\Bgi"); } void main (void) { clrscr(); Figura* Fig[22]; int i,n; cout << " Dati n : "; cin >> n; for (i=0; i<n; i++) { int t,x,y,z; cout << " Dati fig." << i+1 << "(t,x,y,z): "; cin >> t >> x >> y >> z; switch (t) { case 1: Fig[i]=new Punct (x,y,z); break; case 2: Fig[i]=new Patrat(x,y,z); break; case 3: Fig[i]=new Cerc (x,y,z); break;
default: exit(1);

}; cout << " Pret = " << Fig[i]->Pret() << endl; };

121

getche();

InitGraf();
getche(); closegraph();

for (i=0; i<n; i++) { setcolor(15-i); Fig[i]->Draw();} }

122

27. Ierarhii pentru Intrri/Ieiri


Pentru c nu exist instruciuni de intrare/ieire, s-au definit funcii (n C), respectiv dou ierarhii de clase (n C++). Aceste dou ierarhii (reprezentate n figurile de mai jos i declarate n fiierul iostream.h) realizeaz operaiile de intrare/ieire prin stream-uri (flux de date sursdestinaie).
s t re m b uf

file b uf

strstreambuf

Clasa streambuf se folosete pentru gestionarea zonelor tampon i operaii de intrare/ieire simple. Clasa ios este clasa de baz vitual pentru clasa istream (care face conversia dup un format specificat, din caracterele unui obiect de tip streambuf), clasa ostream (care face conversia dup un format specificat, n caractere ale unui obiect de tip streambuf) i clasa iostream (care face conversii n ambele sensuri). Legtura dintre cele dou ierarhii se realizeaz printr-o dat membru a clasei ios (pointer la streambuf).

io s is t re am io s t re am is t re am _w it has s ig n o s t re am _w it has s ig o s t re am

io s t re am _w it has s ig

Clasele derivate din clasa istream sau ostream se numesc clase stream iar obiectele claselor derivate din clasa ios se numesc streamuri. n fiierul iostream.h sunt definite streamurile cin ( istream_withassign, pentru stdin), cout ( ostream_withassign, pentru stdout), clog i cerr ( ostream_withassign, pentru stderr, cu respectiv fr zone tampon).

27.1. Operatorul de inserare <<


Operaiile de scriere se pot efectua cu operatorul de inserare << . Operandul stng trebuie s fie un obiect al clasei ostream (sau al unei clase derivate). Pentru scrierea pe dispozitivul standard se va folosi obiectul cout. Operandul drept este o expresie pentru al crei tip a fost suprancrcat operatorul << . Pentru tipurile standard a fost suprancrcat printr-o funcie membru de forma: ostream& operator << ( Tip_Standard );

123

Pentru tipurile abstracte programatorul poate suprancrca acest operator, aa cum se poate vedea n cele ce urmeaz. Pentru a putea tipri un obiect cout << Obiect ; vom suprancrcrca (ntr-o prim variant) operatorul de inserare (<<) printr-o funcie prieten astfel: class Clas { ... friend ostream& operator << ( ostream&, Clas ); ... }; Exemplu: / / Pr ogr am O per a tor << Fr ie nd ; \ \
#include <iostream.h> #include <conio.h>

class Q { protected: int p,q; public: Q (int m=0, int n=1) { p=m;q=n; } friend ostream& operator << ( ostream& s, Q r ) { s << r.p << "/" << r.q; return s; } }; void main (void) { Q r(12,13); cout << " r = " << r << endl; }
clrscr(); getch();

// Rezultate:
r = 12/13

Se observ c acest operator se poate aplica nlnuit pentru c funcia prieten returneaz o referin la stream-ul curent. n cele ce urmeaz vom da o alt rezolvare fr a utiliza o funcie prieten (care micoreaz gradul de protecie a datelor). Pentru o Clas vom scrie o funcie membru de Tiprire, care va fi apelat de ctre funcia de suprancrcare a operatorului << astfel: class Clas { public: ... ostream& Tiprire ... ( ostream& s );

}; ostream& Tiprire ( ostream& s ) { s << ... ; return s; } ostream& operator << ( ostream&, Clas c ) { return c.Tiprire(s); }

124

Pentru exemplul anterior (Q) programul va fi urmtorul: //


#include <iostream.h> #include <conio.h>

Pr ogr am O per at or <<

\\

class Q { protected: int p,q; public: Q (int m=0, int n=1) { p=m;q=n; } ostream& Tip (ostream& s) { s << p << "/" << q; return s; } }; ostream& operator << ( ostream& s, Q r ) { return r.Tip(s); }
clrscr(); getch();

void main (void) { Q r(12,13); cout << " r = " << r << endl; }

// Rezultate:
r = 12/13

27.2. Operatorul de extragere

>>

Operaiile de citire se pot efectua cu operatorul de extragere >> . Operandul stng trebuie s fie un obiect al clasei istream (sau al unei clase derivate). Pentru citirea de la dispozitivul standard se va folosi obiectul cin. Operandul drept este o expresie pentru al crei tip (standard sau abstract) a fost suprancrcat operatorul >> . Pentru tipurile standard a fost suprancrcat printr-o funcie membru de forma: istream& operator >> ( Tip_Standard & ); Pentru tipurile abstracte programatorul poate suprancrca acest operator, aa cum se poate vedea n cele ce urmeaz. Pentru a putea citi un obiect cin >> Obiect ; vom suprancrcrca (ntr-o prim variant) operatorul de extragere (>>) printr-o funcie prieten astfel: class Clas { ... friend istream& operator >> ( istream&, Clas& ); ...

};

125

Exemplu: //
#include <iostream.h> #include <conio.h>

Pr ogr am O per a tor >> Fr ie nd ;

\\

class Q { protected: int p,q; public: Q (int m=0, int n=1) friend ostream& operator << { s << r.p << " / " << friend istream& operator >> { s >> r.p >> }; void main (void) { Q r; cin >> r; cout << " r = " << r << endl; }

{ p=m; q=n; ( ostream& s, r.q; return ( istream& s, r.q; return

} Q r ) s; } Q& r ) s; }
clrscr(); getch();

Se observ c acest operator se poate aplica nlnuit pentru c funcia prieten returneaz o referin la stream-ul curent. n cele ce urmeaz vom da o alt rezolvare fr a utiliza o funcie prieten (funcie care micoreaz gradul de protecie a datelor). Pentru o Clas vom scrie o funcie membru de Citire, (care va fi apelat de ctre funcia de suprancrcare a operatorului >> ) astfel: class Clas
{

public:

istream& Citire
...

...

( istream& s );

istream& Citire ( istream& s ); { s >> ... ; return s;


} { }

};

istream& operator >> ( istream&, Clas& c ); return c. Citire (s);

Pentru exemplul anterior (Q) programul va fi urmtorul: //


#include <iostream.h> #include <conio.h>

Pr ogr am O per at or >>

\\

class Q { protected: int p,q; public: Q (int m=0, int n=1) { p=m; q=n; } ostream& Tip (ostream& s) { s << p << "/" << q; return s; } istream& Cit (istream& s) { s >> p >> q; return s; } }; ostream& operator << ( ostream& s, Q r ) { return r.Tip(s); } istream& operator >> ( istream& s, Q& r ) { return r.Cit(s); } void main (void) { Q r; clrscr(); cin >> r ; cout << " r = " << r << endl; getch();

126

27.3. Intrri/Ieiri cu format


Tiprirea (afiarea) datelor dup un anumit format (ablon) precizat (asemntor funciilor scanf i printf) se poate realiza i cu ajutorul ierarhiilor de clase definite n C++, fie prin apelul funciilor membru setf, width, fill, precision , fie cu ajutorul unor metode speciale numite manipulatori.

27.3.1. Funciile membru setf, width, fill, precision


Clasa ios conine o dat membru x_flags care conine formatul operaiilor de intrareieire. n aceeai clas mai este definit un tip enumerare prin care se poate referi formatul corespunztor conversiei ataate operaiilor de transfer:
class ios { enum { skipws left right internal dec oct hex showbase showpoint uppercase showpos scientific fixed unitbuf stdio }; }; = = = = = = = = = = = = = = = 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 // // // // // // // // // // // // // // // salt peste (ignor la citire) caracterele albe cadrare la stnga cadrare la dreapta spaiile dup semn sau baz conversie n zecimal conversie n octal conversie n heza afiarea bazei afiare punct zecimal cifre hexa cu litere mari afiare cu semn reale cu exponent reale fr exponent vidare zone tampon sup scriere vidare stdout i stderr public:

Atributul x_flags are o valoare implicit pentru fiecare tip standard, care se poate modifica utiliznd funcia membru setf descris n continuare. Metoda setf are urmtoarele dou forme: 1) long setf (long format); 2) long setf (long bit, long grup); Funcia modific atributul x_flags preciznd ntraga valoare (varianta a)) sau preciznd un grup de bii i bitul dorit din cadrul grupului (varianta b)). Grupele (i valorile corespunztoare) sunt adjustfield (left, right, internal), basefield (dec, oct, hex) i floatfield (scientific, fixed) n ambele variante funcia returneaz valoarea anterioar a atributului x_flags. Referirea grupului i bitului dorit se face prin numele clasei urmat de operatorul de rezoluie i bitul dorit ( ios::b). Valoarea atributului x_flags se poate obine i prin apelul metodei flags (cout.flags() ). Atributul x_width conine lungimea minim a cmpului de afiare a unei date (respectiv lungimea maxim a cmpului din care se face citirea), avnd valoarea implicit 127

nul (afiare pe lungimea minim necesar), care se poate modifica utiliznd funcia membru width descris n continuare n ambele forme: a) int width ( ); b) int width (int lungime); Funcia returneaz valoarea atributului x_flags (varianta a)) sau modific atributul x_width preciznd noua valoare (lungime care poate fi o expresie) i returneaz valoarea anterioar a atributului x_width (varianta b)). Dup fiecare transfer valoarea atributului x_flags devine nul. Atributul x_fill conine caracterul de umplere necesar completrii cmpului de afiare a datei n situaia n care lungimea acestuia este mai mare dect lungimea necesar, avnd valoarea implicit spaiu ( ), care se poate modifica utiliznd funcia membru fill : a) char fill ( ); b) char fill (char car); Funcia returneaz valoarea atributului x_ fill (varianta a)) sau modific atributul x_ fill preciznd noul caracter de umplere (car) i returneaz valoarea anterioar (varianta b)). Atributul x_precision conine precizia de afiare (numrul de zecimale) a unei date de tip real, avnd valoarea implicit 0, care se poate modifica utiliznd funcia membru precision : a) int precision ( ); b) int precision (int n); Funcia returneaz valoarea atributului x_ precision (varianta a)) sau modific atributul x_ precision preciznd noua precizie (p) i returneaz valoarea anterioar (varianta b)). n exemplul urmtor se poate vedea apelul funciilor prezentate anterior precum i rezultatele obinute:
// #include <conio.h> #include <iostream.h> class N { int public: istream& ostream& operator }; c; N (int x=0 ) { c=x; } Cit (istream& s) { s >> c; return s; } Tip (ostream& s) { s << c; return s; } double ( ) { return this-> c; } Op erat oru l d e i n serare

<< cu form a t \\

// N -> R

istream& operator >> (istream& s, N& C) { return C.Cit(s); } ostream& operator << (ostream& s, N C) { return C.Tip(s); }

128

void main (void) { N n; cout << " Dati un numar natural : "; cin >> n; cout << " Numarul natural n este: " << n << endl; cout.setf(ios::hex,ios::basefield); cout << " Numarul natural n este: " << n << endl; cout.setf(ios::showbase); cout << " Numarul natural n este: " << n << endl; cout << " Numarul natural n este: "; cout.setf(ios::dec,ios::basefield); cout.width(6); cout.fill('.'); cout << n << endl; double x(n); cout << " Numarul n/3.14159 este: "; cout.setf(ios::fixed,ios::floatfield); cout.width(9); cout.fill('_'); cout.precision(2); cout << x/3.14159 << endl;

clrscr();

getche(); }

Rezultate:
Dati un Numarul Numarul Numarul Numarul Numarul numar natural : natural n este: natural n este: natural n este: natural n este: n/3.14159 este: 100 100 64 0x64 ...100 ____31.83

27.3.2.

Manipulatori

Atributele x_flags, x_width, x_fill i x_precision pot fi modificate i cu ajutorul manipulatorilor, acetia avnd avantajul c pot fi apelai nlnuit (deoarece returneaz referin la stream). Primii apte manipulatori prezentai n continuare sunt declarai n fiierul iostream.h, iar ultimii ase n fiierul iomanip.h :
1. 2. 3. 4. 5. 6. 7. 1. 2. 3. 4. 5. 6.

ws dec oct hex flush ends endl setbase (int b) setiosflags (int f) resetiosflags (long f) setw (int l) setfill (int c) setprecision (int p)

setarea bitului de salt (skipws) conversie n zecimal conversie n octal conversie n hexa vidarea zonei tampon a ob. stream inserare car. Nul \0 trece la rnd nou i vidarea zonei tampon definete baza n care se face conversia setarea unor bii precizai tergerea unor bii precizai definete lungimea cmpului definete caracterul de umplere definete numrul de zecimale

Exemplul urmtor utilizeaz manipulatorii pentru a realiza tiprirea rezultatelor dorite:

129

//
#include <conio.h> #include <iostream.h> #include <iomanip.h>
class N {

Op erat oru l d e i n serare

<< cu manipul atori \\


Rezultate :
n : 100 n = 100 n = 64 : 2001 n = 0x64 n = ...100 n/3= ____33.33

int c; public: N (int x=0 ) { c=x; } istream& Cit (istream& s) { s >> c; return s; } ostream& Tip (ostream& s) { s << c; return s; } operator double ( ) { return this-> c; } }; istream& operator >> (istream& s, N& C) { return C.Cit(s); } ostream& operator << (ostream& s, N C) { return C.Tip(s); }

void main (void) { N n; cout << " n : cout << " n = cout << " n = cout << " n = cout << " n = cout << "n/3= }

clrscr(); "; cin >> n; " << n << endl; " << hex << n <<" : "<< cout.flags() << endl; " << setiosflags(cout.showbase) << n << endl; " << dec <<setw(6)<<setfill('.')<< n << endl; " << setw(9)<<setfill('_')<<setprecision(2)<<n/3; getche();

n exemplul urmtor se utilizeaz manipulatorii pentru a realiza citirea datelor utiliznd un format variabil (width(i+1)):
#include <conio.h> #include <iostream.h> #include <iomanip.h> class N { char c[6]; public: N ( istream& Cit (istream& ostream& Tip (ostream& }; istream& operator >> (istream& s, ostream& operator << (ostream& s, void main (void) {

//

Op erat oru l d e e xt r age re

>> cu manipulat ori \\


Rezultate :
1 : 1234567890 _______________ n = 1 2 : _______________ n = 23 3 : _______________ n = 456 4 : _______________ n = 7890 5 : 1234567890 _______________ n = 12345
clrscr();

) { c[0]=0; } s) { s >> c; return s; } s) { s << c; return s; } N& C) {return C.Cit(s);} N C) {return C.Tip(s);}

N n; for (int i=1; i<=5; i++) { cout << i << " : "; cin >> setw(i+1) >> n ; // cin.width(i+1); cout << " _______________ n = " << n << endl; }
getche(); }

130

27.4. Tratarea erorilor la operaiile de intrare/ieire


Dac o operaie de intrare/ieire nu s-a ncheiat cu succes (nu s-a desfurat corect, situaie n care vom spune c streamul ajunge ntr-o stare de eroare), programul poate lua o decizie (controlnd n acest fel desfurarea transferurilor de date n scopul corectitudinii desfurrii lor). Tipul erorii (un codul de retur) poate fi aflat verificnd biii datei membru state (de tip int) prin tipul enumerare io_state definit n clasa ios astfel:
class ios { enum { public: = = = = = 0x00, 0x01, 0x02, 0x04, 0x80, // // // // // operaie corect sfrit de fiier eroare intrare/ieire operaie invalid eroare fatal

goodbit eofbit failbit badbit hardfail };

};

1) 2) 3) 4) 5)

Valorile (biilor) atributului state se pot determina utiliznd urmtoarele funcii: int good (); // biii de eroare (eofbit, failbit, badbit, hardfail) nu sunt setai, int eof (); // este setat bitul eofbit, int fail (); // este setat bitul failbit sau badbit sau hardfail, int bad (); // este setat bitul badbit sau hardfail, int rdstate (); // returneaz toate valorile biilor de stare (valoarea datei state).

Valorile biilor datei state pot fi modificate cu funcia: void clear (int = 0); La un apel fr paramteru actual se vor anula biii eofbit, failbit i badbit iar pentru a preciza un anumit bit se poate folosi ca parametri actual o expresie de forma: cin.clear (ios::nume_bit); // nume_bit restul anulai Exemplu: cin.clear (ios::bad_bit | cin.rdstate() ); // bad_bit restul neschimbai Citirea (inclusiv a caracterelor albe) se poate realiza cu funcia membru getline definit astfel: istream& getline ([un]signed char* z, int n, char c = \n); care citete cel mult n-1 caractere sau ntlnete caracterul c. n exemplul urmtor se citesc mai multe cuvinte separate prin spaii:

class N { char

c[80];

Rezultate :
: Citeste spatiile. = Citeste spatiile. : ^Z

}; void main (void) { N n; }

istream& Cit (istream& s) {s. getline (c,80); return s;}

do {cout <<':'; cin >>n; if (cin. good ()) cout <<'='<<n<<endl;} while (!cin. eof());

131

n exemplul urmtor se repet citirea pn cnd numrul tastat este corect:


#include <conio.h> #include <iostream.h> class N { int c; public: N ( ) { c=0; } istream& Cit (istream& s) { s >> c; return s; } ostream& Tip (ostream& s) { s << c; return s; } }; istream& operator >> (istream& s, N& C) { return C.Cit(s); } ostream& operator << (ostream& s, N C) { return C.Tip(s); } void main (void) {

//

C on t rol u l erori l or l a op . I/E \\ Rezultate :


n : a State : 2 n : ^Z State : 3 n : 123 State : 0 n = 123
clrscr();

N n; int Gresit; do { cout << " n : "; cin >> n ; cout << " State : " << hex << cin.rdstate() << endl; if (cin.good()) Gresit=0; else { Gresit=1; cin.clear(); // anulare biti char t[255]; // zona tampon cin.getline(t,255); // vidare z.t. } } while (Gresit); cout << " n = " << dec << n << endl;
}

getche();

Verificarea strii de eroare a unui stream se mai poate face prin operatorul ! sau prin conversia ntr-un pointer fr tip (void*) :
a) operatorul ! este suprancrcat cu metoda clasei ios:

int operator ! ( );

// returneaz o valoare egal cu a funciei fail();

De exemplu, n programul Propoziie.Cpp prezentat anterior instruciunea if (cin.good()) cout << '=' << n << endl; se poate nlocui cu if (!!cin) cout << '=' << n << endl; sau mai simplu cu if (cin) cout << '=' << n << endl;
b) conversia spre tipul void* permite verificarea strii de eroare a stream-ului, i poate fi

utilizat n construcii de forma if ( s >> dat) ; rezultatul (o referin la obiectul stream clasei istream) fiind NULL (0) dac funcia fail( ) 0. Citirea caracterelor sau a datelor se poate realiza i cu funcia membru get definit astfel: a) int get ( ); // extrage un caracter din stream-ul curent, // nu extrage caracterul c.

b) istream& get ([un]signed char* z, int n, char c = \n);

132

n exemplul urmtor se poate vedea att utilizarea conversiei spre tipul void*, precum i a funciei membru get ( n varianta b)):
// #include <iostream.h> #include <string.h> class N { c; Mes; Mer; Met; N (int c=0, char* mes=" : ", char* mer=" Err.\n", char* met=" = "); istream& Cit (istream& s); ostream& Tip (ostream& s) {s<<Met<<c; return s;} }; char* met) strcpy(Mes,mes); strcpy(Mer,mer); strcpy(Met,met); int char* char* char* public: C on t rol u l erori l or l a op . I/E \\

N::N (int c, char* mes, char* mer, { this->c=c; Mes=new char[strlen(mes)+1]; Mer=new char[strlen(mer)+1]; Met=new char[strlen(met)+1]; }

istream& N::Cit(istream& s) { cout << Mes; while (!(s>>c)) { char t[255]; s.clear(); s.get(t,255); if (s.get()==EOF) return s; cout << Mer << Mes; } return s; } istream& operator >> (istream& s, N& C) { return C.Cit(s); } ostream& operator << (ostream& s, N C) { return C.Tip(s); } void main (void) { N n; do { cin >> n; if (cin) cout << n << endl; } while (!cin.eof()); } Rezultate :
: 123 = 123 : a Err. : 456 = 456 : xy Err. : ^Z

133

Cuprins
pag. 1. Redactarea programelor C.....................................................................2
1.1. Generaliti.................................................................................................2 1.2. Structura unui program...............................................................................2 1.3. Funcii........................................................................................................3 1.4. Elementele limbajului................................................................................4

2. Variabile...................................................................................................5
2.1. Variabile globale........................................................................................5 2.2. Variabile locale..........................................................................................5 2.3. Variabile de tip registru..............................................................................6 2.4. Iniializarea variabilelor.............................................................................7

3. Expresii.....................................................................................................8
3.1. Operatori....................................................................................................8

4. Operaii de intrare/ieire.......................................................................12
4.1. Funcia Printf .........................................................................................12 4.2. Funcia Scanf .........................................................................................13 4.3. Funcia PutChar .....................................................................................14 4.4. Funcia GetChar .....................................................................................14 4.5. Funcia GetChe ......................................................................................14 4.6. Funcia GetCh .........................................................................................14

5. Instruciuni.............................................................................................15
5.1. Instruciunea Vid ..................................................................................15 5.2. Instruciunea Expresie ............................................................................15 5.3. Instruciunea Compus ...........................................................................15 5.4. Instruciunea If .......................................................................................16 5.5. Instruciunea Switch ...............................................................................16 5.6. Instruciunea While ................................................................................17 5.7. Instruciunea Do_While .........................................................................17 5.8. Instruciunea For.....................................................................................18 5.9. Instruciunea Break .................................................................................18 5.10. Instruciunea Continue ..........................................................................18

134

5.11. Instruciunea GoTo ................................................................................18 5.12. Apelul unei funcii ................................................................................19

6. Pointeri...................................................................................................21
6.1. Declararea unui Pointer ...........................................................................21 6.2. Operaii cu Pointeri .................................................................................21 6.3. Alocare dinamic a memoriei ..................................................................23 6.4. Pointeri la funcii....................................................................................23 6.5. Utilizarea parametrilor din linia de comand...........................................25 6.6. Declararea constantelor ..........................................................................25 6.7. Stiva ........................................................................................................25

7. Recursiviate ...........................................................................................26 8. Tipuri de date.........................................................................................27


8.1. Definirea unui tip de dat (typedef).......................................................27 8.2. Tipul enumerare (enum)...........................................................................27 8.3. Definirea unei structuri (struct)...............................................................28 8.4. Redefinirea unei date (union)...................................................................29 8.5. Cmpuri de biti........................................................................................29

9. Structuri de date dinamice....................................................................30


9.1. List simplu nlnuit ordonat...............................................................30 9.2. Abori binari..............................................................................................31

10. Utilizarea fiierelor..............................................................................33


10.1. Nivelul inferior.......................................................................................33 10.2. Nivelul superior......................................................................................36

11. Funcii standard...................................................................................41


11.1. Macrouri de clasificare...........................................................................41 11.2. Macrouri de transformare a simbolurilor................................................41 11.3. Conversii................................................................................................41 11.4. Funcii de prelucrare a irurilor de caractere..........................................42 11.5. Funcii de calcul.....................................................................................42 11.6. Funcii pentru controlul proceselor........................................................42 11.7. Funcii pentru timp.................................................................................43 11.8. Funcii diverse .......................................................................................43

135

12. Ecranul n mod text.............................................................................44 13. Ecranul n mod grafic..........................................................................44 14. Faciliti C++.......................................................................................48
14.1. Extensii ale limbajului C........................................................................48 14.2. Operatori...............................................................................................49 14.3. Structur, uniune i enumerare...............................................................52

15. Funcii C++...........................................................................................54


15.1. Funcii Inline..........................................................................................54 15.2. Funcii de tip referin............................................................................55 15.3. Suprancrcarea funciilor......................................................................57 15.4. Iniializarea parametrilor formali............................................................58 15.5. Funcii membru pentru Structuri............................................................59

16. Tip Abstract de Dat...........................................................................60 17. Programare orientat obiect (OOP).................................................64


17.1. Definirea Claselor .................................................................................65 17.2. Constructori i Destructori .................................................................69

18. Specificarea claselor Limbajul UML(Unified Modeling Language) 72 19. Funcii i Clase Prietene (Friend)......................................................73 20. Membri statici (Static) // $:................................................................77
20.1. Atribute (Date membru) Statice // $:......................................................77 20.2. Metode (Funcii membru) Statice // $:....................................................79

21. Pointeri la Metode...............................................................................79 22. Suprancrcarea operatorilor ...........................................................82


22.1. Operatorul de asignare (atribuire) i iniializare (=)...............................83 22.2. Operatorii de atribuire +=, =, *=, /=................................................85 22.3. Operatorii de incrementare (++) i decrementare ()...........................86

23. Conversii utilizator..............................................................................87


23.1. Conversii implicite.................................................................................87 23.2. Conversii explicite.................................................................................90

136

24. Clase ablon (Template).....................................................................92


24.1. Funcii ablon (Template)......................................................................92 24.2. Clase Template ......................................................................................93 24.3. Implementarea elementelor Template ....................................................94

25. Relaii ntre clase.................................................................................95


25.1. Relaia de Asociaie ...............................................................................95 25.2. Relaia de Agregare................................................................................99 25.3. Clase ncuibate(imbricate)....................................................................102 25.4. Relaia de derivare................................................................................104

26. Polimorfism........................................................................................115
26.1. Funcii membru Virtuale......................................................................116 26.2. Clase abstracte - funcii membru virtuale pure.....................................119

27. Ierarhii pentru Intrri/Ieiri............................................................123


27.1. Operatorul de inserare <<...................................................................123 27.2. Operatorul de extragere >>...............................................................125 27.3. Intrri/Ieiri cu format..........................................................................127 27.4. Tratarea erorilor la operaiile de intrare/ieire......................................131

133 Cuprins....................................................................................................134 Bibliografie..............................................................................................138

137

Bibliografie

1. Dan Roman, Ingineria programrii obiectuale, Editura Albastr, Cluj_Napoca, 1996; 2. Dorin & Ioan Mircea Popovici, Iustin Tanase, Tehnologia orientat pe obiecte. Aplicaii, Editura Teora, Bucureti, 1996; 3. Ellis Horowitz, Sartaj Sahni, Dinesh Metha , Fundamentals of data structures in C+
+,

Computer Science Press, New York, 1995;

4. Liviu Negrescu, Limbajele C i C++ pentru nceptori, Editura Albastr, Cluj_Napoca, 1997; 5. Thomas A. Standish, Data Structures, Algorithms & Software Principles in C, Addison-Weslay, California, 1995; 6. Vasile Cioban, Zsolt Darvay, Metode evoluate de programare, UBB-Mate_Info, 1999;

138

Vous aimerez peut-être aussi