Académique Documents
Professionnel Documents
Culture Documents
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.
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;
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.
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); }
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:
++
(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 ++;
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
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 ?
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).
[f]
unde:
- 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
[ f ] , unde:
- 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
Litere mici in Litere MARI ! LITERE MICI IN LITERE MARI ! Se termina la . (Punct) SE TERMINA LA . getchar putchar getchar putchar
LITERE MICI IN LITERE MARI. // S-a tastat: Litere mici in Litere MARI.
14
5.
Instruciuni
;
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)
{
Declaraii Instruciuni
}
Exemplu: { int i;
// Variabil local instruciunii; //
f (i); } ;
// 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_; {
[ break; ] [ break; ]
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
// break; getche();
17
18
{ ...
... } // instruciune
et: ...
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; }
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;
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 :
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.
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
22
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();
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();
23
Numele unei funcii fiind un pointer la acea funcie, ea poate fi parametru actual, i evident trebuie descris ca parametru formal:
...
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)
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
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
Valoare ] ;
sau
Unui parametru formal declarat cu modificatorul Const nu i se mai poate schimba valoarea n subprogramul respectiv. Exemplu:
#include <stdio.h>; #include <conio.h>;
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();
}
int Pop() { if (Next>0) return Stiva[--Next]; else { printf(" Stiva vida \n"); return 0; }
}
{ 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.
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
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
sau
Var_Ref >Component;
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();
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
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(); }
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;
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
Nivelul inferior - face apel direct la sistemul de operare; Nivelul superior - utilizeaz proceduri speciale pentru operaii de intrare/ieire.
10.1.1.
unde:
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:
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.
Funcia returneaz numrul de octei scrii n fiier, reprezentnd lungimea articolului = l u n g , sau -1 n caz de eroare.
10.1.4.
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.
10.1.6.
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.1.
unde:
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:
...
10.2.2.
unde:
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)
{ }
36
10.2.3.
10.2.4.
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(); }
int n=0;
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();
#include <stdio.h> #include <conio.h> void main (void) { FILE *Produse; char Den[20]; int Cant; float Pret;
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:
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
/* 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) { 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++);
10.2.6.
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.
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;
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); }
...
getchar();
{...
fread
(&Art,sizeof(Articol),1,Pf);
printf("- Den. : %s\n", Art.Den ); printf("- Pret : %f\n", Art.Pret); } fclose (Pf);
40
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 ?
[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.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.
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)
Semnifica ie
termin un program la eroare termin un program returnnd un cod de retur
42
int
struct time
Semnifica ie Citete Data curent : Modific Data curent : Citete Ora Exact : Modific Ora Exact :
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); }
1. 2.
43
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}
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 \\
/ /
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);
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)
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
#include <iostream.h>;
void main (void)
{ int i;
<< " 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>;
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();
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 =
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 = " <<
for (int i=11; i<::i; ::i-=11) cout << i <<"::"<< ::i << endl; }
14.2.2.
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>;
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();
#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();
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.
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>;
50
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
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
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"
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
#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
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
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();
}
//
\\
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); }
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)
{
{ { { {
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
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
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
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() ; }
Com pilare
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);
// PMult.Cpp \\
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
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).
- implementarea unui TAD, - instana unei clase, - mesajul prin care se asigur interfaa (operaiile).
metoda
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
{ [ Modificator_de_protecie: ] List_membrii }
}; unde:
Modificator_de_protecie { private, protected, public} private nu permite accesul din afara clasei,
protected permite accesul din clasele derivate, public permite accesul din afara clasei;
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 };
private:
(x,y) e
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
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 > \\ ---------------------------- \\
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
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();} };
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:
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
Specificarea relaiilor dintre clase : relaia de asociere : relaia de derivare : // prietenie // motenire
Student- Facultate: String - Varst : int+ Student () + Student (Student &) +~Student ( )
72
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;
float r;
};
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>
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:
};
73
Exemple:
//
# # # # # include include include include define
\\
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; }
74
# # # # # #
//
\\
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 <conio.h>
Clasa friend
# include <graphics.h>
# include <iostream.h>
\\
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 () { }
};
~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.
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(); }
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.
// $ :
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>
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();
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)); } () { }
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(); }
// x(t) // y(t)
78
// $ :
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
St_Sus, Dr_Jos; MinX() { return MaxX() { return MinY() { return MaxY() { return
} } } }
// // // //
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();
Grafic Mod(DETECT);
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
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 () { }
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
// 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; }
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
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>
//
\\
# include <Iostream.h>
class String { char* s; public: String (); String (const String&); String (const char*); String& operator=(const String&);
// // // //
friend
a) b)
}; 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
(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 ... ... ... ... ... < <= > >= == <>
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
(Op.
+=, -= ) \\
# include <Iostream.h>
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
//
// // // //
int operator < (const Natural&); ~Natural (); int Length ();
... prefixat incr ... postfixat ... ... prefixat decr ... postfixat ... // ... relational < // Destructor // Numarul de cifre
};
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; }
86
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>;
Q void };
Produs (Q);
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; };
clrscr();
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
88
#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);
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; }
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
class Q { public:
long m; long n; Q (long, long); operator double(); Q operator *(Q); Tip (const char* Mes);
}; 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();
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
//
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>
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
//
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)
93
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;
# pragma option Jgd typedef Vect<int, 10> Vint10; typedef Vect<float,10> Vflo13;
94
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.
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 \\
Clas asociat \\
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::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 \\
98
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 \\
Clas Agregant \\
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 \\
//
Clas Agregat \\
\\
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 ! ( ) };
{ { { {
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
Raza Centrul
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();
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
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#+ +#+###
by
cz
a protected: Cl_Derivat x
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 };
N(s+1)
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; }
Semn; ) : N( ) s) : N(s+1) ) )
} } } }
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
//
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 \\
// 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 \\
Clas
Derivat \\
# 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;
x,y;
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
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
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>
\\
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); }
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>
\\
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; \\
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 .
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
//
Met od vi r t u al
\\
class Cb { public: virtual void f() { cout << " Baza }; class Cd : public Cb { public: }; void
{
g(Cb* p) { p->f(); }
clrscr();
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
{
g(Cb& r) { r.f(); }
clrscr();
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>;
\\
#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();
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
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 { { }
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
Punct
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:
}; 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);
121
getche();
InitGraf();
getche(); closegraph();
122
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).
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
\\
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
>>
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>
\\
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; }
} 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 );
};
\\
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
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
129
//
#include <conio.h> #include <iostream.h> #include <iomanip.h>
class N {
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) {
//
) { 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
};
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
do {cout <<':'; cin >>n; if (cin. good ()) cout <<'='<<n<<endl;} while (!cin. eof());
131
//
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 ! ( );
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.
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
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
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
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
136
26. Polimorfism........................................................................................115
26.1. Funcii membru Virtuale......................................................................116 26.2. Clase abstracte - funcii membru virtuale pure.....................................119
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+
+,
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