Note de laborator: C++ - · PDF file13 #undef LA_REVEDERE 14 #define LA_REVEDERE \ 15...
Transcript of Note de laborator: C++ - · PDF file13 #undef LA_REVEDERE 14 #define LA_REVEDERE \ 15...
Note de laborator:C++
Vers. 2.0 — Corectat: iunie 2013
Octavian G. Mustafa∗
e-mail address: [email protected]
Cuprins
Motivatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1Programe din “viata reala” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10Alte programe ın C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28Programare ın C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63Si acum? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208Surse bibliografice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
1 Motivatie: plecand de la zero. . .
Incepem discutia cu cateva programe scrise ın limbajul C. Aceasta pentruca, ın mediul Internet, exista mult cod C gratuit pe care ıl putem adaptanevoilor noastre. Limbajul C++ este o extensie (un superset) a limbajului C,vezi [41, p. 8], astfel ca intructiunile dintr-un program C “portabil” (veziPOSIX, ANSI C etc., cf. [33], [20, p. 151]) vor functiona excelent ın cadrulunui program C++.
Putem, fireste, studia limbajul C++ ın mod direct, fara a apela la C, cf.[42, p. 9], ınsa nu vom face aceasta aici. Se obisnuieste — ın cartile blande cucititorul — sa se ınceapa studiul unui limbaj de programare descriind “cum
∗Acest eseu nu a fost raportat vreunui referent. In consecinta, continutul sau trebuieconsiderat “ca atare.” In particular, utilizarea instructiunilor care urmeaza se face peraspunderea dumneavoastra. Autorul va asteapta comentariile la adresa de e-mail de maisus si va multumeste anticipat pentru efortul depus.
1
se vede” acesta din urma dinspre limbajul cu care cititorul este deja obisnuit,vezi, e.g., [45, pg. 4, 5]. Eu cred ın aceasta abordare . . .
Programele care urmeaza sunt scrise folosind mediul de dezvoltare Visual Stu-
dio sub sistemul de operare Windows XP Professional SP 3, accesibil ın multe sali
de clasa ori via MSDNAA. De asemeni, ele sunt testate sub Windows 7 Profes-
sional SP 1 (x86). Mentionez ca C-ul de la Microsoft este compatibil cu editia
1990 a ANSI C, cf. [7].
Construim un director (folder) destinat viitoarelor programe C si C++,C:\ProiecteleMele_Cpp, dupa care apelam Visual Studio-ul, vezi Figura1.
Figura 1
Alegem New Project, dupa care, vezi Figura 2, ın lista Installed Tem-
plates, optam pentru Visual C++. In tabelul central, selectam Empty Pro-
ject. Numele proiectului — ın primul din campurile albe din partea dejos a ferestrei (pop-up) New Project — va fi primul_program iar pen-tru a stabili locatia acestuia ın directorul construit anterior folosim bu-tonul Browse. Ultimul camp al ferestrei New Project, si anume Solution
name (solutia. . . ), va deveni, automat, primul_program. Evident, solutia —fisierul primul_program.sln din directorul C:\ProiecteleMele_Cpp\pri
mul_program — va permite ın urma unei duble apasari pe butonul stangal mouse-ului ıncarcarea proiectului nostru ın mediul Visual Studio, indifer-ent daca acesta este ın executie sau nu. Insa aceasta numai dupa ce vom ficonstruit primul nostru proiect!
2
Figura 2
Daca totul este ın ordine, apasam butonul OK, vezi Figura 2. Mai departe,ın functie de setarile mediului Visual Studio, pe ecran vor aparea diferiteferestre ın care scriem cod, respectiv sunt afisate diverse informatii, veziFigura 3. Folosind butonul View din meniul principal, putem vizualiza —daca nu au fost setate deja — ferestrele Solution Explorer, Properties,Output, Document Outline, Error List s.a.m.d. Atentie, desi ın Figura 3fereastra centrala este de culoare alba, ceea ce noi vom vedea initial va fi unspatiu de culoare albastru metalizat, ca ın centrul Figurii 4.
In acest moment, putem introduce fisierele proiectului nostru, si anumecentru.c si headerulnostru.h. Pentru aceasta, urmarind Figura 4, nepozitionam cu cursorul pe elementul Source Files al listei din fereastraSolution Explorer. Apasand butonul drept al mouse-ului, remarcam apari-tia unei noi ferestre, din care vom selecta elementul Add. Acesta, odataselectat, va face vizibila o alta fereastra, ın cadrul careia vom opta pentruelementul New Item.
Avand cursorul pozitionat pe elementul New Item, apasam butonul stangal mouse-ului, ceea ce produce aparitia ferestrei Add New Item primul_prog
ram, vezi Figura 5. Aici, selectam din tabelul central elementul C++ File(
.cpp). Urmarind Figura 5, ne deplasam ın partea de jos a ferestrei activepana la campul Name. Acesta va fi completat cu numele ıntreg al fisierului
3
Figura 3
nostru, adica program.c. Atentie, daca nu scriem si particula .c, fisierulva fi salvat ca program.cpp, adica un fisier cu cod C++. La urma urmei,compilatorul cl.exe care sta ascuns sub capota mediului de dezvoltare VisualStudio este un compilator C/C++! Apoi apasam butonul Add.
Finalizarea cu succes a operatiei ne conduce la aparitia elementului program.c ın lista Source Files din fereastra Solution Explorer, vezi din nouFigura 3. Reluam procedeul, vezi Figura 4, plecand de la elementul HeaderFiles din fereastra Solution Explorer, si alegem, urmarind Figura 5, el-ementul Header File(.h) din tabelul central. Odata ıncheiat acest pas,putem practic trece la scrierea codului. . . din primul nostru proiect VisualStudio.
Pozitionand cursorul pe elementul headerulnostru.h din fereastra Solu-tion Explorer, apasam butonul stang al mouse-ului, ceea ce va produceaparitia unei zone de culoare alba ın centrul ecranului, vezi Figura 3. Inaintede a scrie primul nostru program — desigur, daca acest detaliu nu a fostınca setat —, dorim sa numerotam liniile de cod. Ne va fi mai usor astfelsa depanam (debug) programele C/C++. Pentru a activa numerotarea ıncauza, apasam butonul Tools din meniul principal al Visual Studio-ului, caın Figura 6. Din fereastra nou aparuta, selectam elementul Options.
Apasand butonul Options, producem aparitia ferestrei Options, vezi
4
Figura 4
Figura 7. Aici, din lista situata ın partea stanga, ın zona de culoare alba,alegem elementul Text Editor, ceea ce va permite vizualizarea unei noiliste de optiuni. Dintre acestea, alegem elementul C/C++. In acest moment,urmarind Figura 7, putem selecta ın zona Display din partea dreapta a fere-strei active optiunea Line numbers. Pentru a salva aceasta alegere, apasambutonul OK.
Acum, revenind la campul central de culoare alba cu titlul headerulnostru.h, introducem urmatoarele linii de cod.
Un header “utilitar” ın C: headerulnostru.h
1 #i f !defined( HEADERULNOSTRU )
2 #define HEADERULNOSTRU
3 /* ---------------------*/
4
5 /* diverse headere:*/
6 #include <stdio.h>
7 #include <conio.h>
8 #include <stdlib.h>
9 #include <malloc.h>
10 #include <Windows.h>
11
5
Figura 5
12 /* rutina de incheiere */
13 #undef LA_REVEDERE
14 #define LA_REVEDERE \
15 MessageBox(NULL, \
16 TEXT("\u00CEncheiem minunatul program ?\t"), \
17 TEXT("Cutie de dialog"), \
18 MBOK);
19
20 /* ---------------------*/
21 #endif
In mod identic, adaugam ın campul program.c codul sursa al programu-lui.
Primul nostru program ın VS C: program.c
1 #include "headerulnostru.h"
2
3 main(){
4 pr int f ("\nIncepem ...\n");
5 LA_REVEDERE
6 }
6
Figura 6
Trebuie facut urmatorul comentariu vizavi de “ciudata” mea preferinta pen-tru un element vizual, si anume MessageBox. Programele C sunt programe “deconsola” — acel ecran negru. . .—, cu executie ıntr-un singur fir1, cf. [20, p. 2],ınsa noi ne aflam ın Windows, deci consola este numai un proces, cf. [35, p. 88,Chap. 4], denumit cmd.exe, ın cadrul caruia ne manifestam. Acest proces poate fi“vazut” cu Windows Task Manager. Atunci cand rulam un program ın consola —o instanta a cmd.exe —, acesta poate fi observat ın lista de procese afisata de TaskManager. Tehnic vorbind, a opta la punctul de intrare ıntre _tmain si _tWinMaineste o chestiune de linkare (/SUBSYSTEM:CONSOLE), vezi [35, p. 91]. De aceea,mi-am permis sa introduc o modalitate grafica de control ın cadrul programuluimeu C.
Chestiunea mai multor fire de executie — multi-threading — este ıncredintata
sistemului de operare (via functia CreateThread) ınsa se recomanda utilizarea
functiei Windows C/C++ _beginthreadex— care “stie” cum sa apeleze CreateTh-
read. . .—, vezi [35, pg. 182–183, Chap. 6].
Pentru instructiunile de preprocesor , marcate cu # ın codul sursa, amurmat recomandarile din [20, pg. 89, 90, 229]. Astfel, pentru a defini unmacro pe mai multe linii se foloseste caracterul “\”. Pentru concatenareamacrourilor, vezi pagina 162, utilizam ##.
Odata salvate fisierele din proiect — vezi butonul “cu diskete” de sub me-niul principal al VS-ului —, dorim sa le compilam. Pentru aceasta, urmarindFigura 8, utilizam butonul Debug (compilare–cu–corectura) al meniului prin-cipal. In fereastra care va aparea, raspundem la ıntrebarea “This pro-
1La fel si programele C++, vezi [41, p. 357].
7
Figura 7
ject is out of date: Would you like to built it?” apasand buto-nul Yes.
Putem folosi butonul F5 pentru a comanda compilarea–cu–corectura aunui program.
Daca introducerea codului sursa a decurs fara greseli, rezultatul actiuniinoastre este asemanator situatiei din Figura 9. Dupa ce apasam butonul OK,executia programului se va ıncheia cu codul 0, vezi Figura 10.
Pentru diversele optiuni privind “lansarea oficiala” a programului (vari-anta de productie), folosim butonul Build din meniul central: Clean Solu-
tion2, Batch Build — aici apare versiunea Release —, etc.In sfarsit, primul nostru program C dezvoltat ın mediul Visual Studio este
gata. El se gaseste — primul_program.exe — ın directorul C:\ProiecteleMele_Cpp\primul_program\Debug. Il lansam ın executie apasand de douaori butonul stang al mouse-ului atunci cand cursorul este pozitionat pestemica imagine (bitmap) intitulata primul_program.exe, vezi Figura 11.
Un alt comentariu trebuie facut ın ıncheierea acestei sectiuni. In multesituatii, atunci cand dezvoltam un proiect C sub mediul Visual Studio,dorim ca, la sfarsitul executiei sale, “consola” programului sa ramana de-schisa. . . Pentru aceasta avem mai multe optiuni, printre care si introducereaunor elemente vizuale gen MessageBox. Astfel, fie apelam programul din
2In Visual C++ 2010 Express, vezi pagina 40, utilizam butonul Tools si aici optampentru Settings/Expert Settings ca sa ajungem la Clean Solution.
8
Figura 8
consola — via Start/Run/cmd —, fie ınlocuim codul sursa din program.c cuurmatorul set de instructiuni.
O alta vizualizare a aplicatiei: program.c
1 #include "headerulnostru.h"
2
3 main(){
4 pr int f ("\nIncepem ...\n");
5 /* LA_REVEDERE */
6 getch (); /* din <conio.h> */
7 }
Exista opinia ca apelarea uneia dintre variantele functiei getch — o im-plementare a sa folosind getchar poate fi citita ın [20, p. 79] — pentruvizualizarea rezultatelor executiei va avea drept efect introducerea unor date“aiurea” ın sistem. Trebuie ınsa observat ca, la ıncheierea corecta a pro-cesului primul_program.exe, sistemul de operare, printre altele, va eliberamemoria folosita de firul de executie principal, cf. [35, p. 124], deci nu vor
9
Figura 9
ramane date ın sistem. . .
2 Programe din “viata reala”
Imi pare mai atractiv sa ne reamintim cateva elemente ale limbajului Cprin intermediul unor programe utilitare — pe care, la o adica, sa le punem latreaba rapid! —. Aceste programe pot fi, evident, ımbunatatite; de exemplu,ele nu stiu sa revina dintr-o ıntrerupere hardware, cf. [42, p. 133].
Program:> TEX este un sistem de procesare a textelor stiintifice, cu o larga raspandire,vezi [46, 27], una dintre implementarile sale fiind platforma TEX Live, cf. [47].Codul sursa al platformei contine libraria (colectia) kpathsea, folosita d.ex.la cautarea fisierelor cu fonturi. Programul care ne intereseaza citeste primalinie dintr-un fisier text, indiferent de lungimea acesteia. Singura restrictieimediata este ca textul din fisierul ın cauza sa se ıncheie cu ENTER — ceeace pare rezonabil daca ne referim la un fisier al carui continut este un sir decaractere introduse de la tastatura. . .—.
10
Figura 10
Proiectul VS linie_arbitrara, prezentat ın continuare, modifica mini-mal continutul fisierelor line.h, line.c din libraria kpathsea. El este for-mat din fisierele headerulnostru.h, linie.h, centru.c si linie.c. Fisierultext din care citim este test.txt. El trebuie introdus ın directorul C:ProiecteleMele_Cpp\linie_arbitrara\linie_arbitrara ınaintea compilarii.
Am inserat ın codul sursa al proiectului mai multe citate din documentatia
on-line a VS-ului, vezi [26]. Desi numarul de linii de cod se mareste substantial,
dat fiind ca proiectul va fi pastrat ın calculator, adaosul este justificat.
Proiectul linie_arbitrara: linie.h
1 #i f !defined ( LINIE )
2 #define LINIE
3 /* ---------------------*/
4
5 #define BLOC_DE_DATE 75
6
7 #define MODUL_DEBUG 1
11
Figura 11
8 /* ---
9 Daca dorim sa dezactivam modul "debug":
10 #undef MODUL_DEBUG
11 ---*/
12
13 char * read_line(FILE *);
14
15 /* ---------------------*/
16 #endif
Proiectul linie_arbitrara: centru.c
1 #include "headerulnostru.h"
2 #include "linie.h"
3 #include <errno.h>
4
5 int main(){
6
12
7 FILE *studiu = NULL;
8 char *citire = NULL;
9 errno t eroare = 0;
10
11 pr int f s ("\n+++++++\n"
12 "Urmatorul program citeste\n"
13 "linia curenta , oricat de lunga ,\n"
14 "dintr -un fisier ASCII dat.\n"
15 "+++++++\ n");
16
17 i f ( fopen s (&studiu ,"test.txt","r") != 0){
18 pr int f s ("Probleme cu cititul fisierului...");
19 }
20 e l se {
21 citire = read_line(studiu);
22 pr int f s ("\nLinia citita este:\n\n%s",citire);
23
24 i f ( f c l o s e (studiu) != 0){
25 pr int f s ("Probleme cu inchiderea fisierului...");
26 }
27 }
28
29 f ree ((void *) citire);
30 get errno (&eroare);
31 pr int f s ("\n\nEroare: %d\n",eroare);
32 citire = NULL;
33
34 LA_REVEDERE
35 return 0;
36 }
Proiectul linie_arbitrara: linie.c
1 /* ----
2 Functia "read_line", descrisa in continuare ,
3 reprezinta o mica variatie a functiei cu acelasi nume
4 din fisierul "line.c" al programului "kpathsea ".
5 (" line.c: return the next line from a file , or NULL",
6 copyright: Karl Berry , Olaf Weber)
7 "kpathsea " face parte din distributia "TeX Live"
8 a sistemului publicistic TeX.
9 ----*/
10
11 #include "headerulnostru.h"
13
12 #include "linie.h"
13
14 char * read_line(FILE *fisier){
15
16 int c;
17 unsigned int limit = BLOC_DE_DATE;
18 unsigned int loc = 0;
19 char *line = NULL;
20 char *intermediar = NULL;
21
22 i f (( line = (char *) malloc(limit)) == NULL){
23 #i f defined( MODUL_DEBUG )
24 pr int f s ("Probleme de alocare a memoriei ...");
25 #endif
26 /* ---------------
27 "malloc returns a void pointer to the allocated space
28 or NULL if there is insufficient memory available."
29 "malloc sets errno to ENOMEM if a memory allocation
30 fails or if the amount of memory requested exceeds
31 _HEAP_MAXREQ."
32
33 citate de pe:
34 http:// msdn.microsoft.com/en-us/library /6ewkz86d.aspx
35 constanta "_HEAP_MAXREQ" se gaseste in "<malloc.h>"
36 ----------------*/
37 }
38 e l se {
39 while (((c = getc (fisier)) != EOF)
40 && (c != ’\n’) && (c != ’\r’)) {
41 line[loc] = c;
42 /*----
43 optiune: afisam (imediat) caracterul pe ecran...
44 _putch(c);
45 ----*/
46 loc++;
47 /* ------
48 Testam daca mai avem spatiu liber.
49 In caz contrar , adaugam spatiu.
50 -----*/
51 i f (loc == limit) {
52 limit += BLOC_DE_DATE;
53 i f (
54 (intermediar = (char *) rea l l oc ((void *)line , limit))
14
55 == NULL
56 ){
57 /*----
58 "If there is not enough available memory to expand
59 the block to the given size , the original block is
60 left unchanged , and NULL is returned ."
61 "realloc sets errno to ENOMEM if the memory alloca -
62 tion fails or if the amount of memory requested
63 exceeds _HEAP_MAXREQ."
64
65 citate de pe:
66 http:// msdn.microsoft.com/en-us/library/xbebcx7d .aspx
67 ----*/
68 /*----
69 Daca suntem aici , nu am terminat de citit linia ,
70 insa nu mai putem mari memoria alocata citirii.
71 Eliberam memoria folosita pana acum si iesim...
72 ----*/
73 f ree ((void *)line);
74 line = NULL;
75 /*----
76 "is safe (throws away the pointer ’s location )."
77 citat de pe:
78 http://en.wikipedia.org/wiki/Malloc
79 ----*/
80 #i f defined( MODUL_DEBUG )
81 pr int f s ("Probleme de (re)alocare "
82 "a memoriei ...");
83 #endif
84 return NULL;
85 }
86 e l se {
87 line = intermediar;
88 }
89 }
90 }
91 i f (c == EOF) {
92 i f ( f error (fisier)){
93 /* -----
94 "To indicate a read error or end -of-file condition ,
95 getc returns EOF , and getwc returns WEOF. For getc ,
96 use ferror or feof to check for an error or for end
97 of file."
15
98
99 citat de pe:
100 http:// msdn.microsoft.com/en-us/library /5231d02a.aspx
101 -----*/
102 /*----
103 Daca suntem aici , nu am terminat de citit linia ,
104 insa au aparut erori de citire. Eliberam
105 memoria folosita pana acum si iesim...
106 ----*/
107 f ree ((void *)line);
108 line = NULL;
109 #i f defined( MODUL_DEBUG )
110 pr int f s ("Probleme cu stream -ul citit...");
111 #endif
112 return NULL;
113 }
114 e l se {
115 /* -----
116 Daca suntem aici , am ajuns la capatul fisierului...
117 Ultima linie nu se poate incheia cu NEWLINE ...
118 Atentie , daca avem un fisier a carui ULTIMA LINIE
119 nu se incheie cu ENTER , functia returneaza NULL...
120 -----*/
121 f ree ((void *)line);
122 line = NULL;
123 }
124 }
125 e l se {
126 /*----
127 Daca suntem aici , caracterul din stream -ul citit
128 este fie ’\r’, adica CARRIAGE RETURN (CR), fie ’\n’,
129 adica NEWLINE (LINE FEED sau LF).
130 Niciunul nu poate fi vizualizat , deci inlocuim
131 acest caracter cu "zero".
132 ------*/
133 line[loc] = 0;
134 i f (c == ’\r’) {
135 /*----
136 Citim caracterul urmator din stream; exista macar
137 unul , caci "c != EOF".
138 ----*/
139 i f ((c = getc (fisier)) != ’\n’){
140 i f ( f error (fisier)){
16
141 f ree ((void *)line);
142 line = NULL;
143 #i f defined( MODUL_DEBUG )
144 pr int f s ("Probleme 2 cu stream -ul "
145 "citit...");
146 #endif
147 return NULL;
148 }
149 e l se i f (ungetc(c,fisier) == EOF){
150 /*----
151 "If c cannot be pushed back or if no character has
152 been read , the input stream is unchanged and ungetc
153 returns EOF; ungetwc returns WEOF."
154
155 citat de pe:
156 http:// msdn.microsoft.com/en-us/library /29hykw2y.aspx
157 ----*/
158 f ree ((void *)line);
159 line = NULL;
160 #i f defined( MODUL_DEBUG )
161 pr int f s ("Probleme la refacerea "
162 "stream -ului citit...");
163 #endif
164 return NULL;
165 }
166 }
167 }
168 }
169 }
170
171 #i f defined( MODUL_DEBUG )
172 /*----
173 Afiseaza nr. de caractere citite ...
174 ----*/
175 pr int f s ("\nNr. de caractere parcurse :"
176 "\t%d\n",loc);
177 #endif
178 return line;
179 }
In cadrul proiectului linie_arbitrara, am presupus ca pentru a com-pleta fisierul test.txt nu folosim o tastatura locala, ci ne bazam doar pecaracterele ASCII — aici, un caracter (char) ınseamna un octet (byte) —,
17
cf. [20, p. 36], [3]. Aceasta prezumtie este corecta atunci cand ne referim laTEX, un sistem publicistic care functioneaza pe tastaturi “limitate”. . . creandcaracterele suplimentare ca metaforme. Insa nucleul Windows NT (versiu-nile 5.1, 5.2 pentru Windows XP, respectiv 6.1 pentru Windows 7, vezi [29])foloseste sistemul Unicode (UTF16) de notare a caracterelor pentru a facefata diverselor alfabete. Fireste, putem utiliza fara probleme “literele” de unoctet lungime, caci functiile Windows vor realiza conversiile necesare ıntreUnicode si ANSI (Windows-1252, etc), ori de cate ori este necesar, cf. [35,p. 35].
Am folosit si un macro “de depanare”, MODUL_DEBUG, complementar luiNDEBUG, vezi [20, p. 254], [41, p. 750].
Program:> Ilustrez, ın traditia K&R [20, p. 9], folosirea caracterelor multi-octet prin-tr-un convertor de temperatura primitiv ın cadrul proiectului Visual Studioconvertor_FC_1. Reamintesc formulele de conversie:
(C → F ) Fahrenheit =
(
Celsius ×9
5
)
+ 32,
respectiv
(F → C) Celsius = (Fahrenheit− 32)×5
9.
Vezi si [11].In codul sursa, am utilizat o varianta “securizata” a functiei sprintf
din biblioteca C standard, cf. [20, p. 245], respectiv [35, p. 42]. Aceastase numeste StringCchPrintf, se apeleaza via <strsafe.h> si se gasesteın Windows SDK, vezi [50], care trebuie, evident, instalat ınaintea rulariiproiectului VS — ın momentul testarii, versiunea SDK-ului este 7.1 —.
Proiectul convertor_FC_1: fc1.c
1 /* ---
2 Copyright: Octavian , 2011 - -2014
3 ---*/
4
5 #define UNICODE
6 #define _UNICODE
7
8 #include <malloc.h>
9 #include <Windows.h>
10
11 /* ---
12 Putem include efectiv "<WinNT.h>" in lista
18
13 headerelor (continut in "<WinDef.h>")
14 cu conditia ca "<Windows.h>" sa fie
15 inaintea sa.
16 Macro -uri:
17 -- TEXT in "<WinNT.h>"
18 -- S_OK in "<WinError .h>", "<strsafe.h>"
19 ---*/
20
21 #include <tchar.h>/* --- pt. _tmain ---*/
22 #include <strsafe.h> /* --- pt. "StringCchPrintf";
23 ne trebuie Windows SDK...
24 ---*/
25
26 void tmain(){
27
28 TCHAR sir[] = TEXT("Temperatura este: 9999 \u00B0C");
29 s i z e t lungime = countof (sir);
30 /* ---
31 in cele patru spatii ocupate de "9999"
32 introducem valoarea temperaturii...
33 ---*/
34
35 int temperatura_F = 49,
36 temperatura_C = ( int )
37 (0.556 * temperatura_F - 32);
38
39 i f (
40 StringCchPrintf(
41 sir ,
42 lungime ,
43 TEXT("Temperatura este: %d \u00B0C"),
44 temperatura_C
45 ) != S OK
46 ){
47 MessageBox(NULL,
48 TEXT("StringCchPrintf"),
49 TEXT("Probleme cu func\u01ABia:"),
50 MBOK);
51 exit (EXIT FAILURE);
52 }
53
54 MessageBox(NULL,
55 sir ,
19
56 TEXT("Rezultat :"),
57 MBOK);
58 exit (EXIT SUCCESS);
59 }
60 /*----
61 Alternatively , the main and wmain functions
62 can be declared as returning void (no return
63 value). If you declare main or wmain as
64 returning void , you cannot return an exit code
65 to the parent process or operating system by
66 using a return statement. To return an exit
67 code when main or wmain is declared as void ,
68 you must use the exit function .
69
70 citat de pe:
71 http:// msdn.microsoft.com/en-us/library /6wd819wh.aspx
72 ----*/
De multe ori, atunci cand doresc sa deschid un fisier header sau sa malamuresc asupra tipului unei anumite variabile, ma pozitionez cu cursorul pemarimea respectiva (d.ex., size_t) si apas butonul drept al mouse-ului, caın Figura 12. Alegand optiunea Go To Definition, aflu detaliile ın cauza,inclusiv numele fisierului — ori DLL-ul3 — ın care acestea sunt continute.
Program:> A doua varianta a convertorului, ın proiectul convertor_FC_2, testeazadaca avem suficienta memorie pentru manipularea sirului de caractere cetrebuie afisate.
Proiectul convertor_FC_2: fc2.c
1 /* ---
2 Copyright: Octavian , 2011 - -2014
3 ---*/
4
5 #define UNICODE
6 #define _UNICODE
7
8 /* ---
9 Despre utilizarea macro -urilor
10 "UNICODE", "_UNICODE "
11 vezi
12
13 Richter , Nassare , Windows via C/C++ 5th Ed., pag. 38
14 Petzold , Programming Windows 5th Ed., pag. 32
3Abrevierea de la dynamic link library, vezi, d.ex., [2, pg. 491, 492].
20
Figura 12
15 ---*/
16
17 #include <malloc.h>
18 #include <Windows.h>
19 #include <tchar.h>
20 #include <strsafe.h>
21
22 /* ---
23 lungimi
24 ---*/
25 #undef MAX_LUNGIME
26 #define MAX_LUNGIME 25
27
28 /* ---
29 un macro pentru erori:
30 ---*/
31 #undef EROARE
32 #define EROARE(text ,cod) \
33 MessageBox(NULL, \
34 TEXT(text), \
35 TEXT("Probleme cu func\u01ABia:"), \
36 MBOK); \
37 exit (cod);
38
21
39 void tmain(){
40 TCHAR *sir_larg = NULL;
41 int temperatura_F = 47,
42 temperatura_C = ( int )
43 (0.556 * temperatura_F - 32);
44
45 /* ---
46 Doresc sa manipulez sirul:
47 "Temperatura este: [maxim 4 cifre] 0C".
48 Avem 25 de caractere , pe care le rotunjesc
49 la 30, caci un sir TEXT(...) nu se termina
50 obligatoriu cu ’\0’...
51
52 Vezi si:
53 http:// msdn.microsoft.com/en-us/library/dd374116 .ց
(cont.) aspx
54
55 sau Petzold , pag. 23
56 ---*/
57 i f (
58 (sir_larg = (TCHAR *) malloc(
59 (MAX_LUNGIME+5) * s i z eo f (TCHAR)
60 )
61 ) == NULL
62 ){
63 EROARE("malloc",EXIT FAILURE)
64 }
65
66 /* ---
67 trunchiem sirul sir_larg si copiem ceva in el...
68 ---*/
69 i f (
70 StringCchPrintf(sir_larg ,
71 ( s i z e t )MAX_LUNGIME ,
72 TEXT("Temperatura este: %d \u00B0C"),
73 temperatura_C
74 ) != S OK
75 ){
76 f ree ((void *) sir_larg );
77 sir_larg = NULL;
78 EROARE("StringCchPrintf",EXIT FAILURE)
79 }
80
22
81 MessageBox(NULL,
82 sir_larg ,
83 TEXT("Cutie de dialog:"),
84 MBOK);
85 f ree ((void *) sir_larg);
86 sir_larg = NULL;
87 exit (EXIT SUCCESS);
88 }
Program:> Revenind la “literele” de un octet lungime (char), formulez urmatoareaproblema a convertorului de temperatura: dorim sa citim gradele Fahren-heit (numar real) ıntr-un sir care cuprinde caracterele4
“ -”, “,”, “ ” (spatiu gol) si “ C”.
De exemplu, temperatura ın Bucuresti, la statia Baneasa, este:
32,5 C
Solutia data problemei, ın cadrul proiectului VS convertor_FC_3, pre-supune implementarea a doua functii: functia de conversie “(cifra) −→ (cara-cter)”, numita simbol, si functia de transformare “(numar real) −→ (sir decaractere)”, numita populare.
Se cuvine sa reamintim cateva chestiuni. In primul rand, o data de tipulchar este, practic, un numar ıntreg mic, cf. [20, pg. 42, 36], — deci aresens operatia 25 -’g’, cu rezultatul -78 — . De asemeni, literele ’a’, ’b’,’c’, etc. formeaza un bloc continuu (contiguu) ın setul de caractere ASCII.Acest lucru se poate schimba pentru alte seturi de caractere, deci dorim ofunctie simbol independenta de pozitia caracterelor ın set. D.ex., functiiledin <ctype.h> sunt independente de setul de caractere, vezi [20, p. 43]. Adoua chestiune se refera la precizia rezultatului afisat. Se stie ca, atunci candoperam cu numere reale, functiile de conversie realizeaza trunchieri/rotunjiriale datelor, pe care dorim sa le controlam, vezi [20, p. 45] pentru operatoriide conversie, respectiv [20, pg. 9, 15] pentru doua variante ale convertoruluide temperatura. De acest control va raspunde functia populare.
Proiectul convertor_FC_3: program.c
1 #include "headerulnostru.h"
2 #include "convertor.h"
3 #include <errno.h>
4Atentie, am folosit ghilimelele ın sens literar, si nu. . . informatic. Astfel, ın interiorulunui program, "C" desemneza un sir constant , adica un array terminat ın ’\0’, cf. [20,p. 104].
23
4
5 main(){
6 double fahrenheit = 126.2,
7 celsius = (fahrenheit - 32)*5/9;
8 char *citire = NULL;
9 errno t eroare = 0;
10 pr int f s ("\n%7.3f\n",celsius);
11 /*---
12 7: numar minim de caractere afisate;
13 3: numar de zecimale afisate ,
14 vezi Jamsa & Klander , pag. 72, Sect. 68
15 ---*/
16 citire = populare(celsius);
17 pr int f s ("\n%s\n",citire);
18 /*---
19 curat memoria ...
20 testez daca am reusit ...
21 ---*/
22 f ree ((void *) citire);
23 get errno (&eroare);
24 pr int f s ("\n\nEroare: %d\n",eroare);
25 citire = NULL;
26 LA_REVEDERE
27 }
Proiectul convertor_FC_3: convertor.h
1 #i f !defined ( CONVERTOR )
2 #define CONVERTOR
3
4 #undef MODUL_DEBUG
5 #define MODUL_DEBUG 1
6
7 #undef LUNGIME
8 #define LUNGIME 8
9 /* ---
10 numar maxim de caractere:
11 [minus][ zeci][unitati ][ virgula ][zecimala ][ spatiu][C][ց
(cont.) incheiere]
12 ---*/
13 #undef CELSIUS_MIN
14 #define CELSIUS_MIN -99
15 #undef CELSIUS_MAX
16 #define CELSIUS_MAX 99
24
17
18 char simbol( int );
19 char * populare(double);
20
21 #endif
Proiectul convertor_FC_3: simbol.c
1 #include "headerulnostru.h"
2 #include "convertor.h"
3
4 char simbol( int cifra){
5 char rezultat ;
6 switch(cifra){
7 case 0: return (rezultat = ’0’);
8 case 1: return (rezultat = ’1’);
9 case 2: return (rezultat = ’2’);
10 case 3: return (rezultat = ’3’);
11 case 4: return (rezultat = ’4’);
12 case 5: return (rezultat = ’5’);
13 case 6: return (rezultat = ’6’);
14 case 7: return (rezultat = ’7’);
15 case 8: return (rezultat = ’8’);
16 case 9: return (rezultat = ’9’);
17 case 10: return (rezultat = ’-’);
18 case 11: return (rezultat = ’,’);
19 default: return (rezultat = ’?’);
20 }
21 }
Proiectul convertor_FC_3: populare.c
1 #include "headerulnostru.h"
2 #include "convertor.h"
3
4 char * populare(double celsius){
5 char *sir = NULL;
6 int contor = 0, iterator = 0;
7 enum adevar { DA, NU } pozitiv = DA;
8
9 /*---
10 testarea limitelor CELSIUS:
11 ---*/
12 i f (( celsius < CELSIUS_MIN)
13 || (celsius > CELSIUS_MAX)){
25
14 pr int f s ("Date de intrare "
15 "incorecte...");
16 return NULL;
17 }
18
19 i f ((sir = (char *)malloc(
20 LUNGIME * s i z eo f (char)
21 )) == NULL){
22 pr int f s ("Eroare la alocare ...");
23 return NULL;
24 }
25
26 /*---
27 testarea valorilor negative pentru CELSIUS:
28 ---*/
29 i f (celsius < 0){
30 celsius = -celsius;
31 sir[contor ++] = simbol (10);
32 /* afisam "-" */
33 pozitiv = NU;
34 }
35
36 /*---
37 depistam cifra zecilor in CELSIUS:
38 ---*/
39 for (iterator = 10; iterator <= 100; iterator += 10){
40 i f (( celsius - iterator + 10 >= 0)
41 && (celsius - iterator < 0)){
42 sir[contor++] = simbol(( iterator - 10) /10);
43 celsius += - iterator + 10;
44 }
45 }
46
47 /*---
48 depistam cifra unitatilor in CELSIUS:
49 ---*/
50 for (iterator = 1; iterator <= 10; iterator ++){
51 i f (( celsius - iterator + 1 >= 0)
52 && (celsius - iterator < 0)){
53 sir[contor++] = simbol(iterator - 1);
54 celsius += - iterator + 1;
55 }
56 }
26
57
58 /*---
59 afisam virgula:
60 ---*/
61 sir[contor ++] = simbol (11);
62
63 /*---
64 depistam prima zecimala in CELSIUS:
65 ---*/
66 celsius *= 10;
67 /*trecem zecimala in stanga virgulei */
68 for (iterator = 1; iterator <= 10; iterator ++){
69 i f (( celsius - iterator + 1 >= 0)
70 && (celsius - iterator < 0)){
71 sir[contor++] = simbol(iterator - 1);
72 }
73 }
74
75 /*---
76 afisam " C" la sfarsitul sirului:
77 ---*/
78 sir[contor ++] = ’ ’;
79 sir[contor ++] = ’C’;
80
81 /*---
82 numere pozitive : compensam lipsa lui "-"
83 cu un spatiu gol la final...
84 ---*/
85 i f (pozitiv == DA){
86 sir[contor++] = ’ ’;
87 }
88
89 /*---
90 sirul se termina in null...
91 ---*/
92 sir[contor] = ’\0’;
93
94 /*---
95 comparam valoarea contorului cu LUNGIME:
96 ---*/
97 i f (contor > LUNGIME){
98 f ree ((void *)sir);
99 sir = NULL;
27
100 pr int f s ("Probleme cu "
101 "lungimea sirului ...");
102 return NULL;
103 }
104
105 /*---
106 dezactivare DEBUG:
107 #undef MODUL_DEBUG
108 ---*/
109
110 #i f defined ( MODUL_DEBUG )
111 pr int f ("\n\n++++\n%d\n++++\n",contor);
112 #endif
113 return sir;
114 }
“Inversa” functiei populare, si anume “(sir de caractere)−→(numar re-al)” este atof din <stdlib.h>. O implementare a sa se gaseste ın [20, p.71].
3 Alte programe5 ın C
Lista functiilor CRT (libraria run-time a limbajului C) se gaseste la adresa[12] pe platforma MSDN.
Cand pornim un program scris ın limbajul C, vezi [20, pag. 161], sistemulde operare va deschide trei fisiere — intitulate intrarea standard , iesirea stan-dard , respectiv eroarea standard — si ıi va transmite programului pointeri(date de tipul FILE *) la acestea: stdin, stdout si stderr. Pointerii ın cau-za sunt declarati ın <stdio.h>. In mod obisnuit, stdin se refera la tastatura,iar stdout si stderr la ecranului calculatorului. Intrarile si/sau iesirile potfi ınsa redirectionate6.
Program:> Asa cum stim, datele introduse de la tastatura sunt caractere ASCII, vezi[18, p. 137, Sect. 161; p. 515, Sect. 679]. Ceea ce ınseamna ca programul C“vede” intrarile noastre drept siruri de caractere. Urmatorul program preiacinci caractere de la tastatura7 si le afiseaza pe ecran.
Citeste cinci caractere: caract_1.c
1 /* ---
2 citeste cinci caractere de la tastatura
5O recapitulare. . . pe sarite.6In limba engleza, pipe.7Fara taste speciale sau combinatii de taste (d.ex., CTRL + C).
28
3 si apoi le afiseaza : o parola
4 ---*/
5
6 #include "headerulnostru.h"
7 /* ---
8 <conio.h>: pentru _getch , _putch
9 <stdlib.h>: pentru system
10 ---*/
11 #undef TESTARE
12 #define TESTARE 1
13
14 int main(void){
15 int litera ,
16 contor = 1;
17 #i fd e f TESTARE
18 char * tipar();
19 #endif
20
21 system("cls");
22 pr int f s ("\nTastati parola:\n");
23 for (; contor++ <= 5;){
24 litera = getch ();
25 putch(litera);
26 #i fd e f TESTARE
27 pr int f s ("%scontor :\t%d%s",
28 tipar(/* --- 9 ---*/),
29 contor ,
30 tipar(/* --- 10,"test" ---*/));
31 #endif
32 }
33 LA_REVEDERE
34 return 0;
35 }
36
37 #i fd e f TESTARE
38 char * tipar(){
39 return "\n+++ Testare !+++\n";
40 }
41 #endif
Am folosit void ın locul listei de argumente din functia main. Reamin-tesc faptul ca, pentru a asigura compilatorul ca o functie nu are argumente,se recomanda declaratia nume_functie(void). Cealalta varianta, si anumenume_functie(), nu implica inexistenta argumentelor, ci dezactiveaza veri-
29
ficarea listei acestora, cf. [20, p. 33]. Compilatorul din Visual Studio poate
emite un avertisment (Warning: too many arguments in function call), da-
ca folosim argumentele 9, respectiv 10,"test" ın apelul functiei tipar.
Program:> Functia tipar din proiectul anterior ignora parametrii dati de noi. Inprogramul de mai jos, vom ilustra o situatie aflata “la polul opus”, si anumefunctia sumare, care tine seama de un numar variabil de parametri. In de-claratia sa, folosim obligatoriu cel putin un argument obisnuit iar la finalelipsa8, “. . . ”, pentru a ne referi la argumentele ın numar variabil, vezi [20,p. 155]. Pentru a implementa functia sumare — care returneaza suma unuinumar variabil de numere, respectand formatul acestora (int, double) —,folosim tipul de date va_list — adica, char * — definit ın <vadefs.h>,respectiv macrourile va_start, va_arg si va_end din <stdarg.h>.
Ilustrarea elipsei: elli0.c
1 #include "headerulnostru.h"
2 #include <stdarg.h>
3 /* ---
4 pt. va_start , va_arg , va_end;
5 in <vadefs.h>, inclus , se gaseste va_list
6 ---*/
7 /* ---
8 pre -ANSI: <varargs.h>, actual "deprecated".
9 Acest header este folosit inca pentru compatibilitate
10 cu sistemele UNIX V, vezi:
11 http:// msdn.microsoft.com/en-us/library/kb57fad8 .aspx
12 http:// msdn.microsoft.com/en-us/library/we9107a3 .aspx
13 ---*/
14
15
16 #undef DEBUG
17 #define DEBUG 1
18 #undef ERORI
19 #define ERORI(texta ,textb ,textc) \
20 pr int f s ("\nEroare de format!\n" \
21 "Grupuri corecte: %d\n", \
22 texta); \
23 pr int f s ("Suma este , pana aici: %f\n", \
24 textb); \
25 pr int f s (textc);
26
27
8In limba engleza, ellipsis .
30
28 typedef enum valori {NUMAR , EROARE} controlul_erorii;
29
30 int main(){
31 controlul_erorii sumare(char *, ...);
32
33 /*---
34 sumam primele patru numere din lista de intrari ,
35 conform formatului lor:
36 "%d" --- numar intreg ,
37 "%f" --- numar cu virgula (double)
38 ---*/
39 sumare("%f%d%d%d" ,23.0,2,-100,4,"altceva" , -400.67);
40
41 /*---
42 recomandare MSDN:
43 folosirea operatorilor de cast pentru un format corect
44 ---*/
45 sumare("%d%f",( int )23.67, -0.5);
46
47 LA_REVEDERE
48 return 0;
49 }
50
51 controlul_erorii sumare(char *format , ...){
52 char *sir = format;
53 /*---
54 date pentru controlul formatului
55 ---*/
56 int contor_procent = 0,
57 contor_intreg = 0,
58 contor_real = 0,
59 contor_grup = 0;
60 double suma = 0.0;
61
62 /*---
63 introducem un pointer (char *)
64 la sirul argumentelor in numar variabil ,
65 si il pozitionam la primul dintre acestea
66 ---*/
67 va l i s t argumente_fara_nume;
68 va start (argumente_fara_nume ,format);
69
70 /*---
31
71 analiza formatului
72 ---*/
73 for (;*sir != ’\0’;){
74 i f (*sir++ != ’%’){
75 #i fd e f DEBUG
76 ERORI(contor_grup ,suma ,
77 "Grupul nu incepe cu \"%%\"...")
78 #endif
79 /*---
80 eliberam pointerul la sirul argumentelor
81 ---*/
82 va end(argumente_fara_nume);
83 return EROARE;
84 }
85 i f (*sir == ’d’){
86 contor_intreg++;
87 suma += va arg(argumente_fara_nume , int );
88 }
89 i f (*sir++ == ’f’){
90 contor_real++;
91 suma += va arg(argumente_fara_nume ,double);
92 }
93 contor_grup++;
94
95 /* ---
96 daca apare alta litera dupa %
97 ---*/
98 i f (
99 contor_grup != (contor_intreg + contor_real)
100 ){
101 #i fd e f DEBUG
102 ERORI(contor_grup -1,suma ,
103 "Grupul nu contine: d, f ...")
104 #endif
105 va end(argumente_fara_nume);
106 return EROARE;
107 }
108 }
109 #i fd e f DEBUG
110 pr int f s ("\nStatistici:\n"
111 "grupuri \"%%d\" %d\n"
112 "grupuri \"%%f\" %d\n",
113 contor_intreg ,contor_real);
32
114 #endif
115 pr int f s ("\nSuma este: %f\n",suma);
116 va end(argumente_fara_nume);
117 return NUMAR;
118 }
Program:> Urmatorul program manipuleaza diferentiat caracterele scrise ın consola:daca ıntalneste litera “z”, programul va trece pe randul urmator, iar dacaapasam ENTER executia se opreste. Vezi [18, p. 226; Sect. 294].
Citire diferentiata: caract_2.c
1 /* ---
2 citeste caracterele de la tastatura ,
3 daca intalneste "z"-ul, trece pe un rand nou
4 iar daca apasam ENTER se opreste
5 ---*/
6 #include "headerulnostru.h"
7
8 int main(void)
9 {
10 int litera;
11 system("cls");
12 do{
13 litera = getch();
14 i f (litera != ’z’)
15 putch(litera);
16 e l se
17 pr int f s ("\n");
18 }
19 while (litera != ’\r’);
20 LA_REVEDERE
21 return 0;
22 }
Program:> Afisarea caracterelor “speciale” se face ın limbajul C cu ajutorul carac-terului escape “\”. Programul care urmeaza contine caracterele: “\n” – linienoua, “\t” – tabulator orizontal, “\r” – returnare de car, “\"” – apostrof,“\\” – backslash, “\?” – semnul ıntrebarii. Vezi si [18, p. 75; Sect. 74].
Caractere cu escape: caract_3.c
1 /* ---
2 caractere speciale in C (cu escape)
3 ---*/
4
33
5 #include "headerulnostru.h"
6
7 int main(void){
8 int numar = pr int f s ("as\nft\tfds\t\\\ns\nd\?\"sss"
9 "ss\nwerfggggu\ryyy\n");
10 pr int f s ("\nSirul are %d caractere.",numar);
11 LA_REVEDERE
12 return 0;
13 }
Program:> Importanta caracterului escape este relevata de un program care realizeazaurmatoarele sarcini: (i) creaza directorul C:\Diverse Programe ın sistemulde fisiere; (ii) creaza/verifica daca exista fisierul incercare.txt ın folderulC:\ProiecteleMele_Cpp\nume_proiect\nume_proiect; (iii) copiaza acestfisier ın noul director; (iv) introduce ın copie litera “D”. De asemeni, pen-tru un mai bun control vizual al erorilor, am utilizat functia GetACP din<WinNls.h>. Aceasta ne da informatii despre setul de caractere specialedisponibil ın calculator.
Introducerea unui fisier ın sistem: man_fis00.c
1 #define UNICODE
2 #define _UNICODE
3
4 #include "headerulnostru.h"
5
6 /* ---
7 macrouri de eroare , avertizare:
8 ---*/
9 #undef EROARE
10 #define EROARE(text ,cod) \
11 MessageBox(NULL, \
12 TEXT(text), \
13 TEXT("Mesaj de eroare:"), \
14 MBOK); \
15 exit (cod);
16 #undef MESAJ
17 #define MESAJ(text) \
18 MessageBox(NULL, \
19 TEXT(text), \
20 TEXT("Cutie de dialog"), \
21 MBOK);
22
23 /* ---
24 versiunea OS:
34
25 WX: Windows XP SP3 (Windows -1252 code page)
26 W7: Windows 7 SP1 (Windows -1250 code page)
27 ---*/
28 #undef WX
29 #define WX 1
30
31 #undef W7
32
33 int main(void)
34 {
35 FILE *fisier = NULL;
36
37 /*---
38 construiesc directorul
39 ---*/
40 system("cls & "
41 "mkdir \"C:\\ Diverse Programe \"");
42 #i fd e f WX
43 MESAJ("F\u00E3cut!")
44 #endif
45 #i fd e f W7
46 MESAJ("F\u0103cut!")
47 #endif
48 {
49 /*---
50 Atentie la codurile de pagina Windows (pt. caractere):
51 http:// msdn.microsoft.com/en-us/library/dd317752 .aspx
52 ---*/
53 # include <WinNls.h>
54 pr int f s ("\n\nCodul paginii este: %d\n\n",
55 ( int ) GetACP());
56 }
57
58 /*---
59 testez fisierul "incercare.txt"
60 ---*/
61 i f ( fopen s (&fisier ,"incercare.txt","a+") != 0){
62 EROARE("Eroare la deschidere \" incercare.txt\"!\n",
63 EXIT FAILURE)
64 }
65 i f ( f c l o s e (fisier) != 0){
66 EROARE("Eroare la inchidere \" incercare.txt\"!",
67 EXIT FAILURE)
35
68 }
69
70 /*---
71 copiez fisierul
72 ---*/
73 system(
74 "copy incercare.txt /A \"C:\\ Diverse Programe \" /A"
75 );
76
77 /*---
78 inserez caracterul "D"
79 ---*/
80 i f ( fopen s (&fisier ,
81 "C:\\ Diverse Programe \\ incercare.txt","a+") != 0){
82 EROARE("Eroare la creare/deschidere!\n",
83 EXIT FAILURE)
84 }
85 fputc(’D’,fisier);
86 i f ( f c l o s e (fisier) != 0){
87 EROARE("Eroare la inchidere!",EXIT FAILURE)
88 }
89
90 LA_REVEDERE
91 return 0;
92 }
Sa presupunem ca avem deja cateva programe scrise ın limbajul C. Inmulte cazuri, dorim sa rulam aceste programe din afara consolei . Reamintesc
faptul ca, tastand grupul de comenzi ALT + ENTER, consola activa se va ıntinde
ın 1-2 secunde la ıntreg ecranul calculatorului. Consola va reveni la dimensiunile
obisnuite daca repetam grupul de comenzi.
Program:> In programul urmator, folosim cateva functii Windows dedicate consolei,cf. [10], pentru a interactiona cu aceasta. In sistemele de operare Windows,
consola reprezinta numai un proces, adica o instanta a unui program ın executie
formata dintr-un obiect-nucleu si un spatiu de adrese, vezi [35, p. 88, Chap. 4].
Schimbarea titlului consolei: consola00.c
1 /* ---
2 Copyright: Octavian , 2011 - -2014
3 ---*/
4
5 #include "headerulnostru.h"
6
36
7 /* ---
8 lungimea unui sir de caractere
9 ---*/
10 #undef MARIME
11 #define MARIME 300
12
13 /* ---
14 macrouri de eroare , memorie:
15 ---*/
16 #undef EROARE
17 #define EROARE(text) \
18 pr int f s (text); \
19 LA_REVEDERE \
20 exit (EXIT FAILURE);
21 #undef LIBER
22 #define LIBER(nume) \
23 f ree ((void *)nume); \
24 nume = NULL;
25
26 int main(){
27 int litere ,
28 contor = 0;
29 char *titlu_vechi = NULL,
30 *titlu_nou = "Consola de lucru";
31 /* ---
32 date de tip Windows
33 ---*/
34 DWORD cat_am_scris = 10000L;
35 HANDLE maner = NULL;
36
37 /*---
38 aloc spatiu pentru citit titlul consolei
39 ---*/
40 i f (
41 (titlu_vechi =
42 (char *) malloc(MARIME * s i z eo f (char))) == NULL
43 ){
44 EROARE("Probleme de alocare ...")
45 }
46
47 /*---
48 caut consola in registru ...
49 ---*/
37
50 i f (
51 ((maner = GetStdHandle(STDOUTPUTHANDLE))
52 == INVALIDHANDLEVALUE)
53 /* --- functie din <WinBase.h> ---*/
54 || (maner == NULL)
55 ){
56 LIBER(titlu_vechi)
57 EROARE("Probleme de maner...")
58 }
59
60 system("cls");
61 /*---
62 citesc , modific titlul consolei
63 cu functii din <WinCon.h>
64 ---*/
65 i f (!GetConsoleTitleA ((LPSTR) titlu_vechi ,
66 (DWORD) MARIME * s i z eo f (char) -1)
67 ){
68 LIBER(titlu_vechi)
69 EROARE("Probleme de citit titlul ...")
70 }
71 pr int f s ("\n\nVechiul titlu al consolei este:\n"
72 "\"%s\""
73 "\n\nNoul titlu al consolei este:\n",
74 titlu_vechi);
75 i f (!SetConsoleTitleA(titlu_nou)){
76 LIBER(titlu_vechi)
77 EROARE("Probleme de resetare a titlului ...")
78 }
79
80 /*---
81 scriu in consola cu o functie Windows
82 ---*/
83 i f (!WriteConsoleA(maner ,
84 (const void *)titlu_nou ,
85 (DWORD) countof ("Consola de lucru"),
86 &cat_am_scris ,
87 NULL)
88 ){
89 LIBER(titlu_vechi)
90 EROARE("Probleme de scriere ...")
91 }
92
38
93 pr int f s ("\n\n+++++++\ n"
94 "Adaugati trei litere:\n\n");
95 for (;
96 contor++ <= 2;
97 litere = getch(), putch(’\n’), putch(litere)
98 );
99
100 LIBER(titlu_vechi)
101
102 LA_REVEDERE
103 return 0;
104 }
Program:> O metoda simpla de rulare, indepedent de consola, a unor programe ex-ecutabile — nume_program.exe — consta ın utilizarea unor fisiere batch(de comenzi), cf. [4], — comenzi.bat —. Presupunand ca, ın directorulC:\Proiectele Mele_Cpp, aducem fisierul caract_3.exe, vezi pagina 33,extras din subdirectorul Debug al proiectului VS respectiv, scriptul batch demai jos — salvat temporar pe ecranul calculatorului, C:\Documents and Set
tings\Octavian\Desktop — ıi comanda executia.
Controlul executiei: nume_program.bat
1 @echo o f f
2 set cale_fisiere=C:\ProiecteleMele_Cpp
3 cd %cale_fisiere%
4 nume_program.exe
5 :: inlocuim "nume_program" cu "caract_3 "
6 :: avem si comanda alternativa:
7 :: start /wait /b nume_program.exe
8 :: vezi http://ss64.com/nt/start.html
9 ca l l cmd
10 :: ramane consola deschisa
11 ::se tasteaza "exit" pt. iesire
Program:> Rezultatul executiei programului caract_3.exe poate fi redirectat catreun fisier, d.ex. rezultat_caract_3.txt, din acelasi director, folosind oper-atorul “>”. Vezi [20, p. 152].
Redirectarea rezultatului: caract_31.bat
1 @echo o f f
2 set cale_fisiere=C:\ProiecteleMele_Cpp
3 cd %cale_fisiere%
4 caract_3.exe > rezultat_caract_3.txt
5 notepad rezultat_caract_3.txt
39
6 ca l l cmd
7 ::se tasteaza "exit" pt. iesire
Program:> Un exemplu mai elaborat este scriptul batch prin intermediul caruia putemutiliza programul Microsoft Visual C++ 2010 Express (VC++) — gratuit,distribuit independent de VS, cf. [49] —
Codul sursa pentru batch-ul VC++
1 @echo o f f
2 :: variabile pentru VC++ si cmd
3 set cale_principala=C:\Program Files
4 set versiune =\ Microsoft Visual Studio 10.0
5 set drum_exec=\ Common7\IDE
6 set cale_vis=%cale_principala%%versiune%%drum_exec%
7 set help_vis_cont=/en-us/library/60k1461a.aspx
8 set help_vis=http://msdn.microsoft.com%help_vis_cont%
9 set cale_browser=C:\Program Files\Mozilla Firefox
10 set consola=C:\WINDOWS\system32
11 :: sfarsit variabile
12 :: folderul de proiecte
13 echo.
14 set cale_fisiere=C:\ProiecteleMele_Cpp
15 set treaba=mkdir %cale_fisiere%
16 set mesaj=Creat folderul de proiecte "ց
(cont.) ProiecteleMele_Cpp"!
17 i f not exist %cale_fisiere% (%treaba% & echo %mesaj%)
18 :: sfarsit operatii folderul de proiecte
19 chdir %cale_fisiere%
20 start explorer %cale_fisiere%
21 path=%path%;%consola%;%cale_vis%;%cale_browser%
22 echo.
23 echo Pentru Visual C++ Express , tastati: VCExpress
24 echo.
25 echo Pentrul "aplicatiile de consola", folositi ց
(cont.) comanda:
26 echo "cd.\ NumeleProiectului\Debug", dati "Enter" si ց
(cont.) apoi
27 echo tastati: "NumeleProiectului.exe". Pentru a reveni
28 echo la folderul de proiecte , tastati:
29 echo "cd.. & cd..".
30 echo.
31 echo Succes!
32 start firefox %help_vis%
33 echo. & ca l l cmd
40
Program:> Putem rula fisierul caract_31.bat, vezi pagina 39, si dintr-un proiect VS.Astfel, presupunand ca avem proiectul gol octombrie_31_2011 ın directorulde lucru, introducem ın subdirectorul cu acelasi nume fisierele caract_31
.bat si caract_3.exe — calea completa pana la fisiere trebuie sa fie C:\ProiecteleMele_Cpp\octombrie_31_2011\octombrie_31_2011 — . Codul ınlimbajul C de care avem nevoie este listat ın continuare.
Fisiere de comenzi: consola01.c
1 #include "headerulnostru.h"
2
3 int main(void){
4 system("caract_31.bat");
5 LA_REVEDERE
6 return 0;
7 }
Motivatia proiectului anterior este urmatoarea: atunci cand dorim intrarea ın
executie, ıntr-o ordine prestabila, a mai multor fisiere executabile, putem folosi
aceasta cale mixta pentru a evita complicatiile procese-parinte – procese-copil ori
introducerea mai multor fire de executie, vezi [35], [18, p. 561].
Program:> Functia system din <stdlib.h> transmite, asadar, linia de comanda aunui proces catre interpretorul cmd.exe, cf. [8]. Aici, trebuie sa avem grijala modul cum sunt procesate caracterele “speciale” — parsarea argumentelorunei comenzi, tokenizarea lor —. In programul urmator, folosim secventele“\"”, respectiv “^&” pentru o transmitere corecta a acestor argumente.
Linia de comanda: consola02.c
1 #include "headerulnostru.h"
2
3 int main(void){
4 pr int f s ("\nDe dimineata...\n"
5 "Ziare locale si nationale ,\n"
6 "schimb valutar ...\n");
7 system("\"C:\\ Program Files\\Mozilla Firefox"
8 "\\ firefox.exe\""
9 " http://www.gds.ro"
10 " http://www.romanialibera.ro"
11 " http://www.xe.com/currencycharts/"
12 "?from=EUR^&to=USD^&view=1D");
13
14 LA_REVEDERE
15 return 0;
16 }
41
Program:> Functia Windows GetCommandLineW din <WinBase.h> ıntoarce un pointerla bufferul ce contine ıntreaga linie de comanda, cf. [35, p. 97; Chap. 4].Vezi codul C urmator.
Linia de comanda: consola03.c
1 #define UNICODE
2 #define _UNICODE
3 #include "headerulnostru.h"
4
5 int main(void){
6 PWSTR linia_de_comanda = GetCommandLineW();
7 /*---
8 din <WinBase.h>
9 ---*/
10 MessageBox(NULL,linia_de_comanda ,
11 TEXT("Rezultat :"),MBOK);
12 LA_REVEDERE
13 return 0;
14 }
Program:> Urmatorul proiect se ocupa de cautarea unor cuvinte ıntr-un dictionar on-line al limbii romane. Acestea sunt precizate ın linia de comanda, cu careprogramul interactioneaza prin intermediul functiei main, cf. [20, p. 114],[18, p. 510; Sect. 669]. Rutinele din program pot fi realizate si cu functii din<string.h>, d.ex. strcat_s, strncat_s.
Linia de comanda: consola04.c
1 /* ---
2 Un program primitiv de cautare
3 in dictionarul on-line al limbii romane:
4 http:// dexonline.ro
5 -------------------
6 sintaxa:
7 consola04 [cuvant]
8 -------------------
9 Termenul [cuvant] este optional .
10 Cuvantul cautat poate avea <= 40 litere.
11 ---*/
12
13 #undef COMANDA_MAXIMA
14 #define COMANDA_MAXIMA 155
15 #undef COMANDA_REZERVA
16 #define COMANDA_REZERVA 77
17 #undef SPATII_GOALE
42
18 #define SPATII_GOALE 40
19
20 /* ---
21 macrouri debugging:
22 ---*/
23 #undef DEBUG
24 #define DEBUG 1
25 /* #undef DEBUG */
26 #undef EROARE_A
27 #define EROARE_A (text) \
28 pr int f s (text); \
29 exit (EXIT FAILURE);
30 #undef EROARE
31 #define EROARE(text ,pointer) \
32 pr int f s (text); \
33 f ree ((void *) pointer); \
34 pointer = NULL; \
35 exit (EXIT FAILURE);
36 #undef SUCCES
37 #define SUCCES(pointer) \
38 LA_REVEDERE \
39 f ree ((void *) pointer); \
40 pointer = NULL; \
41 exit (EXIT SUCCESS);
42
43 #include "headerulnostru.h"
44
45 void main( int argc , char *argv[])
46 {
47 char *comanda_baza = "\"C:\\ Program Files\\ Mozilla ց
(cont.) Firefox \\firefox.exe\" http:// dexonline.ro/",
48 *supliment = "definitie/",
49 *buffer = NULL,
50 *citirea_cuvantului = "standard ";
51 int contor = 0,
52 iterator = 0;
53
54 i f (
55 COMANDA_MAXIMA <= (COMANDA_REZERVA + SPATII_GOALE)
56 ){
57 #i fd e f DEBUG
58 EROARE_A("\nEroare setari!")
59 #else
43
60 EROARE_A(" ")
61 #endif
62 }
63
64 /*---
65 rezervam memorie pentru linia de comanda "buffer":
66 ---*/
67 i f (
68 (buffer = (char *) ca l l oc (COMANDA_MAXIMA , s i z eo f (char)))
69 == NULL
70 ){
71 #i fd e f DEBUG
72 EROARE_A("\nEroare memorie!")
73 #else
74 EROARE_A(" ")
75 #endif
76 }
77
78 /*---
79 organizarea liniei de comanda:
80 ---*/
81 for (;* comanda_baza != ’\0’;){
82 buffer[contor++] = *comanda_baza++;
83 }
84 #i fd e f DEBUG
85 pr int f s ("contor 1: %d\n",contor);
86 #endif
87
88 for (;* supliment != ’\0’;){
89 buffer[contor++] = *supliment++;
90 }
91 #i fd e f DEBUG
92 pr int f s ("contor 2: %d |%c|\n",
93 contor ,buffer[contor -1]);
94 #endif
95 i f (COMANDA_REZERVA != contor){
96 #i fd e f DEBUG
97 EROARE("\nProbleme de iterare ...",buffer)
98 #else
99 EROARE(" ",buffer)
100 #endif
101 }
102
44
103 /*---
104 adaugam SPATII_GOALE spatii goale...
105 aici va fi copiat cuvantul ce trebuie
106 cautat in dictionar
107 ---*/
108 for (; iterator <= SPATII_GOALE -1; iterator ++){
109 buffer[contor++] = ’ ’;
110 }
111 buffer[contor] = ’\0’;
112 #i fd e f DEBUG
113 pr int f s ("contor 3: %d %d |%c|\n",
114 contor ,iterator ,buffer[contor -1]);
115 #endif
116
117 /*---
118 linia de comanda poate primi argumentul optional
119 ---*/
120 i f (argc == 1){
121 /* ---
122 in lipsa unui cuvant in linia de comanda (default),
123 cautam cuvantul "standard ":
124 ---*/
125 for (contor = 0; contor <= countof("standard ");){
126 buffer[COMANDA_REZERVA + contor ++]
127 = *citirea_cuvantului++;
128 }
129 i f (
130 pr int f s ("\nAdresa standard :\n%s\n",buffer) < 0
131 ){
132 #i fd e f DEBUG
133 EROARE("\nNu pot afisa adresa standard ...",buffer)
134 #else
135 EROARE(" ",buffer)
136 #endif
137 }
138 system(buffer);
139 SUCCES(buffer)
140 }
141 /*---
142 citesc cuvantul :
143 ---*/
144 citirea_cuvantului = argv[1];
145 for (contor = 0;* citirea_cuvantului != ’\0’;){
45
146 buffer[COMANDA_REZERVA + contor ++]
147 = *citirea_cuvantului++;
148 }
149 i f ( pr int f s ("\nAdresa :\n%s\n",buffer) < 0){
150 #i fd e f DEBUG
151 EROARE("\nNu pot afisa adresa ...",buffer)
152 #else
153 EROARE(" ",buffer)
154 #endif
155 }
156 system(buffer);
157 SUCCES(buffer)
158 }
Program:> Tratarea erorilor 9 este o parte importanta a oricarui proiect VS, [20, p.164]. Lasand la o parte chestiunea dificila a ıntreruperilor hardware care potsurveni pe parcursul executiei codului C, vezi [37], ın programul de mai josfolosim functiile signal si raise din <signal.h> pentru a organiza iesireadin ıntrerupere, reluarea executiei. Aici, vom activa valoarea SIGILL, [20, p.255], a semnalului de ıntrerupere emis de sistemul de operare — neutilizatade Windows — pentru a ıncalca recomandarea MSDN [38] de a nu folosifunctii de tip printf atunci cand nu cunoastem starea10 operatiei run-time.
Intreruperi: eh00.c
1 #include <conio.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <signal.h> /* semnalarea erorii*/
5
6 void main(){
7 int numar = SIGILL,
8 /*---
9 codul erorii: instructiune ilegala
10 ---*/
11 caracter = 0;
12 void actiune( int );
13 /*---
14 handlerul erorii;
15 va fi apelat in cazul producerii erorii ...
16 ---*/
17
9In limba engleza, error handling.10Cf. [20, p. 244], intructiunea printf(...) este echivalenta cu fprintf(stdout,...).
46
18 pr int f s ("\nSalut!\n"
19 "Pentru a incheia , tastati ’x ’:\t");
20 while(( caracter = getch()) != ’x’){
21 s igna l (numar ,actiune);
22 /*---
23 semnalarea erorii:
24 daca se produce , atunci va fi apelat handlerul;
25 acestuia i se va transmite parametrul numar...
26 ---*/
27 ra i se (numar); /* producerea erorii */
28 pr int f s ("\nReluati operatia !\n"
29 "Pentru a incheia , tastati ’x ’:\t");
30 }
31 exit (EXIT SUCCESS);
32 }
33 void actiune( int cod){
34 f p r in t f s ( stderr ,
35 "\nEroare ...\n"
36 "Codul erorii: %d\n"
37 "Cauza: nu ati tastat ’x ’...\n",
38 cod);
39 }
Program:> In proiectul VS de la pagina 34, am utilizat functia fputc din <stdio.h>
ca sa introducem un caracter ıntr-un fisier. Pentru a ne asigura ca “fluxulde date”11 (fisier deschis) exista, apelasem anterior functia fopen_s. In cazcontrar, functia fputc ar fi invocat un handler (o functie) pentru eroarea de“parametru invalid”. Acest “hamal” (handler) — reprezentat printr-un han-dle, adica un pointer la functie, [20, p. 118] — fie repara eroarea si continuaexecutia, fie va ıncheia executia programului, [35, p. 41; Chap. 1]. CodulC dat ın continuare prezinta un asemenea handler, care afiseaza un mesaj siopreste executia. Pentru a-l vedea “la lucru”, folositi — ca pana acum —optiunea Empty Project la initializarea noului proiect VS. Apoi, construitisolutia via Build\Batch Build...12 si selectati ın fereastra Batch Build,la rubrica Solution Config, varianta Release|Win32. Vezi si tehnica VEH,
cf. [35, p. 751; Chap. 25].
Intreruperi: eh01.c
1 #define UNICODE
2 #define _UNICODE
11 In limba engleza, stream, cf. [9, p. 81]. Vezi si [20, p. 241].12Cu optiunea Debug, veti vedea un Watson crash report (fereastra de depanare stan-
dard).
47
3 #include <conio.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <crtdbg.h>
7
8 void main(void){
9 FILE *fisier = NULL;
10 void handler_parametru_invalid(
11 const wchar t *,
12 const wchar t *,
13 const wchar t *,
14 unsigned int ,
15 uintptr t );
16 {
17 set invalid parameter handler (
18 handler_parametru_invalid
19 );
20 i f ( fputc(’D’,fisier))
21 exit (EXIT SUCCESS);
22 }
23 }
24
25 void handler_parametru_invalid(
26 const wchar t *expresia_care_produce_eroare ,
27 const wchar t *functie ,
28 const wchar t *fisier ,
29 unsigned int linie_de_cod ,
30 uintptr t rezervat ){
31 fwprintf s ( stderr ,
32 L"\nParametru invalid detectat la "
33 L"apelul functiei \" fputc\".\n"
34 L"Programul se incheie aici!\n");
35 abort();
36 }
Reamintesc ca, fiind ıntr-un sistem de operare Windows (unde resurselesunt virtualizate), apelul nereusit al functiei fputc va declansa, concomitentcu afisarea ıntr-o consola a mesajului din partea handlerului, o fereastrade dialog a JIT-ului (Just-In-Time Debugger) de la Visual Studio. . . Pre-supunand ca VS-ul este instalat pe calculatorul cu care testam programul.Altfel, ın Windows XP13, ın afara mesajului de consola, va aparea o fereastra
13 Inainte de a apasa de doua ori pe imaginea executabilului Nume_program.exe, inseratiın C:\WINDOWS\system32 fisierul msvcr100.dll, copiat din calculatorul ın care ati “con-
48
cu textul Nume_program.exe has encountered a problem and needs to
close..., ın timp ce ın Windows 7 textul afisat ın fereastra va fi Nume_pro-
gram.exe has stopped working... In schimb, daca rulati programul eh01.exe din consola, raspunsul handlerului va aparea ın (aceeasi) consola.
Program:> Este util adesea sa dispunem de un program care sa introduca ıntr-unfisier o informatie exprimata printr-un sir de caractere, d.ex. un numar detelefon mobil ori un mesaj scurt (SMS), ımpreuna cu o minima ordonare(formatare), respectiv cu adaugarea timpului curent si a unei parole (chei).Acesta ar fi cel mai simplu model de baza de date, vezi [6, pg. 19, 24]. In modevident, rutinele din program pot fi realizate cu ajutorul functiei scanf_s din<stdio.h>. Proiectul VS care urmeaza este alcatuit din fisierele program.c,headerulnostru.h, macrouri.h si handlere.c.
Baza de date txt, cu timestamp si parola: program.c
1 /* ---
2 sintaxa: nume_program.exe xx.txt [parola]
3 aici , [] desemneaza un argument optional
4 ---*/
5
6 /* ---
7 Formatul bazei de date:
8 ===============================
9 ----inceput inregistrare ----
10 NMC | NCCE | continut
11 ----inceput preluare ----
12 Parola este: P/FP
13 ----sfarsit preluare ----
14 Info timp: TS
15 ----sfarsit inregistrare ----
16 ===============================
17 Aici ,
18 NMC: caracterul dat de hash -ul
19 (int)(nr. maxim de caractere * 0.01) + ’0’
20 NCCE: (int)(nr. de car. citite efectiv * 0.1) +’0’
21 P/FP: parola/Fara parola!
22 TS: timestamp
23 ---*/
24
25 /* ---
26 compilare cu optiunea Release;
27 altfel , nu uitati ca trebuie:
struit” — Batch Build — executabilul.
49
28 1) definit _DEBUG
29 2) inserat
30 _CrtSetReportMode(_CRT_ASSERT , 0);
31
32 Vezi:
33 http:// msdn.microsoft.com/en-us/library /1 y71x448.aspx
34 ---*/
35
36 /* ---
37 limitari :
38 + cand argc = 2:
39 - nu se testeaza daca introducem numele fisierului
40 sau parola;
41 - nu se parseaza nici numele fisierului nici parola;
42 - nu se aloca/elibereaza memorie pentru parola ,
43 presupunand ca este extrem de scurta;
44 + cand argc >= 3 ...
45 ---*/
46
47 #define UNICODE
48 #define _UNICODE
49
50 #undef LUNGIME_LINIE
51 #define LUNGIME_LINIE 500
52 #undef LUNGIME_MESAJ
53 #define LUNGIME_MESAJ 100
54 #undef FORMATE_MESAJ
55 #define FORMATE_MESAJ 4
56 #undef DATE_TIMP
57 #define DATE_TIMP 70
58
59 #include "headerulnostru.h"
60 #include "macrouri.h"
61 #include <time.h>
62
63 void main( int argc , char *argv[]){
64 /*---
65 handlere de eroare:
66 ---*/
67 extern void handler_pentru__cgets_s(
68 const wchar t *,
69 const wchar t *,
70 const wchar t *,
50
71 unsigned int ,
72 uintptr t );
73 extern void handler_pentru_ctime_s(
74 const wchar t *,
75 const wchar t *,
76 const wchar t *,
77 unsigned int ,
78 uintptr t );
79 extern void handler_pentru_fprintf_s(
80 const wchar t *,
81 const wchar t *,
82 const wchar t *,
83 unsigned int ,
84 uintptr t );
85 extern void handler_pentru_fputs(
86 const wchar t *,
87 const wchar t *,
88 const wchar t *,
89 unsigned int ,
90 uintptr t );
91 extern void handler_pentru_fclose(
92 const wchar t *,
93 const wchar t *,
94 const wchar t *,
95 unsigned int ,
96 uintptr t );
97 extern void handler_pentru_fopen_s(
98 const wchar t *,
99 const wchar t *,
100 const wchar t *,
101 unsigned int ,
102 uintptr t );
103
104 /*---
105 stream -ul de lucru:
106 ---*/
107 FILE *fisier = NULL;
108 /*---
109 linie: bufferul inregistrarii (continut )
110 mesaj: bufferul mesajului (P/FP)
111 contor_parola: cu/fara cheie
112 alt_contor: iterator
113 ---*/
51
114 char *linie = NULL,
115 *mesaj = NULL;
116 int contor_parola = 0,
117 alt_contor = 0;
118
119 /*---
120 datele functiilor "_s":
121 ---*/
122 s i z e t numar_standard = LUNGIME_MESAJ;
123 s i z e t *numar_caractere_citite = &numar_standard;
124 time t timp_curent = ( int64 ) 0;
125 char *buffer_timp = NULL;
126
127 i f (
128 (LUNGIME_LINIE <= 2 * (LUNGIME_MESAJ + FORMATE_MESAJ
129 + DATE_TIMP + 2))
130 && (FORMATE_MESAJ < 4) && (DATE_TIMP <= 26)
131 /* ---
132 pentru "nr. magic" 26 vezi:
133 http:// msdn.microsoft.com/en-us/library /4 ey61ayt.aspx
134 ---*/
135 ){
136 #i fd e f DEBUG
137 EROARE_A("Defecte de setare!")
138 #else
139 EROARE_A(" ")
140 #endif
141 }
142
143 /*---
144 rezervarea memoriei : linie , timestamp
145 ---*/
146 i f (
147 (linie = (char *) ca l l oc (LUNGIME_LINIE , s i z eo f (char)))
148 == NULL
149 ){
150 #i fd e f DEBUG
151 EROARE_A("\nEroare memorie linie!")
152 #else
153 EROARE_A(" ")
154 #endif
155 }
156 i f (
52
157 (buffer_timp = (char *) ca l l oc (DATE_TIMP , s i z eo f (char)))
158 == NULL
159 ){
160 #i fd e f DEBUG
161 EROARE("\nEroare memorie timp!",linie)
162 #else
163 EROARE(" ",linie)
164 #endif
165 }
166
167 /*---
168 analizam linia de comanda:
169 ---*/
170
171 i f (argc == 1){
172 #i fd e f DEBUG
173 EROARE("\nLipsesc fisierul si parola!\n",linie)
174 EROARE(" ",buffer_timp)
175 #else
176 EROARE(" ",linie)
177 EROARE(" ",buffer_timp)
178 #endif
179 }
180 i f (argc == 2){
181 #i fd e f DEBUG
182 pr int f s ("\nLipseste parola!\n");
183 #endif
184 mesaj = "Fara parola!";
185 contor_parola = 1;
186 }
187
188 /*---
189 ne conectam la baza:
190 ---*/
191 {/* incep bloc instructiuni "fopen_s ":
192 doar aici instalez handler -ul
193 de eroare pt. fopen_s ...
194 */
195 set invalid parameter handler (
196 handler_pentru_fopen_s
197 );
198 i f (
199 fopen s (&fisier ,argv[1],"a+") != 0
53
200 ){
201 /* ---
202 daca am ajuns aici , am revenit din eroare;
203 aceasta pt. ca handler -ul doar a afisat
204 un mesaj...
205 o valoare nenula returnata de fopen_s este
206 un cod de eroare;
207 ---*/
208 #i fd e f DEBUG
209 EROARE("Eroare la deschiderea fisierului!",
210 linie)
211 EROARE(" ",buffer_timp)
212 #else
213 EROARE(" ",linie)
214 EROARE(" ",buffer_timp)
215 #endif
216 }
217 }/* final bloc instructiuni "fopen_s" */
218
219 pr int f s ("\nTastati n <= 100 caractere"
220 "\nsi apoi apasati ENTER:\n\n");
221
222 /*---
223 citirea intrarii si a timpului :
224 ---*/
225 {/*incep bloc intructiuni "_cgets_s " */
226 set invalid parameter handler (
227 handler_pentru__cgets_s
228 );
229 cget s s (linie ,
230 LUNGIME_MESAJ + 1,
231 numar_caractere_citite);
232 }/*final bloc intructiuni "_cgets_s " */
233
234 i f (time(& timp_curent) == -1){
235 #i fd e f DEBUG
236 EROARE("Eroare la citirea timpului !",
237 linie)
238 EROARE(" ",buffer_timp)
239 #else
240 EROARE(" ",linie)
241 EROARE(" ",buffer_timp)
242 #endif
54
243 }
244
245 {/*incep bloc intructiuni "ctime_s" */
246 set invalid parameter handler (
247 handler_pentru_ctime_s
248 );
249 i f (
250 ctime s(buffer_timp ,DATE_TIMP * s i z eo f (char),
251 &timp_curent) != 0
252 ){
253 #i fd e f DEBUG
254 EROARE("Eroare la structurarea timpului!",
255 linie)
256 EROARE(" ",buffer_timp)
257 #else
258 EROARE(" ",linie)
259 EROARE(" ",buffer_timp)
260 #endif
261 }
262 }/*final bloc intructiuni "ctime_s" */
263
264 /*---
265 formatam linia:
266 1) mutam textul la dreapta cu patru pozitii
267 2) inseram "NMC|NCCE|"
268 ---*/
269
270 for (alt_contor = ( int ) (* numar_caractere_citite) - 1;
271 alt_contor >= 0;
272 linie[alt_contor + 4] = linie[alt_contor --]
273 );
274
275 /*---hash -uri:---*/
276 linie[0] = (char) (( int )(LUNGIME_LINIE * 0.01) + ’0’);
277 linie[1] = ’|’;
278 linie[2] = (char) (( int )(( int ) (* numar_caractere_cititeց
(cont.) ) * 0.1) + ’0’);
279 linie[3] = ’|’;
280
281 /*---
282 incarcam inregistrarea:
283 ---*/
284
55
285 {/*inceput bloc instructiuni cu "fprintf_s" */
286 set invalid parameter handler (
287 handler_pentru_fprintf_s
288 );
289 i f (
290 f p r in t f s (fisier ,
291 "\n----inceput inregistrare ----\n") < 0
292 ){
293 #i fd e f DEBUG
294 EROARE("Eroare la inserarea "
295 "antetului inregistrarii!",
296 linie)
297 EROARE(" ",buffer_timp)
298 #else
299 EROARE(" ",linie)
300 EROARE(" ",buffer_timp)
301 #endif
302 }
303
304 }/* final bloc instructiuni cu "fprintf_s" */
305
306 { /* aplicam "fputs" pentru linie: */
307 set invalid parameter handler (handler_pentru_fputs);
308 i f ( fputs (linie ,fisier) == EOF){
309 #i fd e f DEBUG
310 EROARE("Eroare la inserarea liniei!",
311 linie)
312 EROARE(" ",buffer_timp)
313 #else
314 EROARE(" ",linie)
315 EROARE(" ",buffer_timp)
316 #endif
317 }
318 } /* final "fputs" */
319
320 /* aplicam "fflush": */
321 i f ( f f lu sh (fisier) == EOF){
322 #i fd e f DEBUG
323 EROARE("Eroare la flush -ul liniei!",
324 linie)
325 EROARE(" ",buffer_timp)
326 #else
327 EROARE(" ",linie)
56
328 EROARE(" ",buffer_timp)
329 #endif
330 }/* final "fflush" */
331
332 { /*inceput bloc instructiuni cu "fprintf_s" */
333 set invalid parameter handler (
334 handler_pentru_fprintf_s
335 );
336 i f (
337 f p r in t f s (fisier ,"\n----inceput preluare ----\n") < 0
338 ){
339 #i fd e f DEBUG
340 EROARE("Eroare la inserarea "
341 "antetului preluarii!",
342 linie)
343 EROARE(" ",buffer_timp)
344 #else
345 EROARE(" ",linie)
346 EROARE(" ",buffer_timp)
347 #endif
348 }
349 }/* final bloc instructiuni cu "fprintf_s" */
350
351 i f (contor_parola == 0){
352 { /*inceput bloc instructiuni cu "fprintf_s" */
353 set invalid parameter handler (
354 handler_pentru_fprintf_s
355 );
356 i f (
357 f p r in t f s (fisier ,"Parola este:\t") < 0
358 ){
359 #i fd e f DEBUG
360 EROARE("Eroare la inserarea "
361 "mesajului parolei!",
362 linie)
363 EROARE(" ",buffer_timp)
364 #else
365 EROARE(" ",linie)
366 EROARE(" ",buffer_timp)
367 #endif
368 }
369 }/* final bloc instructiuni cu "fprintf_s" */
370
57
371 { /* aplicam "fputs" pentru parola: */
372 set invalid parameter handler (handler_pentru_fputs);
373 i f ( fputs (argv[2],fisier) == EOF){
374 #i fd e f DEBUG
375 EROARE("Eroare la inserarea parolei!",
376 linie)
377 EROARE(" ",buffer_timp)
378 #else
379 EROARE(" ",linie)
380 EROARE(" ",buffer_timp)
381 #endif
382 }
383 }/* final "fputs" */
384
385 /* aplicam "fflush": */
386 i f ( f f lu sh (fisier) == EOF){
387 #i fd e f DEBUG
388 EROARE("Eroare la flush -ul parolei!",
389 linie)
390 EROARE(" ",buffer_timp)
391 #else
392 EROARE(" ",linie)
393 EROARE(" ",buffer_timp)
394 #endif
395 }/* final "fflush" */
396 }
397 e l se {/* ---
398 daca sunt aici ,
399 nu am dat o parola...
400 ---*/
401 { /*inceput bloc instructiuni cu "fprintf_s" */
402 set invalid parameter handler (
403 handler_pentru_fprintf_s
404 );
405 i f ( f p r in t f s (fisier ,mesaj) < 0){
406 #i fd e f DEBUG
407 EROARE("Eroare la inserarea "
408 "mesajului de lipsa "
409 "a parolei!",
410 linie)
411 EROARE(" ",buffer_timp)
412 #else
413 EROARE(" ",linie)
58
414 EROARE(" ",buffer_timp)
415 #endif
416 }
417 }/* final bloc instructiuni cu "fprintf_s" */
418 } /* final bloc "else" */
419
420 { /*inceput bloc instructiuni cu "fprintf_s" */
421 set invalid parameter handler (
422 handler_pentru_fprintf_s
423 );
424 i f (
425 f p r in t f s (fisier ,
426 "\n----sfarsit preluare ----\n"
427 "Info timp:\t") < 0
428 ){
429 #i fd e f DEBUG
430 EROARE("Eroare la inserarea "
431 "mesajului de final "
432 "pentru preluare !",
433 linie)
434 EROARE(" ",buffer_timp)
435 #else
436 EROARE(" ",linie)
437 EROARE(" ",buffer_timp)
438 #endif
439 }
440 i f (
441 f p r in t f s (fisier ,buffer_timp) < 0
442 ){
443 #i fd e f DEBUG
444 EROARE("Eroare la inserarea timpului!",
445 linie)
446 EROARE(" ",buffer_timp)
447 #else
448 EROARE(" ",linie)
449 EROARE(" ",buffer_timp)
450 #endif
451 }
452 i f (
453 f p r in t f s (fisier ,
454 "----sfarsit inregistrare ----\n\n") < 0
455 ){
456 #i fd e f DEBUG
59
457 EROARE("Eroare la inserarea "
458 "mesajului de final "
459 "pentru inregistrare!",
460 linie)
461 EROARE(" ",buffer_timp)
462 #else
463 EROARE(" ",linie)
464 EROARE(" ",buffer_timp)
465 #endif
466 }
467 }/*sfarsit bloc instructiuni cu "fprintf_s" */
468
469 /*---
470 deconectam baza:
471 ----*/
472
473 {/*inceput bloc instructiuni cu "fclose" */
474 set invalid parameter handler (
475 handler_pentru_fclose
476 );
477 i f ( f c l o s e (fisier) == EOF){
478 #i fd e f DEBUG
479 EROARE("Eroare la inchiderea streamului...!",
480 linie)
481 EROARE(" ",buffer_timp)
482 #else
483 EROARE(" ",linie)
484 EROARE(" ",buffer_timp)
485 #endif
486 }
487 }/*sfarsit bloc instructiuni cu "fclose" */
488
489 SUCCES(linie ,buffer_timp)
490 }
Baza de date txt, cu timestamp si parola: macrouri.h
1 #i f !defined ( MACROURI )
2 #define MACROURI
3 /* ---------------------*/
4
5 /* ---
6 macrouri debugging:
7 ---*/
60
8 #undef DEBUG
9 #define DEBUG 1
10 /* #undef DEBUG */
11 #undef EROARE_A
12 #define EROARE_A (text) \
13 pr int f s (text); \
14 exit (EXIT FAILURE);
15 #undef EROARE
16 #define EROARE(text ,pointer) \
17 pr int f s (text); \
18 f ree ((void *) pointer); \
19 pointer = NULL; \
20 exit (EXIT FAILURE);
21 #undef SUCCES
22 #define SUCCES(pointer_a ,pointer_b) \
23 LA_REVEDERE \
24 f ree ((void *) pointer_a); \
25 pointer_a = NULL; \
26 f ree ((void *) pointer_b); \
27 pointer_b = NULL; \
28 exit (EXIT SUCCESS);
29
30 /* ---------------------*/
31 #endif
Baza de date txt, cu timestamp si parola: handlere.c
1 #include "headerulnostru.h"
2
3 void handler_pentru__cgets_s(
4 const wchar t *expresia_care_produce_eroare ,
5 const wchar t *functie ,
6 const wchar t *fisier ,
7 unsigned int linie_de_cod ,
8 uintptr t rezervat ){
9 fwprintf s ( stderr ,
10 L"\nParametru invalid detectat la "
11 L"apelul functiei \"_cgets_s \".\n");
12 }
13 void handler_pentru_ctime_s(
14 const wchar t *expresia_care_produce_eroare ,
15 const wchar t *functie ,
16 const wchar t *fisier ,
17 unsigned int linie_de_cod ,
61
18 uintptr t rezervat ){
19 fwprintf s ( stderr ,
20 L"\nParametru invalid detectat la "
21 L"apelul functiei \"ctime_s \".\n");
22 }
23 void handler_pentru_fprintf_s(
24 const wchar t *expresia_care_produce_eroare ,
25 const wchar t *functie ,
26 const wchar t *fisier ,
27 unsigned int linie_de_cod ,
28 uintptr t rezervat ){
29 fwprintf s ( stderr ,
30 L"\nParametru invalid detectat la "
31 L"apelul functiei \" fprintf_s\".\n");
32 }
33 void handler_pentru_fputs(
34 const wchar t *expresia_care_produce_eroare ,
35 const wchar t *functie ,
36 const wchar t *fisier ,
37 unsigned int linie_de_cod ,
38 uintptr t rezervat ){
39 fwprintf s ( stderr ,
40 L"\nParametru invalid detectat la "
41 L"apelul functiei \"fputs\".\n");
42 }
43 void handler_pentru_fclose(
44 const wchar t *expresia_care_produce_eroare ,
45 const wchar t *functie ,
46 const wchar t *fisier ,
47 unsigned int linie_de_cod ,
48 uintptr t rezervat ){
49 fwprintf s ( stderr ,
50 L"\nParametru invalid detectat la "
51 L"apelul functiei \"fclose \".\n");
52 }
53 void handler_pentru_fopen_s(
54 const wchar t *expresia_care_produce_eroare ,
55 const wchar t *functie ,
56 const wchar t *fisier ,
57 unsigned int linie_de_cod ,
58 uintptr t rezervat ){
59 fwprintf s ( stderr ,
60 L"\nParametru invalid detectat la "
62
61 L"apelul functiei \"fopen_s \".\n");
62 }
Program:> Urmatorul program studiaza aparitiile unui caracter ıntr-un sir de carac-tere, folosind aritmetica pointerilor (adreselor), vezi [20, p. 100]. Ar puteafi utilizat la parsarea numelor de fisiere din proiectul anterior — cautamcaracterul “.” din sirul “nume_fisier.txt” —.
Numarator de caractere: caract0x.c
1 #include "headerulnostru.h"
2 #include <string.h>
3
4 #undef LUNGIME
5 #define LUNGIME 100
6
7 void main(void){
8 int pozitie = 1,
9 contor = 0;
10 s i z e t inregistrare = 0;
11 char caracter = ’e’,
12 *pointerul /* adresele caracterelor*/,
13 sirul[] = "E acesta un sir feeric cu date , ei?";
14
15 pointerul = sirul;
16 pr int f s ("\nIncepe scanarea ...\n");
17 for (;* pointerul != ’\0’;pozitie ++)
18 i f (* pointerul++ == caracter ){
19 contor ++;
20 pr int f s ("Pozitia: %d\n",pozitie);
21 }
22
23 inregistrare = strn len s (sirul ,LUNGIME);
24
25 pr int f s ("Scanare terminata.\n"
26 "Nr. de aparitii : %d\n"
27 "Lungimea sirului: %d\n",
28 contor ,
29 inregistrare
30 = (inregistrare == LUNGIME) ? -1 : inregistrare
31 );
32
33 LA_REVEDERE
34 exit (EXIT SUCCESS);
35 }
63
4 Programare ın C++
Limbajul C++ a fost inventat de profesorul Bjarne Stroustrup de la Uni-versitatea A&M Texas si este descris ın cartea [41]. Limbajul a fost denumitla ınceput si C cu clase, vezi [40], [41, p. 10].
Un draft al standardului pentru limbajul C++ se gaseste la adresa [39].Program:> Primul program scris ın C++ trebuie, fireste, sa salute lumea. Cum limbajul
C++ extinde limbajul C, suntem, practic, acasa. De aceea, vom putea folosiın cadrul sau functia printf din biblioteca C standard <stdio.h>. Intr-un proiect VS gol, introducem fisierele centru.cpp, headerulnostru.h siajutor.cpp de mai jos.
“Salut, prieteni!”: centru.cpp
1 #include "headerulnostru.h"
2
3 int main(){
4
5 std:: pr int f ("\nSalut , prieteni !\n");
6 afisare("Suntem la laboratorul: %d\n" ,2);
7 afisare("Maine , venim la laboratorul: %d\n" ,3);
8
9 incheiere();
10 return 0;
11 }
“Salut, prieteni!”: headerulnostru.h
1 #ifndef _HEADERULNOSTRU_
2 #define _HEADERULNOSTRU_
3 /* ------------------*/
4
5 // headere C++:
6 #include <cstdio >
7 #include <cstdlib >
8
9 // headere C:
10 #include <conio.h>
11
12 int afisare(const char*, int );
13 int incheiere();
14
15 /* ------------------*/
16 #endif
64
“Salut, prieteni!”: ajutor.cpp
1 #include "headerulnostru.h"
2 #include <cstring >
3
4 int afisare(const char *mesaj , int numar){
5 s t a t i c int lungime = 200;
6 i f (
7 std:: str len (mesaj) >= s ta t i c cas t < s i ze t >(lungime)
8 ){
9 std:: pr int f ("\nMesaj prea lung...\n");
10 return -1;
11 }
12 return std:: pr int f (mesaj ,numar /*+ (lungime ++)*/);
13 }
14
15 int incheiere(){
16 std:: pr int f ("\nTastati o litera pentru a incheia: ");
17 return getch();
18 }
Observam prefixul std al functiei printf. Pentru a-l explica, mentionezca biblioteca C++ standard preia fisierele <nume.h> ale bibliotecii C standardsub forma <cnume>, cf. [41, p. 202]. In aceste fisiere se foloseste un mecanismC++ denumit nume de spatiu14, [41, pg. 167, 176], pentru a evita conflictelede nume15 care apar atunci cand, fara sa stie, programatori diferiti folosescacelasi nume pentru a desemna marimi diferite. Precizand — prin numele despatiu — spatiul (zona din program16) unde numele marimii respective (vari-abila, functie) este valabil, problema se rezolva eficient. In fisierul <cstdio>,numele de spatiu ın care se gaseste functia C printf este std (standard).Pentru a atesta apartenenta unui nume la un nume de spatiu se foloste oper-atorul de spatiu17 “::”, vezi [41, p. 82]. Expresiile nume_de_spatiu::nume
constituie nume complete18 ale marimilor.Cuvantul cheie static, [41, pg. 145, 200, 819], trebuie folosit doar ın
codul de implementare al functiilor19, e.g., afisare. El cere ca variabila ıncauza sa fie initializata o singura data — la primul apel al functiei —, indifer-
14 In limba engleza, namespace, cf. [18, p. 867].15 In limba engleza, name clashes .16 In limba engleza, scope, vezi [41, p. 168]. Se foloseste si sintagma domeniu de valabi-
litate, adica zona din program ın care marimea este activa, cf. [23, pg. 48, 49].17 In limba engleza, scope resolution operator .18 In limba engleza, fully qualified names , cf. [42, p. 291].19Si al claselor. . . Vezi si [41, p. 819, Section B.2.3].
65
ent de cate ori va fi apelata aceasta. Daca activati expresia + (lungime++)
din codul functiei afisare, veti observa ca programul “tine minte” valoarealungime ıntre apeluri consecutive.
Mai departe, remarcam ca functia strlen returneaza valori de tip size_t,adica unsigned int. Pentru a face comparatia cu marimea lungime, trebuierealizata o conversie explicita de tip (cast). Codul C (size_t) lungime estereorganizat ın C++ via operatorul static_cast<nume_tip>, cf. [41, p. 130].
La pornirea unui program C++, sistemul de operare ıi va atasa o seriede fluxuri de date, intitulate std::cout, std::cin, std::cerr, std::clog,etc20. Elementele (functii, date) necesare utilizarii acestora se gasesc ın fi-sierele antet <iostream> si <iomanip> — sau <iostream.h>, <iomanip.h>cf. [18, p. 718, Sect. 980] —. Lucrand ın consola, sunt mai usor de retinuturmatoarele “traduceri” ale denumirilor acestor fluxuri de intrare–iesire: cin(console–in, citire), cout (console–out21, scriere), cerr (console–error, erori,fara buffer) si clog (console–log, erori, cu buffer), vezi si [18, p. 598, Sect.817]. Practic, reamintindu-ne fluxurile din limbajul C, vezi pagina 28, coutse refera la stdout, cin la stdin, iar cerr si clog la stderr, vezi [41, p.637].
Program:> Putem lucra cu fluxurile de intrare–iesiere la fel ca ıntr-un program C,utilizand omoloage ale functiilor din libraria standard getchar si puts, cf.[20, p. 247].
Afisand un caracter. . . : ajutor.cpp
1 #include <iostream >
2 #include <iomanip >
3 #include <conio.h>
4
5 using namespace std;
6 // evitam scrierea prefixului "std::"
7
8 int main(){
9 char litera = ’\n’;
10 litera = cin.get();
11 cout.put(litera);
12 getch();
13 return 0;
14 }
20Lor li se adauga stream-urile pentru caractere multi-byte, vezi [41, p. 609].21 In realitate, prof. Stroustrup abreviaza cu cout expresia “character output stream”,
cf. [42, p. 45, Sect. 2.2].
66
Limbajul C++ ofera ınsa o alternativa performanta a comunicarii I/O prinfunctii via notiunea de operatori , ca e.g., ın urmatoarea situatie familiara:
a+ b ınseamna + (a, b)
Program:> Operatorul pentru fluxurile–de–iesire cout, cerr si clog este “<<”, iarpentru cin avem “>>”. In programul urmator, folosim manipulatorii22 —setprecision, scientific, fixed din numele de spatiu std — ca sa schim-bam modul de afisare al unor date numerice.
Precizia ın C++: unu.cpp
1 #include <iostream >
2 #include <iomanip > //pt. manipulatorul setprecision
3 #include <conio.h>
4 int main()
5 {
6 double valoare = 1.345;
7 system("cls");
8 std::cout << std:: setprec i s ion (0)//vedem tot numarul
9 << valoare << std::endl;
10 std::cout << std:: setprec i s ion (2)
11 << valoare << std::endl;
12 std::cout << std:: s c i e n t i f i c << std:: setprec i s ion (2)
13 << valoare << std::endl;
14 std::cout << std:: f ixed << std:: setprec i s ion (4)
15 << valoare << std::endl
16 << 23.4567891 << " " << -12.54
17 << std:: setprec i s ion (12)
18 << " alta precizie! "
19 << 0.88 << std::endl;
20 getch();
21 return 0;
22 }
Program:> Cum numeroase programe C++ manipuleaza date numerice, este conven-abil sa dispunem de cel putin o “functie de format” personalizata, care saafiseze pe ecran ori sa scrie ıntr-un fisier rezultatele calculelor noastre ınurma unei simple apelari! Proiectul Visual Studio listat ın continuare oferaun astfel de mecanism de formatare si este compus din fisierele program.cpp,headerulnostru.h, format_afisare.h si format_afisare.cpp. Fara a nepreocupa de semnificatia anumitor instructiuni C++, putem folosi mecanis-mul ca ın fisierul program.cpp — pana acum am manevrat cu succes functia
22 In fapt, niste functii, apelate de operator printr-un pointer la functie, cf. [41, p. 631].Manipulatorii se gasesc ın <iomanip>, <ios>.
67
MessageBox, fara sa tinem seama de ceea ce este un callback, cf. [41, p.650] si [18, pg. 1013, 1014] —.
O functie de format: program.cpp
1 #include "headerulnostru.h"
2 #include "format_afisare.h"
3 #include <iostream >
4 #include <iomanip >
5
6 using namespace octavian ;
7
8 int main(){
9
10 /* ---
11 Explicatii:
12 (+): aplicam la sfarsit "formatul ",
13 el modifica afisarea pentru intreg randul ,
14 adica pana la ";"...;
15 (++): aplicand la inceput "formatul ", el ramane
16 valabil si pe randurile urmatoare;
17 (+++): modificator de precizie ; numai unul pe rand ,
18 spre deosebire de cazul clasic ...;
19 (++++): revenim la formatul standard ...
20 ---*/
21
22 std::cout
23 << 2.00 << " "
24 << 3.12345678901234 << " " << 4.12345678901234 << " "
25 << 5.12345678901234 << " " << 6.12345678901234 << " "
26 << 7.12345678901234 << " " << 8.12345678901234 << " "
27 << 9.12345678901234 << " " << 10.12345678901234
28 << " "
29 << Afisare (& std::cout ,2)//(+)
30 << std::endl;
31 std::cout << 2.00 << std::endl;
32 {
33 Afisare afis(& std::cout ,9);
34 std::cout << 2.00 << " "
35 << 3.12345678901234 << " " << 4.12345678901234
36 << " "
37 << 5.12345678901234 << " " << 6.12345678901234
38 << " " << std::endl;
39 std::cout <<3.00 << std::endl;//(++)
68
40 }
41 std::cout << 4.00 << std::endl;
42 {
43 Afisare afis(& std::cout ,7);
44 std::cout << 2.00 << " "
45 << 3.12345678901234 << " " << 4.12345678901234
46 << " "
47 << afis(5)//(+++)
48 << 5.12345678901234 << " " << 6.12345678901234
49 << " "
50 << std::endl;
51 std::cout << 5.00 << std::endl;
52 }
53 std::cout << 6.00 << std::endl;// (++++)
54
55 LA_REVEDERE
56 return 0;
57 }
O functie de format: format_afisare.h
1 /* ---
2 Copyright: Octavian , 2011 - -2014
3 ---*/
4 #ifndef _FORMAT_AFISARE_
5 #define _FORMAT_AFISARE_
6
7 #include <cstdio >
8 #include <iostream >
9
10 namespace octavian{
11 typedef unsigned int numar;
12 typedef std:: streamsize lungime;
13 typedef std::ostream iesire;
14 typedef std:: ios base :: fmtflags date_fanioane;
15
16 enum tip_flux {flux_cout , flux_cerr};
17
18 c la s s Santinela{
19 tip_flux fel_flux;
20
21 //date "cout":
22 /*
23 explicatie:
69
24 - afisat_contor_flux_cout: afisarea numarului
25 de "obiecte -format"
26 - flux_start_cout: adresa stream -ului utilizat
27 - fanioane_cout: flag -urile precedente ale
28 stream -ului utilizat
29 - precizie_arhiva_cout: precizia precedenta a
30 stream -ului utilizat
31 */
32 s t a t i c numar afisat_contor_flux_cout;
33 s t a t i c iesire* flux_start_cout;
34 s t a t i c numar contor_flux_start_cout;
35 s t a t i c date_fanioane fanioane_cout;
36 s t a t i c lungime precizie_arhiva_cout;
37
38 //date "cerr":
39 s t a t i c numar afisat_contor_flux_cerr;
40 s t a t i c iesire* flux_start_cerr;
41 s t a t i c numar contor_flux_start_cerr;
42 s t a t i c date_fanioane fanioane_cerr;
43 s t a t i c lungime precizie_arhiva_cerr;
44
45 public :
46 //citirea adresei stream -ului:
47 iesire* sentry_flux() const;
48 //citirea flag -urilor:
49 date_fanioane sentry_flux_flaguri() const;
50 //citirea preciziei:
51 lungime sentry_flux_precizie() const ;
52 //periculoase --->
53 /* ---
54 explicatie:
55 Datele statice din clasa "sentry" -- Santinela sunt ,
56 defapt , marimi globale private. Uneori , trebuie sa
57 le citesc/modific fara a avea la indemana un obiect
58 Santinela... Aici intervin
59 functiile -membru statice (publice)!
60 ---*/
61 s t a t i c iesire* sentry_flux_stat(numar);
62 s t a t i c date_fanioane sentry_flux_flaguri_stat(numar);
63 s t a t i c lungime sentry_flux_precizie_stat(numar);
64 s t a t i c numar afisat_cititor(numar);
65 s t a t i c void afisat_resetor(numar);
66 s t a t i c numar contor_flux_cititor(numar);
70
67 //<--- periculoase
68 // constructor predefinit la "cout":
69 exp l i c i t Santinela(
70 numar ffel_flux = s ta t i c cas t <numar >(1)
71 );
72 //pt. initializare directa ca sub -obiect ...
73 exp l i c i t Santinela(iesire* fflux);
74 Santinela(const Santinela&);
75 Santinela operator=( const Santinela&);
76 ~Santinela();
77 };
78
79 c la s s Afisare{
80 fr iend iesire;
81 fr iend iesire& operator <<(iesire&,Afisare&);
82 Santinela sentry_afisare;
83 tip_flux flux_duplicat;
84 numar precizie ;
85 date_fanioane optiunea_mea;
86 public :
87 // predefinit la "cout":
88 exp l i c i t Afisare( int pprecizie = 3);
89 exp l i c i t Afisare(iesire*, int pprecizie = 3);
90 Afisare(const Afisare &);
91 Afisare operator=( const Afisare &);
92 Afisare& operator()( int );
93 ~Afisare();
94 };
95 }
96 #endif
O functie de format: format_afisare.cpp
1 /* ---
2 Copyright: Octavian , 2011 - -2014
3 ---*/
4 #include "headerulnostru.h"
5 #include "format_afisare.h"
6 #include <iomanip >
7
8 #undef VERIFICARE
9 #define VERIFICARE 1
10 //#undef VERIFICARE
11
71
12 // santinela fluxurilor...
13 //"cerr":
14 octavian ::iesire*
15 octavian :: Santinela::
16 flux_start_cerr = &std:: cerr;
17 octavian ::numar
18 octavian :: Santinela::
19 contor_flux_start_cerr = numar();
20 octavian ::numar
21 octavian :: Santinela::
22 afisat_contor_flux_cerr = numar();
23 octavian :: date_fanioane
24 octavian :: Santinela::
25 fanioane_cerr = (* flux_start_cerr)
26 . f l a g s ();
27 octavian ::lungime
28 octavian :: Santinela::
29 precizie_arhiva_cerr = (* flux_start_cerr)
30 .precis ion ();
31 //"cout":
32 octavian ::iesire*
33 octavian :: Santinela::
34 flux_start_cout = &std::cout;
35 octavian ::numar
36 octavian :: Santinela::
37 contor_flux_start_cout = numar();
38 octavian ::numar
39 octavian :: Santinela::
40 afisat_contor_flux_cout = numar();
41 octavian :: date_fanioane
42 octavian :: Santinela::
43 fanioane_cout = (* flux_start_cout)
44 . f l a g s ();
45 octavian ::lungime
46 octavian :: Santinela::
47 precizie_arhiva_cout = (* flux_start_cout)
48 .precis ion ();
49
50 octavian ::iesire*
51 octavian :: Santinela:: sentry_flux() const {
52 i f (fel_flux == flux_cout)
53 return flux_start_cout;
54 e l se
72
55 return flux_start_cerr;
56 }
57
58 octavian ::iesire*
59 octavian :: Santinela::
60 sentry_flux_stat(numar fls){
61 i f (fls == s ta t i c cas t <numar >(1))
62 return flux_start_cout;
63 e l se
64 return flux_start_cerr;
65 }
66
67 octavian :: date_fanioane
68 octavian :: Santinela::
69 sentry_flux_flaguri() const {
70 i f (fel_flux == flux_cout)
71 return fanioane_cout;
72 e l se
73 return fanioane_cerr;
74 }
75
76 octavian :: date_fanioane
77 octavian :: Santinela::
78 sentry_flux_flaguri_stat(numar fls){
79 i f (fls == s ta t i c cas t <numar >(1))
80 return fanioane_cout;
81 e l se
82 return fanioane_cerr;
83 }
84
85 octavian ::lungime
86 octavian :: Santinela::
87 sentry_flux_precizie() const {
88 i f (fel_flux == flux_cout)
89 return precizie_arhiva_cout;
90 e l se
91 return precizie_arhiva_cerr;
92 }
93
94 octavian ::lungime
95 octavian :: Santinela::
96 sentry_flux_precizie_stat(numar fls){
97 i f (fls == s ta t i c cas t <numar >(1))
73
98 return precizie_arhiva_cout;
99 e l se
100 return precizie_arhiva_cerr;
101 }
102
103 octavian ::numar
104 octavian :: Santinela::
105 afisat_cititor(numar nac){
106 i f (nac == s ta t i c cas t <numar >(1))
107 return afisat_contor_flux_cout;
108 e l se
109 return afisat_contor_flux_cerr;
110 }
111
112 void
113 octavian :: Santinela::
114 afisat_resetor(numar nar){
115 i f (nar == s ta t i c cas t <numar >(1))
116 afisat_contor_flux_cout = numar();
117 e l se
118 afisat_contor_flux_cerr = numar();
119 }
120
121 octavian ::numar
122 octavian :: Santinela::
123 contor_flux_cititor(numar ncfc){
124 i f (ncfc == s ta t i c cas t <numar >(1))
125 return contor_flux_start_cout;
126 e l se
127 return contor_flux_start_cerr;
128 }
129
130 octavian :: Santinela::
131 Santinela(numar ffel_flux)
132 {
133 i f (ffel_flux == s ta t i c cas t <numar >(1)){
134 fel_flux = flux_cout;
135 contor_flux_start_cout++;
136 }
137 e l se {
138 fel_flux = flux_cerr;
139 contor_flux_start_cerr++;
140 }
74
141 }
142
143 octavian :: Santinela::
144 Santinela(iesire* fflux){
145 i f (fflux == &std::cout){
146 fel_flux = flux_cout;
147 contor_flux_start_cout++;
148 }
149 e l se {
150 fel_flux = flux_cerr;
151 contor_flux_start_cerr++;
152 }
153 }
154
155 octavian :: Santinela::
156 Santinela(const Santinela& o_santinela){
157 i f (o_santinela.fel_flux == flux_cout){
158 fel_flux = flux_cout;
159 contor_flux_start_cout++;
160 }
161 e l se {
162 fel_flux = flux_cerr;
163 contor_flux_start_cerr++;
164 }
165 }
166
167 octavian :: Santinela
168 octavian :: Santinela::
169 operator=( const Santinela& o_santinela){
170 i f (o_santinela.fel_flux == flux_cout){
171 fel_flux = flux_cout;
172 contor_flux_start_cout++;
173 return * th is ;
174 }
175 e l se {
176 fel_flux = flux_cerr;
177 contor_flux_start_cerr++;
178 return * th is ;
179 }
180 }
181
182 octavian :: Santinela::
183 ~Santinela(){
75
184 i f (fel_flux == flux_cout){
185 /* ---
186 primul apel al destructorului va fi la
187 incheierea scope -ului ultimului obiect Afisare ...
188 atentie: nu putem crea obiecte Santinela decat in
189 constructorul obiectului Afisare!
190 ---*/
191 contor_flux_start_cout --;
192 afisat_contor_flux_cout++;
193 }
194 i f (fel_flux == flux_cerr){
195 contor_flux_start_cerr --;
196 afisat_contor_flux_cerr++;
197 }
198 }
199
200 octavian ::Afisare ::
201 Afisare( int pprecizie) :
202 precizie ( s ta t i c cas t <numar >( pprecizie)),
203 flux_duplicat(flux_cout),
204 sentry_afisare(Santinela(& std::cout ))
205 {
206 optiunea_mea = std:: ios base ::dec
207 | std:: ios base :: f ixed
208 | std:: ios base ::showpoint;
209 lungime
210 noua_precizie = s ta t i c cas t <lungime >(precizie );
211 (*( sentry_afisare.sentry_flux()))
212 . se t f (optiunea_mea);
213 (*( sentry_afisare.sentry_flux()))
214 .precis ion (noua_precizie);
215 // curatat contoare ...
216 numar
217 locala_contor_afisari = Santinela::
218 afisat_cititor( s ta t i c cas t <numar >(1)),
219 locala_contor_flux = Santinela::
220 contor_flux_cititor( s ta t i c cas t <numar >(1));
221 i f (locala_contor_flux == s ta t i c cas t <numar >(1)){
222 /* ---
223 niciun obiect Afisare "in viata"...,
224 Santinela a incrementat deja...
225 ---*/
226 #i fd e f VERIFICARE
76
227 std:: pr int f ("\n\nFolosim formatul meu\n\n");
228 #endif
229 i f (locala_contor_afisari == s ta t i c cas t <numar >(1))
230 //sub -obiectul sau Santinela distrus anterior ...
231 Santinela:: afisat_resetor( s ta t i c cas t <numar >(1));
232 }
233 }
234
235 octavian ::Afisare ::
236 Afisare(iesire* fflux , int pprecizie):
237 precizie ( s ta t i c cas t <numar >( pprecizie)),
238 sentry_afisare(Santinela(fflux))
239 {
240 i f (fflux == &std::cout){
241 flux_duplicat = flux_cout;
242 numar
243 locala_contor_afisari = Santinela::
244 afisat_cititor( s ta t i c cas t <numar >(1)),
245 locala_contor_flux = Santinela::
246 contor_flux_cititor( s ta t i c cas t <numar >(1));
247 i f (locala_contor_flux == s ta t i c cas t <numar >(1)){
248 #i fd e f VERIFICARE
249 std:: pr int f ("\n\nFolosim formatul meu!\n\n");
250 #endif
251 i f (locala_contor_afisari == s ta t i c cas t <numar >(1))
252 Santinela:: afisat_resetor( s ta t i c cas t <numar >(1));
253 }
254 }
255 i f (fflux == &std:: cerr){
256 flux_duplicat = flux_cerr;
257 numar
258 locala_contor_afisari = Santinela::
259 afisat_cititor( s ta t i c cas t <numar >(2)),
260 locala_contor_flux = Santinela::
261 contor_flux_cititor( s ta t i c cas t <numar >(2));
262 i f (locala_contor_flux == s ta t i c cas t <numar >(1)){
263 #i fd e f VERIFICARE
264 std:: pr int f ("\n\nFolosim formatul meu!\n\n");
265 #endif
266 i f (locala_contor_afisari == s ta t i c cas t <numar >(1))
267 Santinela:: afisat_resetor( s ta t i c cas t <numar >(2));
268 }
269 }
77
270 optiunea_mea = std:: ios base ::dec
271 | std:: ios base :: f ixed
272 | std:: ios base ::showpoint;
273 lungime
274 noua_precizie = s ta t i c cas t <lungime >( precizie);
275 (*( sentry_afisare.sentry_flux()))
276 . se t f (optiunea_mea);
277 (*( sentry_afisare.sentry_flux()))
278 .precis ion (noua_precizie);
279 }
280
281 octavian ::Afisare ::~ Afisare (){
282 // resetarea datelor stream -urilor:
283 /*---
284 Nu doresc sa folosesc functiile -membru ale
285 obiectului Santinela! Conform Stroustrup ,
286 Special edition , Section 10.4.6 , pag. 247,
287 atunci cand incepe executia unui destructor pentru
288 obiectele Afisare , are loc secventa "intai executam
289 codul destructorului , apoi apelam destructorii sub -
290 obiectelor"!
291 Pentru a evita sa tinem seama de aceasta secventa :
292 - am introdus functii -membru statice
293 in clasa Santinela;
294 - am introdus membrul "flux_duplicat"
295 in clasa Afisare;
296 ---*/
297 i f (flux_duplicat == flux_cout){
298 (*Santinela::
299 sentry_flux_stat( s ta t i c cas t <numar >(1)))
300 .unsetf (optiunea_mea);
301 (*Santinela::
302 sentry_flux_stat( s ta t i c cas t <numar >(1)))
303 . se t f (Santinela::
304 sentry_flux_flaguri_stat( s ta t i c cas t <numar >(1))
305 );
306 (*Santinela::
307 sentry_flux_stat( s ta t i c cas t <numar >(1)))
308 .precis ion (Santinela::
309 sentry_flux_precizie_stat( s ta t i c cas t <numar >(1))
310 );
311 }
312 i f (flux_duplicat == flux_cerr){
78
313 (* Santinela::
314 sentry_flux_stat( s ta t i c cas t <numar >(2)))
315 .unsetf (optiunea_mea);
316 (* Santinela::
317 sentry_flux_stat( s ta t i c cas t <numar >(2)))
318 . se t f (Santinela::
319 sentry_flux_flaguri_stat( s ta t i c cas t <numar >(2))
320 );
321 (* Santinela::
322 sentry_flux_stat( s ta t i c cas t <numar >(2)))
323 .precis ion (Santinela::
324 sentry_flux_precizie_stat( s ta t i c cas t <numar >(2))
325 );
326 }
327 precizie = numar();
328 optiunea_mea = date_fanioane();
329
330 /*---
331 In acest moment , pe fluxul "nume", unde "nume"
332 este fie "cout", fie "cerr", am (nedistruse)
333 atatea obiecte -format
334 Afisare: contor_flux_start_nume...
335 Au fost deja distruse atatea obiecte -format
336 Afisare:
337 afisat_contor_flux_nume...
338 In mod corect , lucrul cu un obiect -format Afisare
339 se realizeaza astfel: introduc un asemenea obiect
340 si apoi ii folosesc operatorul de apel --- opera -
341 tor() --- pentru a modifica precizia afisarii
342 datelor numerice ...
343 Se poate intampla sa introduc mai multe obiecte
344 -format pe acelasi flux.
345 ---*/
346
347 /*---
348 Doresc sa afisez un mesaj la distrugerea ultimului
349 obiect Afisare "in viata"...
350 Aici ma bazez pe secventa : "intai destructorul
351 obiectului mare , apoi cel al sub-obiectului"!
352 ---*/
353 i f (flux_duplicat == flux_cout){
354 numar
355 locala_contor_afisari = Santinela::
79
356 afisat_cititor( s ta t i c cas t <numar >(1)),
357 locala_contor_flux = Santinela::
358 contor_flux_cititor( s ta t i c cas t <numar >(1));
359 i f (locala_contor_flux == s ta t i c cas t <numar >(1)){
360 #i fd e f VERIFICARE
361 std:: pr int f (
362 "\nRevenim la formatul precedent pe fluxul "
363 "\"cout\"!\n"
364 "Asadar , pe acest flux , formatul meu "
365 "a fost aplicat de %d ori!\n\n",
366 s ta t i c cas t < int >( locala_contor_afisari) + 1);
367 // inca nu s-a incrementat afisarea ...
368 #endif
369 /* ---
370 Anterior , am folosit un obiect Afisare.
371 Dupa distrugerea lui , contorul
372 afisat_contor_flux_nume
373 a fost incrementat...
374 ---*/
375 Santinela:: afisat_resetor( s ta t i c cas t <numar >(1));
376 }
377 }
378 i f (flux_duplicat == flux_cerr){
379 numar
380 locala_contor_afisari = Santinela::
381 afisat_cititor( s ta t i c cas t <numar >(2)),
382 locala_contor_flux = Santinela::
383 contor_flux_cititor( s ta t i c cas t <numar >(2));
384 i f (locala_contor_flux == s ta t i c cas t <numar >(1)){
385 #i fd e f VERIFICARE
386 std:: pr int f (
387 "\nRevenim la formatul precedent pe fluxul "
388 "\"cerr\"!\n"
389 "Asadar , pe acest flux , formatul meu "
390 "a fost aplicat de %d ori!\n\n",
391 s ta t i c cas t < int >( locala_contor_afisari) + 1);
392 #endif
393 Santinela:: afisat_resetor( s ta t i c cas t <numar >(2));
394 }
395 }
396 }
397
398 octavian ::Afisare ::
80
399 Afisare(const Afisare& o_afisare):
400 sentry_afisare(o_afisare.sentry_afisare)
401 {
402 flux_duplicat = o_afisare.flux_duplicat;
403 precizie = o_afisare.precizie ;
404 optiunea_mea = o_afisare.optiunea_mea;
405 lungime
406 noua_precizie = s ta t i c cas t <lungime >( precizie );
407 (*( sentry_afisare.sentry_flux()))
408 . se t f (optiunea_mea);
409 (*( sentry_afisare.sentry_flux()))
410 .precis ion (noua_precizie);
411 }
412
413 octavian ::Afisare
414 octavian :: Afisare ::
415 operator=( const Afisare& o_afisare){
416 i f ( th is == &o_afisare)
417 return * th is ;
418 (*( sentry_afisare.sentry_flux()))
419 .unsetf (optiunea_mea);
420 sentry_afisare = o_afisare.sentry_afisare;
421 flux_duplicat = o_afisare.flux_duplicat;
422 precizie = o_afisare.precizie ;
423 optiunea_mea = o_afisare.optiunea_mea;
424 lungime
425 noua_precizie = s ta t i c cas t <lungime >(precizie );
426 (*( sentry_afisare.sentry_flux()))
427 . se t f (optiunea_mea);
428 (*( sentry_afisare.sentry_flux()))
429 .precis ion (noua_precizie);
430 return * th is ;
431 }
432
433 octavian ::Afisare&
434 octavian :: Afisare ::
435 operator()( int nnum){
436 numar transf_precizie = s ta t i c cas t <numar >(nnum);
437 precizie = transf_precizie;
438 return * th is ;
439 }
440
441 octavian ::iesire&
81
442 octavian ::
443 operator <<(octavian :: iesire& stream_iesire ,
444 octavian :: Afisare& af){
445 iesire*
446 locale_flux =af.sentry_afisare.sentry_flux();
447 (*locale_flux). f lush ()
448 .precis ion ( s ta t i c cas t <lungime >(af.precizie ));
449 return (* locale_flux);
450 }
Codul C++ din fisierul headerulnostru.h se gaseste la pagina 5.Program:> In mod asemanator, putem construi diverse mecanisme de introducere
(citire) a datelor de la tastatura ori via redirectare. In cartea sa despreınvatarea C++ [42], profesorul Stroustrup foloseste urmatoarea functie “deıncheiere”:
Functie de ıncheiere
1 void keep_window_open(){
2 std:: cin. c lear ();
3 std::cout << "Please enter a character to exit\n";
4 char ch;
5 std:: cin >> ch;
6 return;
7 }
O varianta a sa poate fi organizata astfel23:
Functie de ıncheiere: varianta
1 #include <iostream >
2 #include <iomanip >
3
4 void iesire();
5
6 int main(){
7 iesire();
8 return 0;
9 }
10
11 void iesire(){
12 for (
13 std:: cin. c lear (),
14 std::cout << "\nApasati ENTER"
15 " pentru a incheia: "
23 In anumite situatii, aceasta da gres. Vezi discutia de la pagina 137.
82
16 << std::endl ,
17 std:: cin. ignore();;
18 ) return;
19 }
Intotdeauna trebuie testata starea fluxului–de–intrare, cf. [41, p. 615,616]. Functia clear — cu valoarea prestabilita std::ios_base::goodbit
pentru parametru — seteaza starea fluxului la “buna”, iar functia ignore
citeste, fara sa stocheze, urmatorul caracter al fluxului, vezi [41, p. 619]. A-ceasta din urma se opreste din executie cand ıntalneste EOF din <stdio.h>.Este recomandabil, [41, p. 601], sa se foloseasca std::cin.eof() ın loculmacroului popular EOF din limbajul C — defapt, EOF este valoarea returnatade std::char_traits<char>::eof() din <iosfwd>, cf. [41, pg. 581, 620]— .
Program:> Pentru a usura codul C++, fluxurile de intrare–iesire dispun de operatorulvoid*. Astfel, starea fluxului este testata implicit pe baza acestui operator ınsecventele–bucla — for(/**/;/**/;/**/){/**/}, while(/**/){/**/} —ori ın executiile conditionate — if(/**/) then{/**/} —, cf. [41, p. 617]:
Testand starea fluxurilor. . .
1 #include <iostream >
2 #include <iomanip >
3 #include <cstdlib >
4
5 void main(){
6 char litera;
7 for (; std:: cin. c lear (), std:: cin >> litera;)
8 i f (litera == ’a’)
9 exit (EXIT SUCCESS);
10 }
Program:> Un alt aspect interesant poate fi remarcat ın cadrul programului unu.cppde la pagina 67, si anume ca nu este nevoie de instructiuni suplimentarepentru a afisa “numere” si “cuvinte” laolalta. Putem spune ca programul“ghiceste” felul output-ului. Mecanismul C++ care permite aceasta simplifi-care se numeste sablon24 si este reprezentat prin expresia <numele_tipului_
datei>. Fara prea multe detalii, poate fi folosit astfel:
Utilizarea sabloanelor: program.cpp
1 #include <cstdlib >
2 #include <cstdio >
3 #include <conio.h>
24 In limba engleza, template.
83
4
5 #include "sablon.cpp"
6
7 int main(){
8 out("\nSalut!\n");
9 out(3);
10 out("\nPa...");
11
12 getch();
13 return 0;
14 }
Utilizarea sabloanelor: sablon.cpp
1 #include <iostream >
2 #include <iomanip >
3
4 template<typename T>
5 void out(const T& t){
6 std:: cerr << t;
7 }
Desi ın locul cuvantului cheie typename putem scrie class, este reco-mandabil sa-l pastram pe primul, cf. [48, p. 10].
Program:> De multe ori, ın interiorul programelor de dimensiuni mai mari, se puneproblema sa raspundem unei anumite cerinte (periodice) printr-un bloc decod ın care este implementata o suita de pasi bine stabiliti (un algoritm).De exemplu, pentru a-si putea citi documentele din e-mail , un utilizatorurmeaza pasii standard: (i) insereaza un nume–de–utilizator, (ii) furnizeazao parola, (iii) apasa un buton, etc. In programul anterior, ın corpul functieiout a fost implementat un astfel de algoritm, si anume afisarea parametrilorreali. Insa, ın anumite situatii, la executarea unora dintre pasi trebuie apli-cate masuri particulare, specifice cerintei — e.g., utilizatorul respectivuluicont de e-mail este VIP , foloseste un serviciu suplimentar platit, etc. — .Aceste masuri constituie trasaturile25 raspunsului. Limbajul C++ folosestemecanismul sabloanelor si pentru a pune ın executie politica26, adica suita demasuri particulare prin care se rezolva o cerinta speciala, vezi [41, pg. 340,757].
Urmatorul program, scris ın limbajul C, se refera la o situatie ın caremecanismul C++ de implementare a politicilor poate micsora substantial can-titatea de cod. Reamintindu-ne discutia de la pagina 10 despre sistemul
25 In limba engleza, traits .26 In limba engleza, policy.
84
publicistic TEX, sa presupunem ca procesam un document stiintific (LATEX)pe platforma MiKTEX [25], via interfata grafica TEXnicCenter [43], vezi [27].Documentul ın cauza contine cateva zeci de fotografii mari, ın formatul eps,iar compilarea LATEX =⇒ PS dureaza cateva minute. Cum suntem nevoiti sacompilam documentul de sute de ori pe parcursul producerii sale, este util sadispunem de un program care sa dezactiveze/activeze fotografiile din codulLATEX. Dat fiind ca documentul este un sir de caractere ASCII, una dintresolutiile la ındemana consta ın apelarea la expresii regulate, vezi [20, p. 116],[42, p. 836].
In cazul nostru, problema este simpla, caci suntem interesati de douaexpresii exacte: \includegraphics[ si %\includegraphics[.
Cautarea unor expresii ıntr-un sir: graphics2.c
1 /* ---
2 >>>>graphics2:
3 un program simplu
4 de prepare a fisierelor "tex"
5 pentru compilarea "LaTeX ==> PS"
6 cu ajutorul "MiKTeX"
7 Copyright: Octavian , 2011 - -2014
8
9 >>>>Sintaxa liniei de comanda:
10 graphics2 nume_fisier.tex tip_procesare
11 Aici ,
12 nume_fisier: numele fisierului de
13 procesat
14 tip_procesare: tastati "i" (inserez)
15 sau "s" (sterg)
16
17 >>>>Ce face graphics2:
18 in fisierul "nume_fisier.tex",
19 blocurile de comenzi LaTeX destinate procesarii
20 imaginilor sunt de forma
21 =============
22 \begin{figure *}[h]
23 \centering
24 \includegraphics[DIMENSIUNI]{ ADRESA POZEI}\\
25 {CAPTURA POZEI}% INFORMATII AUXILIARE
26 \label{REFERINTA FIGURII%DEZACTIVATA}
27 \end{figure*}
28 =============
29 Aici (LaTeX),
30 "\\" desemneaza o noua linie ,
85
31 "%" un comentariu.
32 Pentru a DEZACTIVA (tip_procesare: "i") imaginea ,
33 graphics2 cauta expresia "\ includegraphics[" si
34 o prefateaza cu "%".
35 Pentru a ACTIVA (tip_procesare: "s") imaginea ,
36 graphics2 cauta expresia "%\ includegraphics[" si
37 sterge caracterul "%".
38
39 >>>>Limitarile graphics2:
40 -- nu analizeaza numele fisierului de procesat
41 -- nu rezerva memorie pt. expresia de procesat
42 -- daca fisierul de procesat nu exista ,
43 programul nu defineste un handler de eroare
44 (cerut de "fopen_s ")
45 -- fisierul procesat are nume fix: "scriere.tex"
46 -- ...
47 ---*/
48
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <conio.h>
52 #include <string.h>
53
54 /* ---
55 Numarul de caractere procesate la o alocare:
56 ---*/
57 #undef LUNGIME
58 #define LUNGIME 20
59
60 int main( int argc , char *argv[]){
61
62 /*---
63 Explicatia datelor:
64 fisier: stream -ul din care citim
65 executie : stream -ul in care scriem
66 model: expresia pe care o cautam
67 buffer: sirul in care salvam procesarea
68 particula: caracterul curent
69 fisier_intrare: numele fisierului de procesat
70 sir_intrare: tipul de procesare
71 iterator_sir: numarul total de caractere citite
72 alt_iterator: numarul de aparitii ale primului
73 caracter din expresia "model"
86
74 secv_iterator: numarul de aparitii ale
75 expresiei "model"
76 iterato:
77 iterator :
78 iteratorr:
79 salt: diversi iteratori
80 limita: lungimea blocului de memorie
81 lungime_model: lungimea expresiei "model"
82 contor: memoreaza pozitiile in care apare
83 primul caracter din expresia "model"
84 secvente : memoreaza pozitiile in care apare
85 expresia "model"
86 pa: handler de incheiere
87 ---*/
88
89 FILE *fisier = NULL, *executie = NULL;
90 char *buffer = NULL, particula = 0,
91 *fisier_intrare = NULL,* sir_intrare = NULL;
92 int iterator_sir = 0, alt_iterator = 0,
93 secv_iterator = 0, iterator = 0,
94 iteratorr = 0, iterato = 0, salt = 0,
95 limita = LUNGIME , lungime_model = 0,
96 *contor = NULL, *secvente = NULL;
97 void pa(char *, int *, int *);
98
99 i f (argc < 3){
100 pr int f s ("\nArgumente incomplete!\n"
101 "Vezi linia de comanda ...\n"
102 "Tasteaza o litera pentru a iesi: ");
103 getch();
104 return 0;
105 }
106 fisier_intrare = argv[1];
107 sir_intrare = argv[2];
108 i f (strcmp(sir_intrare ,"i") == 0){
109 /* ---
110 tipul procesarii: "i"
111 ---*/
112 char model[] = "\\ includegraphics[";
113 /* caracterul "\" este special in C...*/
114 lungime_model = countof (model) - 1;
115
116 buffer = (char *) ca l l oc (limita , s i z eo f (char));
87
117 contor = ( int *) ca l l oc (limita , s i z eo f ( int ));
118 secvente = ( int *) ca l l oc (limita , s i z eo f ( int ));
119
120 fopen s (&fisier ,fisier_intrare ,"r");
121 fopen s (&executie ,"scriere.tex","w");
122
123 /* blocul de citire:*/
124 for (;( particula = getc (fisier)) != EOF;
125 iterator_sir++){
126 i f (iterator_sir == limita){
127 limita += LUNGIME;
128 buffer = (char *) rea l l oc ((void *)buffer ,
129 limita* s i z eo f (char));
130 contor = ( int *) rea l l oc ((void *)contor ,
131 limita* s i z eo f ( int ));
132 secvente = ( int *) rea l l oc ((void *)secvente ,
133 limita* s i z eo f ( int ));
134 }
135 i f (particula == ’\\’){
136 contor[alt_iterator] = iterator_sir;
137 alt_iterator++;
138 }
139 buffer[iterator_sir] = particula;
140 }
141
142 /* daca suntem aici , atunci putem avea
143 iterator_sir == limita ...
144 altfel , limita > iterator_sir...*/
145 pr int f s ("\nStatistica:\n"
146 "Numar total de caractere: %d\n"
147 "Numar de aparitii ale caracterului: %d\n"
148 "Ultimul caracter citit: %c\n\n",
149 iterator_sir ,
150 alt_iterator ,
151 buffer[iterator_sir -1]);
152
153 /* blocul de testare:*/
154 for (iterator = 0;iterator < alt_iterator;
155 iterator ++){
156 for (iteratorr = 0; iteratorr < lungime_model;
157 iteratorr++)
158 i f (buffer[contor[iterator ]+iteratorr]
159 == model[iteratorr])
88
160 {salt++;}
161 i f (salt == lungime_model){
162 pr int f s ("Secventa apare "
163 "la pozitia: %d\n"
164 "Secventa este: ",
165 contor[iterator] + 1);
166 for (iterato = 0; iterato < lungime_model;
167 iterato ++){
168 pr int f s ("%c",
169 buffer[contor[iterator ]+iterato ]);
170 }
171 pr int f s ("\n");
172 secvente [secv_iterator] = contor[iterator ];
173 secv_iterator++;
174 }
175 salt = 0;
176 }
177
178 pr int f s ("\nStatistica:\n"
179 "Numar de aparitii ale secventei: %d\n",
180 secv_iterator);
181
182 /*blocul de manevre pentru sirul "buffer":*/
183 /*adaug memorie pentru introducere...
184 ultimul caracter citit: iterator_sir - 1...
185 de asemeni , putem avea
186 limita == iterator_sir...
187 vreau sa adaug cel putin un caracter ...
188 avem secv_iterator aparitii ale expresiei;
189 pt fiecare aparitie introducem un %...
190 deci mai adaugam: */
191 i f (iterator_sir == limita){
192 salt = 1;
193 }
194 limita += (1 + secv_iterator)
195 /*atentie: secv_iterator este obligatoriu nenul!!!*/
196 + (salt == 0 ? 0 : 1);
197 buffer = (char *) rea l l oc ((void *)buffer ,limita);
198 buffer[limita -1] =’\0’; /* inchei sirul de acum...*/
199 for (iterator = iterator_sir;iterator <limita -1;
200 iterator ++)
201 buffer[iterator] = ’%’; /* completare standard ...*/
202 for (iteratorr = secv_iterator -1; iteratorr >= 0;
89
203 iteratorr --){
204 /* avem iterator_sir+1 <= limita -1...*/
205 for (iterator = iterator_sir
206 +( secv_iterator -1-iteratorr);
207 iterator >= secvente [iteratorr];
208 iterator --
209 ){
210 buffer[iterator +1]=buffer[iterator ];
211 }
212 buffer[secvente[iteratorr]] = ’%’;
213 }
214
215 /*blocul de manevre pentru fisierul nou:*/
216 fputs (buffer ,executie);
217 f f lu sh (executie );
218
219 /*blocul de final: inchiderea fisierelor ,
220 eliberarea memoriei ...*/
221 f c l o s e (fisier);
222 f c l o s e (executie );
223 pa(buffer ,contor ,secvente);
224 buffer = NULL;
225 contor = NULL;
226 secvente = NULL;
227 }/*---
228 final pentru tipul procesarii: "i"
229 ---*/
230 i f (strcmp(sir_intrare ,"s") == 0){
231 /* ---
232 tipul procesarii: "s"
233 ---*/
234 char model[] = "%\\ includegraphics[";
235 /* caracterul "\" este special in C...*/
236 lungime_model = countof(model) - 1;
237
238 buffer = (char *) ca l l oc (limita , s i z eo f (char));
239 contor = ( int *) ca l l oc (limita , s i z eo f ( int ));
240 secvente = ( int *) ca l l oc (limita , s i z eo f ( int ));
241
242 fopen s (&fisier ,fisier_intrare ,"r");
243 fopen s (&executie ,"scriere.tex","w");
244
245 /*blocul de citire:*/
90
246 for (;( particula = getc (fisier)) != EOF;
247 iterator_sir++){
248 i f (iterator_sir == limita){
249 limita += LUNGIME;
250 buffer = (char *) rea l l oc ((void *)buffer ,
251 limita* s i z eo f (char));
252 contor = ( int *) rea l l oc ((void *)contor ,
253 limita* s i z eo f ( int ));
254 secvente = ( int *) rea l l oc ((void *)secvente ,
255 limita* s i z eo f ( int ));
256 }
257 i f (particula == ’%’){
258 contor[alt_iterator] = iterator_sir;
259 alt_iterator++;
260 }
261 buffer[iterator_sir] = particula;
262 }
263
264 /*daca suntem aici , atunci putem avea
265 iterator_sir == limita ...
266 altfel , limita > iterator_sir...*/
267 pr int f s ("\nStatistica:\n"
268 "Numar total de caractere: %d\n"
269 "Numar de aparitii ale caracterului: %d\n"
270 "Ultimul caracter citit: %c\n\n",
271 iterator_sir ,
272 alt_iterator ,
273 buffer[iterator_sir -1]);
274
275 /*blocul de testare:*/
276 for (iterator = 0; iterator < alt_iterator;
277 iterator ++){
278 for (iteratorr = 0; iteratorr < lungime_model;
279 iteratorr++)
280 i f (buffer[contor[iterator ]+ iteratorr]
281 == model[iteratorr])
282 {salt++;}
283 i f (salt == lungime_model){
284 pr int f s ("Secventa apare "
285 "la pozitia: %d\n"
286 "Secventa este: ",
287 contor[iterator ] + 1);
288 for (iterato = 0; iterato < lungime_model;
91
289 iterato ++){
290 pr int f s ("%c",
291 buffer[contor[iterator ]+ iterato ]);
292 }
293 pr int f s ("\n");
294 secvente [secv_iterator] = contor[iterator ];
295 secv_iterator++;
296 }
297 salt = 0;
298 }
299
300 pr int f s ("\nStatistica:\n"
301 "Numar de aparitii ale secventei: %d\n",
302 secv_iterator);
303
304 /*blocul de manevre pentru sirul "buffer":*/
305 /*adaug memorie pentru introducere...
306 ultimul caracter citit: iterator_sir - 1...
307 de asemeni , putem avea limita == iterator_sir...
308 vreau sa adaug cel putin un caracter ...
309 avem secv_iterator aparitii ale expresiei;
310 pt fiecare aparitie introducem un %...
311 deci mai adaugam: */
312 i f (iterator_sir == limita){
313 salt = 1;
314 }
315 limita += (1 + secv_iterator)
316 /*atentie: secv_iterator este obligatoriu nenul!!!*/
317 + (salt == 0 ? 0 : 1);
318 buffer = (char *) rea l l oc ((void *)buffer ,limita);
319 buffer[limita -1] =’\0’; /* inchei sirul de acum...*/
320 for (iterator = iterator_sir;iterator <limita -1;
321 iterator ++)
322 buffer[iterator ] = ’%’; /* completare standard ...*/
323 for (iteratorr = 0;iteratorr <= secv_iterator -1;
324 iteratorr++){
325 for (iterator = secvente [iteratorr]-iteratorr;
326 iterator <= iterator_sir -iteratorr;
327 iterator ++
328 ){
329 buffer[iterator ]=buffer[iterator +1];
330 }
331 }
92
332
333 /*blocul de manevre pentru fisierul nou:*/
334 fputs (buffer ,executie);
335 f f lu sh (executie );
336
337 /*blocul de final: inchiderea fisierelor ,
338 eliberarea memoriei ...*/
339 f c l o s e (fisier);
340 f c l o s e (executie );
341 pa(buffer ,contor ,secvente);
342 buffer = NULL;
343 contor = NULL;
344 secvente = NULL;
345 }/*---
346 final pentru tipul procesarii: "s"
347 ---*/
348 i f (!(strcmp(sir_intrare ,"s") == 0)
349 &&
350 !(strcmp(sir_intrare ,"i") == 0)){
351 pr int f s ("\nOptiune eronata !\n"
352 "Vezi linia de comanda ...\n"
353 "Tasteaza o litera pentru a iesi: ");
354 }
355 getch();
356 return 0;
357 }
358
359 void pa(char *bufer , int *conto , int *ssecv){
360 f ree ((void *)bufer);
361 f ree ((void *)conto);
362 f ree ((void *)ssecv);
363 pr int f s ("\n\nLa revedere !\n\n\t");
364 }
Asa cum se poate observa, codul programului este ımpartit ın doua ras-punsuri la cereri specifice. Ar fi fost excelent sa dispunem de functia:
1 template<typename Expresie , typename Procesare >
2 char* graphics2(Expresie e, Procesare p){
3 // instructiuni...
4 }
Aici, cel de-al doilea argument precizeaza politica: i (inserare), respectiv s
(stergere).Doua tipuri de date din libraria standard C++, si anume vector si string,
93
folosesc unul dintre parametrii mecanismului sablon pentru a-si preciza polit-ica spatiului alocat (ın memorie), necesar bunei lor functionari — expandare—, cf. [41, pg. 442, 582]. Vezi si [24, p. 63, Item 13]. Aceste doua tipuri dedate pot fi folosite cu succes drept ınlocuitori de siruri de date “obisnuite”— adica, bool, char, int, double, [41, p. 70] —, vezi [42, pg. 60, 116], chiardaca nu cunoastem organizarea lor ın detaliu. Fiind implementate cu aju-torul sabloanelor, partea din libraria standard a limbajului C++ care descriedatele vector si string se mai numeste si libraria standard de sabloane27.
Program:> In acest program construim un vector de date double, pe care ıl sortam[15, p. 109] si ıl afisam — ınainte si dupa sortare —.
Sortarea unor numere reale: sortare1.cpp
1 #include "headerulnostru.h"
2 #include <iostream >
3 #include <vector >
4 #include <algorithm > //pt. sort
5
6 int main(){
7 std::vector <double > vectocta;
8 for ( int i = 0;i <= 6; i++)
9 vectocta .push back(1.27*(10-i)+3);
10 std::cout << "\nAfisare nesortata:\n"
11 <<std::endl;
12 for ( int i = 0;
13 i < s ta t i c cas t < int >( vectocta . s i ze ());
14 i++)
15 std::cout << "vectocta[" << i << "] = "
16 << vectocta[i]
17 << std::endl;
18 /*---
19 pentru "sort" vezi si
20 http://www.cppreference.com/wiki/algorithm/sort
21 ---*/
22 std:: sort (vectocta .begin(),vectocta.end());
23 std::cout << "\nAfisare sortata :\n"
24 <<std::endl;
25 for ( int i = 0;
26 i < s ta t i c cas t < int >( vectocta . s i ze ());
27 i++)
28 std::cout << "vectocta[" << i << "] = "
27 In limba engleza, Standard Template Library (STL), cf. [42, p. 1096]. Vezi si [18, pg.825, 909].
94
29 << vectocta[i]
30 << std::endl;
31 LA_REVEDERE
32 return 0;
33 }
Program:> Un program simplu ın care construim un string — acest tip de date, spredeosebire de vector, se refera numai la secvente de caractere28 — reia temacautarii ıntr-un dictionar on-line, vezi programul consola04.c de la pagina42, dar foloseste dictionarul Cambridge pentru engleza britanica. Deoareceinterogarile bazei de date, vezi [6, p. 26], [14, p. 139], sunt mai complicatedecat ın cazul dictionarului limbii romane, anumite cuvinte nu vor fi gasitecu expresia de interogare folosita ın program.
Dictionar: cambridge_1.cpp
1 #include "headerulnostru.h"
2 #include <iostream >
3 #include <string >
4
5 int main(){
6 std:: str ing
7 sirul = "\"C:\\ Program Files\\Mozilla Firefox"
8 "\\firefox.exe\""
9 " http:// dictionary.cambridge.org/"
10 "dictionary/british/";
11 std::cout << "\nDictionar on-line. "
12 "Inchideti fereastra browser -ului\n"
13 "dupa ce ati citit definitia.\n"
14 "Introduceti un cuvant: "
15 << std::endl;
16 std:: str ing adaos;
17 std:: cin >> adaos;
18 sirul += adaos + "_1?q=" + adaos;
19 std::cout << "\n-----------------\n"
20 "Adresa completa :\n"
21 << sirul
22 << "\n-----------------\n"
23 << std::endl;
24 sirul += "& (echo La revedere !)"
25 " & echo.";
26 system(sirul. c s t r ());
27 LA_REVEDERE
28Cf. [41, p. 583], string ınseamna basic_string<char>.
95
28 return 0;
29 }
Facem observatia ca fluxurile std::cout si std::cin sunt “legate”29 unulde celalalt, astfel ca programul va afisa pe ecran mesajul “Introduceti un
cuvant:” ıntotdeauna ınainte sa ceara, via cursor, tastarea unui cuvant ınlimba engleza, cf. [41, p. 623].
Program:> Folosim specificatorul de legaturi extern, vezi [18, p. 623, Sect. 863],pentru a ne referi la datele definite ıntr-o alta unitate de traducere30 (fisiercompilat, cu extensia obj). In programul care urmeaza, aceste date suntdiverse caractere speciale.
Afisare: afisat_caractere.cpp
1 #include "headerulnostru.h"
2 #include "litere.h"
3 #include <iostream >
4
5 int main(){
6
7 using namespace octavian ;
8 std::cout
9 << patr_stanga << " " << patr_dreapta
10 << ’\n’
11 << aco_stanga << " " << aco_dreapta
12 << std::endl
13 << rot_stanga << " " << rot_dreapta
14 << ’\n’
15 << coada_maimuta << spatiu << diez
16 << spatiu << bar_vert
17 << std::endl
18 << dolar << std::ends << tilda
19 << std::endl;
20 LA_REVEDERE
21 return 0;
22 }
Afisare: litere.h
1 #ifndef _LITERE_
2 #define _LITERE_
3
4 namespace octavian{
29 In limba engleza, tie.30 In limba engleza, translation unit , cf. [41, p. 197].
96
5 typedef char litere;
6 extern litere
7 spatiu ,
8 rot_stanga ,
9 rot_dreapta ,
10 patr_stanga ,
11 patr_dreapta ,
12 aco_stanga ,
13 aco_dreapta ,
14 diez ,
15 bar_vert ,
16 coada_maimuta ,
17 dolar ,
18 tilda;
19 }
20
21 #endif
Afisare: litere.cpp
1 #include "litere.h"
2 typedef octavian ::litere octalt;
3
4 // vezi http://en.wikipedia.org/wiki/ASCII_table
5 octalt
6 octavian :: spatiu = ’\040’,
7 octavian :: rot_stanga = ’\050’,
8 octavian :: rot_dreapta =’\051’,
9 octavian :: patr_stanga = ’\133’,
10 octavian :: patr_dreapta = ’\135’,
11 octavian :: aco_stanga = ’\173’,
12 octavian :: aco_dreapta = ’\175’,
13 octavian :: bar_vert = ’\174’,
14 octavian :: coada_maimuta = ’\100’,
15 octavian ::diez = ’\043’,
16 octavian :: dolar = ’\044’,
17 octavian :: tilda = ’\176’;
Utilizand cuvantul cheie typedef, introducem un pseudonim31 pentrunumele unui tip de date, vezi [41, p. 84]. Astfel, este mult mai usor demodificat programul atunci cand schimbam tipul de date — d.ex. utilizamtipul wchar_t [41, p. 72] ın loc de char —.
31 In limba engleza, alias .
97
Program:> Reamintesc ca, ın cadrul limbajului C, un obiect este o zona de memorie,a carei interpretare depinde de clasa de stocare32 — aceasta din urma deter-mina durata de viata33 a stocarii; avem doua clase de stocare34: automata sistatica —, si de tipul datelor stocate, cf. [20, pg. 195, 197] si [42, p. 60]. Ex-emplul imediat este dat de literele “de un octet” lungime. Astfel, obiectului(variabilei) litera din definitia
1 char litera = ’a’;
ıi este alocat un bloc de opt biti ın memorie35. Insa, ın afara tipurilor fun-damentale de date, exista si tipuri derivate, cum ar fi structurile si uniunile,cf. [20, p. 196], care ınglobeaza diverse siruri de obiecte. Aici, organizareamemoriei (cuvinte, aliniere36, etc.) tine de compilatorul folosit, vezi [20, pg.147, 149].
Limbajul C++ pune la dispozitia noastra un instrument suplimentar pen-tru crearea de noi tipuri de date (tipuri definite–de–utilizatori37), si anumeclasa (tipul class). Spre deosebire de cazul tipurilor fundamentale de dateint, char sau double, compilatorul trebuie “ınvatat” cum sa stocheze ınmemorie datele UDT, respectiv cum sa le manipuleze — ne putem ıntreba ceınseamna: (UDT data1) + (UDT data2) —. Cea de-a doua sarcina poartadenumirea de supraıncarcarea38 operatorilor, cf. [18, p. 623]. Nu toti oper-atorii limbajului C++ pot fi supraıncarcati, d.ex. operatorul conditional [23,p. 11], “?:”, nu poate fi supraıncarcat, cf. [42, p. 1070].
Datele de tipul class sunt reprezentate prin obiecte, vezi [42, p. 301].Astfel, o clasa, notata C, este familia (colectia) tuturor obiectelor de tipul C.Putem descrie ce ınseamna “sa faci parte” din clasa C, adica sa prezentam ca-racteristicile (datele–membru39 si functiile–membru) unui element din clasaC, si apoi exemplifica pe baza unui obiect (element) din colectia (familia,clasa, setul, etc.) notata C. Prin extrapolare, spunem ca datele–membrusi functiile–membru ale unui obiect oarecare al clasei C sunt datele–membru
32 In limba engleza, storage class .33 In limba engleza, lifetime, storage duration sau (local) extent , cf. [23, p. 49].34 In C++ apare cea de-a treia clasa de stocare, si anume free store (heap), cf. [42, p.
1047]. In standardul limbajului C++ ea se numeste (clasa de) stocare dinamica, vezi [39,p. 65]. Lasam la o parte chestiunea (stocarii) datelor din firele de executie, precizata destandard. . .
35Vezi si [42, p. 78, Section 3.9] pentru type safety.36Nu trebuie presupus ca marimea unei structuri este suma marimilor datelor sale [20,
p. 138].37 In limba engleza, user-defined types (UDT), cf. [42, p. 300].38 In limba engleza, operator overloading, vezi [42, p. 316 si urm.].39 In limba engleza, data members , cf. [42, p. 301]. In romaneste, se ıntalnesc frecvent
sintagmele variabile membre, cf. [18, p. 637], respectiv campuri , cf. [13, p. 91].
98
si functiile–membru ale clasei C40: mai precis, clasa C ne da un “sablon”al datelor pe care le ınmagazineaza un obiect al clasei (acestea sunt datele–membru), respectiv al functiilor (–membru) ce opereaza (de regula) cu dateleınmagazinate de obiectul ın cauza al clasei, vezi [18, p. 638, Sect. 885].Uneori, datele–membru ale unei clase sunt numite proprietatile clasei, iarfunctiile–membru ale clasei desemneaza metodele41 clasei, cf. [18, p. 643,Sect. 893]. Referindu-ne generic la proprietatile si metodele unei clase, dis-cutam despre membrii clasei. Atunci cand vorbim despre un obiect oarecareal clasei, spunem ca el este o instanta a clasei, vezi [18, ibid.].
Proiectul Visual Studio listat ın continuare se refera la o clasa fara date–membru. El este format din fisierele program.cpp, salut.h, salut.cpp siheaderulnostru.h — de la pagina 5 —.
Primul proiect cu clase: program.cpp
1 #include "headerulnostru.h"
2 #include "salut.h"
3
4 int main(){
5 octavian :: Salut primul_salut;
6 primul_salut.functie_salut();
7 LA_REVEDERE
8 return 0;
9 }
Primul proiect cu clase: salut.h
1 #ifndef _SALUT_
2 #define _SALUT_
3
4 namespace octavian{
5 c la s s Salut{
6 public :
7 void functie_salut();
8 }; //atentie , nu trebuie omis acest ";"!
9 }
10
11 #endif
40Cf. [41, p. 754], clasa si nu obiectul constituie unitatea de ıncapsulare.41 In paradigma object–oriented (OO) — programare orientata–obiect —, vezi [44, p.
12]. In limbajul Java [19, p. 111], toate functiile–membru sunt metode. Cf. [41, p. 310],ın C++ o metoda desemneaza mai degraba o functie–membru virtuala.
99
Primul proiect cu clase: salut.cpp
1 #include "salut.h"
2 #include <iostream >
3 #include <iomanip >
4
5 using namespace octavian ;
6 void Salut:: functie_salut(){
7 std::cout << "\nSalut , prieteni !\n" << std::endl;
8 }
Ca regula generala: declaratia unei clase din “viata reala” se introduceın fisierul nume_clasa.h ın timp ce implementarea membrilor sai — ın cazulnostru, definirea functiei octavian::Salut::functie_salut — trebuie fa-cuta ın fisierul nume_clasa.cpp.
Specificatorul de acces public ne permite sa apelam functia–membru cusintaxa:
1 numele_obiectului.numele_functiei_membru();
Alti specificatori sunt private — aprioric, nu este nevoie sa-l inseram ındeclaratii — si protected, vezi [41, pg. 402, 849].
Program:> Evident, un nume de spatiu, d.ex. octavian, va fi compus din declaratiilemai multor clase, plus alte date relevante (vezi programul afisat_caracterede la pagina 96), ca ın urmatorul proiect VS.
Al doilea proiect cu clase: program.cpp
1 #include "headerulnostru.h"
2 #include "salut.h"
3 #include "cutii.h"
4
5 int main(){
6 octavian ::Salut primul_salut;
7 primul_salut.functie_salut();
8 octavian ::Cutie al_doilea_salut ,
9 al_treilea_salut;
10 al_doilea_salut.functie_salut();
11 al_treilea_salut.functie_salut();
12 LA_REVEDERE
13 return 0;
14 }
Al doilea proiect cu clase: salut.h
1 #ifndef _SALUT_
2 #define _SALUT_
100
3 namespace octavian{
4 c la s s Salut{
5 typedef unsigned int numere;
6 s t a t i c numere contor;
7 public :
8 void functie_salut();
9 };
10 }
11 #endif
Al doilea proiect cu clase: salut.cpp
1 #include "salut.h"
2 #include <iostream >
3 #include <iomanip >
4
5 using namespace octavian ;
6 Salut::numere
7 Salut::contor = 0;
8
9 void Salut:: functie_salut(){
10 i f (contor++ == 0)
11 std::cout << "Salut , prieteni !\n" << std::endl;
12 }
Al doilea proiect cu clase: cutii.h
1 #ifndef _CUTII_
2 #define _CUTII_
3
4 namespace octavian{
5 c la s s Cutie{
6 public :
7 void functie_salut();
8 };
9 }
10
11 #endif
Al doilea proiect cu clase: cutii.cpp
1 #include "cutii.h"
2 #include <iostream >
3 #include <iomanip >
4
101
5 using namespace octavian ;
6 #include "salut.h"
7
8 void Cutie:: functie_salut(){
9 Salut salut;
10 salut.functie_salut();
11 std::cout << "Ne revedem , prieteni !\n" << std::endl;
12 }
Pana acum, ın numele de spatiu octavian am introdus clase cu caracteris-tici asemanatoare — ambele se ocupa de prelucrarea/transmiterea unui mesajcatre utilizator —, ceea ce ne-a facut sa dam acelasi nume functiilor–membruınsarcinate cu afisarea mesajului, chiar daca implementarile lor difera. Acestefunctii–membru publice constituie interfata (publica) a claselor [41, p. 760],si reprezinta, ın fapt, tot ceea ce ıl intereseaza pe utilizatorul respectivelorclase, vezi [41, p. 225], [23, p. 100].
Membrii statici ai unei clase — atunci cand sunt specificati drept publici— pot fi apelati, chiar daca nu dispunem ın program de obiecte ale clasei ıncauza, cu sintaxa:
1 /**/ numele_clasei:: numele_membrului /**/;
cf. [41, p. 228].Program:> Introducem ın discutie un tip special de functie–membru, si anume cons-
tructorul . In primul rand, un constructor nu returneaza valori si are numeleclasei , cf. [34, p. 46]. De asemeni, nu putem introduce pointeri la construc-tori [41, p. 424].
1 // diversi constructori:
2 numele_clasei();
3 numele_clasei(tip_un_argument ,tip_alt_argument);
4 // alte functii --membru:
5 tip_data_iesire
6 numele_functiei_membru(tip_data_intrare);
Atunci cand este apelat, acesta construieste (initializeaza) un obiect alclasei, adica realizeaza o instantiere a clasei, vezi [42, pg. 182, 183]. Astfel,datele–membru ale unei clase pot fi initializate prin intermediul construc-torilor: ın fisierul program.cpp al proiectului VS listat mai jos, obiectulcutiedoi din clasa Cutie_doi are valoarea 4 la campul numar. Multimeavalorilor pe care le au la un moment dat datele–membru ale unui obiect con-stituie starea (valoarea) obiectului la momentul respectiv, cf. [41, p. 748].
Initializarea/modificarea datelor–membru poate fi ınsa realizata si cu altefunctii–membru — este cazul clasei Cutie_unu din acelasi fisier, care folosestemembrul functie_scris pentru initializarea campului numar —.
102
Functiile–membru ale unei clase se ımpart, asadar, ın doua categorii: celecare “citesc” (nu modifica) date si cele care “scriu” (modifica) date. Putemfolosi terminologia inspectori si modificatori [41, p. 706], accesori si mutatori[44, p. 16], functii–set si functii–get [22, pg. 218, 229], etc. Impartirea este,evident, neriguroasa, caci putem vorbi si despre manageri – implementori –functii-helping42 – functii-de-acces – membri-const , vezi [22, p. 223 si urm.].
In anumite situatii — indiferent daca folosim un constructor sau o functie–membru oarecare —, dorim sa initializam unele dintre campuri cu valori“tipice” (standard). De exemplu, o valoare tipica pentru o data–membrude tip int este numarul zero. Ne putem pune ıntrebarea: ce ınseamna ovaloare tipica pentru o data UDT? Aceasta chestiune a condus la notiuneagenerala de invariant , cf. [42, p. 309], [41, p. 749], prin care descriem stareabuna(bine-definita) a unui obiect. In C++, valoarea standard a unei date detip T este oferita de expresia T(). Astfel, instructiunile int x = int(); siint x = 0; sunt echivalente, vezi [42, p. 323]. Prima dintre ele este esentialaatunci cand scriem sabloane, cf. [41, p. 131].
Daca valoarea standard a tipului unei anumite date este cunoscuta43,putem alege sa nu definim un constructor — el va fi generat de compilator(cel putin44) pentru datele UDT [41, pg. 243, 244] — sau sa folosim unconstructor fara argumente. Acesta este constructorul implicit45, cu sintaxanumele_clasei().
Constructori: program.cpp
1 #include "diverse.h"
2 #include "cutii.h"
3 using namespace octavian ;
4
5 int main(){
6 Cutie_zero cutiezero;
7 cutiezero.functie_citit();
8 Cutie_unu cutieunu;
9 cutieunu .functie_scris(
10 s ta t i c cas t <Cutie_unu::numere_in >(12)
11 );
12 cutieunu .functie_citit();
13 Cutie_doi cutiedoi;
14 cutiedoi .functie_citit();
15 Cutie_doi cutiedoii(
42sau –helper , vezi [41, p. 240].43De catre compilator!44 In Visual C++. . .45 In limba engleza, default constructor , cf. [42, p. 324].
103
16 s ta t i c cas t <Cutie_doi::numere_doi >(4)
17 );
18 cutiedoii.functie_citit();
19 cutiedoii = 34;
20 cutiedoii.functie_citit();
21 Cutie_trei cutietrei;
22 cutietrei.functie_citit();
23 iesire();
24 return 0;
25 }
Constructori: diverse.h
1 #ifndef _DIVERSE_
2 #define _DIVERSE_
3
4 #include <cstdlib >
5 #include <cstdio >
6 #include <conio.h>
7
8 namespace octavian{
9 void iesire();
10 }
11
12 #endif
Constructori: diverse.cpp
1 #include "diverse.h"
2 #include <iostream >
3 #include <iomanip >
4
5 void octavian :: iesire(){
6 for (
7 std:: cin. c lear (),
8 std::cout << "\nApasati ENTER"
9 " pentru a incheia: "
10 << std::endl ,
11 std:: cin.ignore();;
12 ) return;
13 }
Constructori: cutii.h
1 #ifndef _CUTII_
104
2 #define _CUTII_
3
4 namespace octavian{
5 c la s s Cutie_zero{
6 public :
7 void functie_citit();
8 };
9 c la s s Cutie_unu{
10 public :
11 typedef int numere_in;
12 typedef int numere_out;
13 void functie_citit() const ;
14 numere_out functie_scris(numere_in);
15 private:
16 numere_in numar;
17 };
18 c la s s Cutie_doi{
19 public :
20 typedef int numere_doi;
21 void functie_citit() const ;
22 Cutie_doi();
23 Cutie_doi(numere_doi nnumar);
24 private:
25 numere_doi numar;
26 };
27 c la s s Cutie_trei{
28 public :
29 typedef int numere_trei;
30 void functie_citit() const ;
31 exp l i c i t
32 Cutie_trei(numere_trei nnumar = numere_trei());
33 private:
34 numere_trei numar;
35 };
36 }
37
38 #endif
Constructori: cutii.cpp
1 #include "cutii.h"
2 #include <iostream >
3 #include <iomanip >
4 using namespace octavian ;
105
5
6 void Cutie_zero:: functie_citit(){
7 #undef STA
8 #define STA std::
9 STA cout << "In Cutie_zero avem:\n"
10 << STA endl;
11 #undef STA
12 }
13
14 Cutie_unu:: numere_out
15 Cutie_unu:: functie_scris(Cutie_unu:: numere_in nnumar){
16 numar = nnumar;
17 return stat i c cas t <numere_out >( numar);
18 }
19
20 void Cutie_unu:: functie_citit() const{
21 std::cout << "In Cutie_unu avem: "
22 << s ta t i c cas t < int >(numar) << "\n"
23 << std::endl;
24 }
25
26 Cutie_doi:: Cutie_doi(){
27 numar = Cutie_doi:: numere_doi();
28 }
29
30 Cutie_doi:: Cutie_doi(Cutie_doi:: numere_doi nnumar){
31 numar = nnumar;
32 }
33
34 void Cutie_doi:: functie_citit() const{
35 using namespace std;
36 cout << "In Cutie_doi avem: "
37 << s ta t i c cas t < int >( numar) << "\n"
38 << endl;
39 }
40
41 Cutie_trei:: Cutie_trei(Cutie_trei:: numere_trei nnumar){
42 numar = nnumar;
43 }
44
45 void Cutie_trei:: functie_citit() const {
46 #undef IES
47 #define IES std::cout
106
48 #undef SFARSIT
49 #define SFARSIT std::endl;
50 IES << "In Cutie_trei avem: "
51 << s ta t i c cas t < int >(numar) << "\n"
52 << SFARSIT
53 #undef IES
54 #undef SFARSIT
55 }
Functiile–membru etichetate const nu pot modifica starea obiectului, cf.[41, pg. 229, 230].
Atunci cand obiectele unei clase nu sunt masive, vezi [41, p. 282], leputem folosi ca argumente standard pentru functiile–membru (ın particular,pentru constructori) — ıntotdeauna ultimele argumente, cf. [41, p. 153] —:
1 tip_date_iesire
2 nume_functie(
3 tip_unu argument_unu ,
4 tip_doi argument_doi = valoare_standard_doi ,
5 tip_trei argument_trei = valoare_standard_trei
6 );
Ultimul aspect al discutiei de fata priveste operatorul de atribuire46 = careintervine la linia 19 ın codul sursa al fisierului program.cpp. Starea obiectuluicutiedoii se modifica, valoarea campului numar fiind 34, ıncepand cu linia20. Pentru a evita o asemenea situatie, constructorul uniparametric al claseiCutie_trei a fost declarat explicit, vezi [41, p. 284].
Program:> Uneori, datele–membru manipulate ın program ocupa un spatiu consistentın memorie. De aceea, dorim ca — la sfarsitul domeniului de valabilitateal unui obiect — valorile datelor–membru ale acestuia sa fie “sterse”47. Inacest scop, limbajul C++ ne pune la dispozitie o functie–membru speciala, sianume destructorul , cu sintaxa ~numele_clasei(). In proiectul VS listatın continuare, la apelul destructorului va fi afisat un mesaj catre utilizatorulclasei. Daca destructorul nu este apelat ın mod explicit — o situatie mai rarıntalnita [22, p. 286] —, atunci programul ıl va apela ın mod automat .
Destructor: program.cpp
1 #include "diverse.h"
2 #include "cutie.h"
3
46 In limba engleza, assignment operator [41, p. 110].47Mai precis, trebuie sa “dezinitializam” obiectul clasei respective (dezinstantiere) si
apoi, daca am alocat ın mod explicit memorie pentru anumite manipulari, sa ıi returnam(dealocam) adresele de memorie folosite spatiului liber (free store), cf. [22, pg. 146, 285].
107
4 int main(){
5
6 {
7 octavian :: Cutie o_cutie;
8 }//fortez apelarea destructorului!
9
10 octavian :: iesire();
11 return 0;
12 }
Destructor: cutie.h
1 #ifndef _CUTIE_
2 #define _CUTIE_
3
4 namespace octavian{
5 c la s s Cutie{
6 typedef unsigned int numere;
7 numere numar;
8 numere initializor(numere);
9 public :
10 Cutie();
11 ∼Cutie();
12 };
13 }
14
15 #endif
Destructor: cutie.cpp
1 #include "cutie.h"
2 #include <iostream >
3 #include <iomanip >
4 using namespace octavian ;
5
6 Cutie::numere
7 Cutie:: initializor(numere nnumar){
8 return nnumar;
9 }
10
11 Cutie::Cutie(){
12 numar = initializor(
13 s ta t i c cas t <numere >(2 * numere() + 100)
14 );
15 }
108
16
17 Cutie::∼Cutie(){
18 std::cout << "Valoarea din Cutie este: "
19 << s ta t i c cas t < int >(numar) << ’\n’
20 << std::endl;
21 numar = numere();
22 }
Fisierele diverse.h, diverse.cpp se gasesc la pagina 104.Program:> In cazul unor constructori multiparametrici este recomandata utilizarea
unei liste de initializare a membrilor [41, pg. 247, 248], cu sintaxa:
1 nume_clasa:: nume_clasa(tip_unu param_unu ,
2 tip_doi param_doi ,
3 tip_trei param_trei
4 ) :
5 data_unu(param_unu),
6 data_doi(param_doi),
7 data_trei(param_trei) {}
De asemeni, pentru a controla aparitia obiectelor unei clase, anumiti cons-tructori pot fi declarati private, ca ın proiectul care urmeaza. Un exemplutehnic este oferit de clasa std::slice_array<T> din STL, vezi [41, p. 671].Totusi, este indicat sa dispunem macar — public—de constructorul implicitpentru a nu avea probleme atunci cand fie introducem ın program o declaratiede tipul [22, p. 279]:
1 const octavian ::Cutie0 ocutie0_constanta;
fie avem date–membru const [41, p. 244].
Constructori2: program.cpp
1 #include "diverse.h"
2 #include "alte_cutii.h"
3
4 int main(){
5 octavian :: Cutie0 ocutie0;
6 ocutie0.initializor(
7 s ta t i c cas t <octavian ::numere_gen >(25)
8 );
9 pr int f s ("\n%d\n",ocutie0.cititor ());
10 pr int f s ("\n%d\n",
11 ocutie0.initializor(
12 s ta t i c cas t <octavian ::numere_gen >(26)
13 )
14 );
109
15 octavian :: Cutie1 ocutie1 (23 , -45.88);
16 pr int f s ("\n%d\n",
17 s ta t i c cas t < int >(
18 ocutie1.cititor_naturali()
19 )
20 );
21 pr int f s ("\n%f\n",
22 s ta t i c cas t <double >(
23 ocutie1.cititor_reali()
24 )
25 );
26 octavian :: iesire();
27 return 0;
28 }
Constructori2: alte_cutii.h
1 #ifndef _ALTE_CUTII_
2 #define _ALTE_CUTII_
3 namespace octavian{
4 // diverse
5
6 typedef int numere_gen;
7 c la s s Cutie0{
8 public :
9 typedef unsigned int numere;
10 numere initializor(numere_gen);
11 numere_gen cititor() const;
12 private:
13 numere numar;
14 };
15 typedef unsigned int naturali_gen;
16 typedef double reali_gen;
17 c la s s Cutie1{
18 public :
19 typedef unsigned int naturali ;
20 typedef double reali;
21 naturali_gen cititor_naturali() const;
22 reali_gen cititor_reali() const ;
23 exp l i c i t
24 Cutie1(naturali_gen nnat ,
25 reali_gen rreal = reali_gen()
26 );
27 ∼Cutie1();
110
28 private:
29 Cutie1();//ctor -ul "default" este privat!
30 naturali nat;
31 reali real;
32 };
33 }
34 #endif
Constructori2: alte_cutii.cpp
1 #include "alte_cutii.h"
2 using namespace octavian ;
3
4 Cutie0:: numere
5 Cutie0:: initializor(numere_gen nnumar){
6 return (numar = s ta t i c cas t <numere >(nnumar));
7 }
8
9 numere_gen Cutie0:: cititor () const {
10 return stat i c cas t <numere_gen >(numar);
11 }
12
13 Cutie1:: Cutie1(naturali_gen nnat , reali_gen rreal) :
14 nat(nnat), real(rreal) {}//lista de initializare!
15
16 Cutie1::∼Cutie1(){
17 nat = naturali ();
18 real = reali();
19 }
20 naturali_gen Cutie1:: cititor_naturali() const {
21 return stat i c cas t <naturali_gen >(nat);
22 }
23
24 reali_gen Cutie1:: cititor_reali() const{
25 return stat i c cas t <reali_gen >(real);
26 }
Fisierele diverse.h, diverse.cpp se gasesc la pagina 104.Mentionez o regula generala: desi nu are importanta ın ce ordine declaram
membrii clasei (date, functii, sabloane, tipuri [41, p. 755]) — fireste, separandpartea public de partile private si protected —, ın cazul unor constructorimultiparametrici, initializatorii acestora trebuie dati ın ordinea pe care amales-o la declararea constructorilor respectivi, cf. [42, pg. 310, 562].
Program:> In proiectul VS listat ın cadrul sectiunii de fata, introducem operatorii
111
new/new[] si delete/delete[], folositi de limbajul C++ pentru alocarea, re-spectiv dezalocarea unui spatiu de memorie, cf. [42, pg. 262, 578, 584], ınzona heap(free store). Vezi si [18, p. 610]. Trebuie precizat ca un obiect con-struit cu new va exista pana cand va fi distrus ın mod explicit cu delete [41,p. 128]. Astfel, se renunta la manipularea memoriei prin apelarea directa48
a functiilor malloc, calloc, realloc, free, etc., vezi [41, p. 577].
Manipularea memoriei: program.cpp
1 #include "diverse.h"
2 #include "vector.h"
3 using namespace octavian ;
4
5 int main(){
6 functie(
7 s ta t i c cas t <intregi_gen >(3),
8 s ta t i c cas t <reali_gen >(44.2)
9 );
10 iesire();
11 return 0;
12 }
Manipularea memoriei: vector.h
1 #ifndef _VECTOR_
2 #define _VECTOR_
3
4 namespace octavian{
5 typedef int intregi_gen;
6 typedef double reali_gen;
7 void functie(intregi_gen ,reali_gen);
8 c la s s Vector{
9 typedef int intregi;
10 typedef double reali;
11 typedef reali* preali;
12 intregi marime;
13 preali elem;
14 // marimi private , nu le implementam:
15 Vector();
16 Vector(const Vector&);
17 Vector& operator=( const Vector&);
18 reali_gen& operator[]( intregi_gen);
48Cf. [39, p. 81/67, nota de subsol 35], urmand standardul limbajului C++, implemen-tarea operatorului new ar trebui sa se bazeze pe functiile std::malloc si std::callocdin <cstdlib>.
112
19 public :
20 exp l i c i t Vector(intregi_gen mmarime);
21 ∼Vector();
22 intregi_gen lungime () const ;
23 void scriere(intregi_gen , reali_gen);
24 reali_gen citire(intregi_gen) const;
25 bool sir_sau_numar() const {
26 return ( s ta t i c cas t < int >( marime) == 1);
27 }
28 };
29 }
30 #endif
Manipularea memoriei: vector.cpp
1 #include "vector.h"
2 #include <iostream >
3 #include <iomanip >
4
5 octavian ::Vector::
6 Vector(intregi_gen mmarime) :
7 marime( s ta t i c cas t <intregi >(mmarime)),
8 elem(new reali_gen[mmarime ])
9 {
10 for ( int i = 0;
11 i < s ta t i c cas t < int >( mmarime);
12 i++
13 )
14 elem[i] = 1.1;
15 std::cout << "\nAm initializat Vectorul !\n"
16 << std::endl;
17 }
18 octavian ::Vector::
19 ∼Vector(){
20 delete [] elem;
21 std::cout << "\nAm sters Vectorul !\n"
22 << std::endl;
23 }
24 octavian :: intregi_gen
25 octavian :: Vector:: lungime () const {
26 #undef CONV
27 #define CONV(a) s ta t i c cas t <intregi_gen >(a)
28 return CONV(marime);
29 #undef CONV
113
30 }
31 void octavian :: Vector::
32 scriere(intregi_gen index ,reali_gen valoare){
33 typedef unsigned int ui;
34 elem[ s ta t i c cas t <ui >( index)]
35 = s ta t i c cas t <reali >( valoare);
36 }
37 octavian :: reali_gen
38 octavian :: Vector:: citire(intregi_gen index) const{
39 typedef unsigned int ui;
40 return stat i c cas t <reali_gen >(
41 elem[ s ta t i c cas t <ui >(index)]
42 );
43 }
44
45 void octavian ::
46 functie(intregi_gen index , reali_gen adaos){
47 octavian :: Vector un_vector(index);
48 i f (! un_vector.sir_sau_numar())
49 std::cout << "Vectorul are mai mult de o intrare!"
50 << std::endl;
51 for ( int i = 0;
52 i < s ta t i c cas t < int >( un_vector.lungime ());
53 i++
54 ){
55 un_vector.scriere(
56 s ta t i c cas t <intregi_gen >(i),
57 s ta t i c cas t <reali_gen >(1.2 * i) + adaos
58 );
59 std::cout << "\nun_vector[" << i << "] = "
60 << s ta t i c cas t <double >( un_vector.
61 citire( s ta t i c cas t <intregi_gen >(i))
62 )
63 << std::endl;
64 }
65 }
La fel ca pana acum, folosim fisierele diverse.h si diverse.cpp de la pagina104.
In codul sursa al fisierului vector.h apar, ıntre liniile 14 si 19, mai multemarimi (functii, operatori) pe care nu le definim — implementam —, cidoar le declaram. Fiind private, dupa cum am mai spus, aceste marimirestrictioneaza anumite utilizari ale obiectelor din clasa octavian::Vector.
114
La marimile de la liniile 16–17 ma voi referi ın proiectul Visual Studiourmator. Operatorul de indexare49 [] va putea fi introdus urmand tehnicasupraıncarcarii operatorilor, pe care o voi prezenta ulterior.
Ideea de a grupa date, functii, sabloane si tipuri ıntr-un ansamblu (clasa)care detine reguli precise de accesare a acestora poarta numele de ıncapsu-larea50 informatiei, cf. [18, pg. 635, 639].
Atunci cand implementarea unei functii–membru este minimala, ca ıncazul functiei octavian::Vector::sir_sau_numar, instructiunile acesteiapot fi inserate ın declaratia clasei, ceea ce va spori performanta executieiınsa va augmenta spatiul de memorie51 ocupat de cod [42, p. 312]. In modechivalent, o functie poate fi precedata de cuvantul cheie inline, vezi [41,pg. 144, 235] si [18, pg. 617, 658].
Program:> Ne ocupam ın acest proiect VS cu Regula Celor Trei, [36] si [41, pg. 283,284], adica vom implementa initializarea–directa si initializarea–cu–copiere52
a obiectelor unei clase. Pentru prima chestiune introducem constructorulde copiere53 al clasei, care are sintaxa nume_clasa(const nume_clasa&).Cea de-a doua chestiune priveste operatorul de atribuire al clasei, cu sintaxanume_clasa& operator =(const nume_clasa&).
Regula Celor Trei: program.cpp
1 #include "diverse.h"
2 #include "perechi.h"
3
4 int main(){
5 {
6 octavian :: Pereche0 prima_pereche;
7 prima_pereche.initializare(2,3.54);
8 octavian :: Pereche0 a_doua_pereche;
9 a_doua_pereche = prima_pereche;
10 a_doua_pereche.afisare ();
11 octavian :: Pereche0 a_treia_pereche(prima_pereche);
12 a_treia_pereche.afisare ();
13 }
14 {
15 octavian :: Pereche1 prima_pereche;
49 In limba engleza, subscript operator , cf. [41, p. 286].50 In limba engleza, encapsulation [42, p. 496].51Vezi [42, p. 577], [18, p. 439, Sect. 571].52 In limba engleza, direct–initialization — adica, blocul {T a; T b(a);} — si copy–
initialization — adica, blocul {T a; T b = a;} — [39, p. 216/202, Sect. 8.5, articolele14, 15]. Aici, T desemneaza tipul datei.
53 In limba engleza, copy constructor , cf. [41, p. 271].
115
16 prima_pereche.afisare ();
17 octavian :: Pereche1 a_doua_pereche(1 ,13.33);
18 a_doua_pereche.afisare ();
19 prima_pereche = a_doua_pereche;
20 prima_pereche.afisare ();
21 octavian :: Pereche1 a_treia_pereche(a_doua_pereche);
22 a_treia_pereche.afisare ();
23 }
24 octavian :: iesire();
25 #undef UN_TEXT
26 return 0;
27 }
Regula Celor Trei: perechi.h
1 #ifndef _PERECHI_
2 #define _PERECHI_
3 namespace octavian{
4 c la s s Pereche0 {
5 typedef int intregi;
6 typedef double reali;
7 intregi intreg;
8 reali real;
9 public :
10 void initializare( int , double);
11 void afisare () const;
12 };
13 c la s s Pereche1 {
14 typedef int intregi;
15 typedef double reali;
16 intregi intreg;
17 reali real;
18 Pereche1 ( int );
19 Pereche1 (double);
20 public :
21 Pereche1 ();
22 Pereche1 ( int ,double);
23 Pereche1 (const Pereche1 &);
24 Pereche1 & operator=( const Pereche1 &);
25 ∼Pereche1 ();
26 void afisare () const;
27 };
28 }
29 #endif
116
Regula Celor Trei: perechi.cpp
1 #include "perechi.h"
2 #include <iostream >
3 #include <iomanip >
4
5 #undef UN_TEXT
6 #define UN_TEXT \
7 std::cout << "\nMembrul intreg este: " \
8 << s ta t i c cas t < int >(intreg) \
9 << "\nMembrul real este: " \
10 << s ta t i c cas t <double >( real) \
11 << std::endl;
12 void
13 octavian :: Pereche0 ::
14 initializare( int iintreg , double rreal){
15 intreg = s ta t i c cas t <intregi >(iintreg);
16 real = s ta t i c cas t <reali >(rreal);
17 }
18 void octavian :: Pereche0 :: afisare() const{
19 UN_TEXT
20 }
21 octavian :: Pereche1 ::Pereche1 (){
22 intreg = intregi();
23 real = reali();
24 }
25 octavian :: Pereche1 ::
26 Pereche1 ( int iintreg ,double rreal){
27 intreg = s ta t i c cas t <intregi >(iintreg);
28 real = s ta t i c cas t <reali >(rreal);
29 }
30
31 octavian :: Pereche1 ::
32 Pereche1 (const octavian ::Pereche1 & o_pereche){
33 intreg = o_pereche.intreg;
34 real = o_pereche.real;
35 }
36 octavian :: Pereche1&
37 octavian :: Pereche1 ::
38 operator=( const octavian ::Pereche1 & o_pereche){
39 i f ( th is == &o_pereche)
40 return * th is ;//cazul "a == a"
41 intreg = o_pereche.intreg;
42 real = o_pereche.real;
117
43 return * th is ;
44 }
45 octavian :: Pereche1 ::∼Pereche1 (){
46 intreg = intregi();
47 real = reali();
48 }
49 void octavian :: Pereche1 :: afisare() const{
50 UN_TEXT
51 }
Fisierele diverse.h, diverse.cpp se gasesc la pagina 104.In primul bloc de cod — liniile 5–13 — din fisierul program.cpp am
folosit initializarea–directa si initializarea–cu–copiere pentru obiectele cla-sei Pereche0, care nu dispune de Cei Trei, si anume destructorul – cons-tructorul de copiere – operatorul de atribuire. Totusi, compilatorul ıncearcao initializare/copiere membru–cu–membru(superficiala)54 a datelor [41, pg.229, 245]. In cel de-al doilea bloc de cod — liniile 14–23 —, initializam o-biecte ale clasei Pereche1, care se bucura de sprijinul Celor Trei! Atuncicand clasa cu care operam contine date complexe — d.ex. siruri de caractere—, copierea/initializarea superficiala nu ne este de folos!
Datele UDT cu constructor de copiere si operator de atribuire au o semantica
de tip valoare, ın timp ce datele UDT pentru care folosim copierea/initializarea
superficiala detin o semantica de tip pointer(referinta), vezi [42, p. 619]. Aceasta
idee este generalizata ın limbajul C#, unde vorbim despre tipuri valoare si tipuri
referinta, cf. [16, pg. 140, 152].
Trebuie facut un comentariu privind design-ul celor doua clase Pereche0si Pereche1: campurile lor au tipuri independente, d.ex. octavian::Pere
che0::intregi nu are nimic de a face cu octavian::Pereche1::intregi.Pentru a pastra aceasta independenta, functiile–membru octavian::Pere
che0::afisare si octavian::Pereche1::afisare au coduri-sursa identice,si evitam duplicarea codului via macro-ul UN_TEXT55. Alta varianta pre-supune universalizarea tipurilor, si anume:
1 namespace octavian{
2 typedef int intregi;
3 typedef double reali;
4 void functie_afisare(intregi ,reali);//helper!
5 c la s s Pereche0 {
6 intregi intreg;
7 reali real;
54 In limba engleza, memberwise initialization, vezi [22, p. 295], si shallow/memberwisecopy, cf. [42, pg. 619, 621].
55Tot duplicat. . .
118
8 public :
9 //restul clasei , neschimbat
10 };
11 c la s s Pereche1 {
12 intregi intreg;
13 reali real;
14 Pereche1 ( int );
15 Pereche1 (double);
16 public :
17 //restul clasei , neschimbat
18 };
19 }
Acum, o implementare a functiei octavian::Pereche0::afisare poate fidata de codul:
1 void
2 octavian :: Pereche0 ::
3 afisare() const{
4 octavian :: functie_afisare(intreg ,real);
5 }
unde
1 void octavian :: functie_afisare(intregi iintreg ,
2 reali rreal){
3 std::cout << "\nMembrul intreg este: "
4 << s ta t i c cas t < int >(iintreg)
5 << "\nMembrul real este: "
6 << s ta t i c cas t <double >( rreal)
7 << std::endl;
8 }
In ce ma priveste, prefer utilizarea unui cod repetitiv introducerii de functii–helper.
O clasa pentru “perechi” profesionala este std::pair<T1,T2> din <utili
ty>, cf. [41, p. 482].In codul fisierului perechi.h, la liniile 23 si 24, apare un tip special de
date, si anume tipul referinta [22, pg. 38, 127, 130] avand sintaxa T&, undeT constituie un tip oarecare de date. Simbolul & desemneaza operatorul dereferentiere56 iar datele de tip referinta trebuie initializate, cf. [41, p. 97],fiind pseudonimele unor obiecte. De aceea, atunci cand aplicam initializarea–cu–copiere a unor obiecte UDT, vezi nota de subsol 53 de la pagina 115, au
56 In limba engleza, address-of operator [41, p. 264].
119
loc urmatorii pasi: se initializeaza obiectul a, apoi obiectul b, dupa careobiectul a va fi copiat ın obiectul b!
Pentru conformitate, limbajul C++ ne permite sa aplicam tipurilor de datepredefinite57, care nu sunt clase [22, p. 600], o sintaxa tipica claselor. Evi-dent, atunci cand introducem ıntr-un calcul numarul 7 (data de tip int)este “pretentios” sa ne referim la 7 ca la o instanta a clasei int. Totusi, 7este un element al multimii ıntregilor 58, astfel ca noul concept de obiect O
al clasei C poate fi fortat sa includa si tipurile predefinite de date. Astfel,initializarea–cu–copiere are sintaxa {int x = 7;} iar initializarea–directa sescrie {int x(7);} [42, p. 311].
Ultimul detaliu al discutiei se refera la pointerul this ıntalnit la liniile 39si 43 ın codul fisierului perechi.cpp. Astfel, atunci cand exista mai multeobiecte ale clasei C, fiecare poseda o copie a starii sale. In schimb, functiile–membru apelate prin intermediul instantelor (nestatice) folosesc aceeasi copiea functiei–membru respective (din declaratia clasei). Aceasta pentru ca fie-care functie–membru contine un pointer this de tipul C*. Pointerul thisda adresa instantei din clasa C prin intermediul careia functia–membru ıncauza a fost invocata, cf. [22, pg. 234-235] si [41, p. 231]. Functiile–membrustatice nu au, bine-nteles, un pointer this, vezi [41, p. 278].
Program:> Proiectul VS de fata implementeaza clasa octavian::Sir, tinand seamade Regula Celor Trei si supraıncarcand anumiti operatori ai limbajului C++.Unul dintre campurile clasei este un pointer la un sir de caractere, deci avemnevoie de alocari/dezalocari de memorie.
In fisierul sir.h de mai jos, folosim — ıncepand cu linia 15 — cuvantulcheie friend59. Entitatile etichetate drept prietene nu sunt membre aleclasei, ınsa exista conventia stilistica sa fie declarate la ınceputul bloculuide instructiuni [22, p. 240]. Marimile friend au access direct la membriiprivati ai clasei [41, pg. 278, 760]. Functia octavian::verificare — ınfisierul program.cpp, linia 5 — ısi foloseste atributul friend pentru a testaimplementarea initializarii–directe si a initializarii–cu–copiere a obiectelorclasei.
Un comentariu privind design-ul clasei. Ca si anterior, am utilizat pseudo-nime pentru diverse tipuri de date, pregatind clasa pentru aplicarea tehniciisabloanelor , vezi e.g., [41, p. 443]. Insa, pentru a nu complica excesiv co-dul, am folosit functiile strcpy_s si strcat_s din <string.h> ımpreuna cuoperatorul static_cast<T> ın locul unor algoritmi [41, p. 529].
57 In limba engleza, built-in [41, p. 241].58 In limba engleza, integers . Valoarea 7 este o constanta literala, neadresabila; cu alte
cuvinte, ea este stocata undeva ın calculator, ınsa nu putem “ajunge” la ea, vezi [22, p.17].
59 In limba romana, prieten.
120
Cu ajutorul macro-ului “de depanare” VERIFICARE pot fi observate efec-tele unor decizii ın design-ul operatorilor. Mai precis, analizand lista parame-trilor formali ai acestora, ne punem ıntrebarea: cand trebuie folosit apelulprin valoare60 [18, p. 187], si cand apelul prin referinta al functiilor (opera-torilor) [18, pg. 189, 192]?
Introducand cuvantul cheie explicit ın declaratia constructorului uni-parametric, ımpiedicam conversia (const char*) =⇒ octavian::Sir dinblocul {Sir a = "mac", b("mac");}. De asemeni, fiind date obiectele {Sira,b,c;}, nu putem realiza operatia {c = a + "mac";}, desi putem calculaexpresia {c = "mac" + b;}!
Pentru “numarul magic” 30 folosit ımpreuna cu operatorul new[], vezi[41, p. 423, Sect. 15.6.1].
Supraıncarcarea operatorilor: program.cpp
1 #include "diverse.h"
2 #include "sir.h"
3
4 int main(){
5 //octavian :: verificare();
6 char* asd = "mac";
7 octavian ::Sir pel(
8 s ta t i c cas t <octavian ::ptip_caracter >(asd)
9 );
10 pel = s ta t i c cas t <octavian :: ptip_caracter >("bip")
11 + pel;
12 pel += s ta t i c cas t <octavian :: ptip_caracter >(
13 "123456789777"
14 );
15 octavian :: tip_flux_iesire* ss = & std::cout;
16 (*ss) << pel;
17 octavian :: iesire();
18 return 0;
19 }
Supraıncarcarea operatorilor: sir.h
1 #ifndef _SIR_
2 #define _SIR_
3 #include <iostream >
4 #include <iomanip >
5 namespace octavian{
6 typedef char tip_caracter;
60 In limba engleza, pass–by–value [22, p. 125].
121
7 typedef tip_caracter* ptip_caracter;
8 typedef unsigned int tip_natural;
9 typedef int tip_intreg;
10 typedef tip_intreg& rtip_intreg;
11 typedef std:: ostream tip_flux_iesire;
12 typedef tip_flux_iesire& rtip_flux_iesire;
13
14 c la s s Sir{
15 fr iend void verificare();
16 fr iend tip_flux_iesire;
17 fr iend rtip_flux_iesire
18 operator <<(rtip_flux_iesire ,Sir&);
19 fr iend Sir
20 operator+( const ptip_caracter ,Sir);
21 public :
22 Sir();
23 exp l i c i t Sir(const ptip_caracter);
24 Sir(const Sir&);
25 ∼Sir();
26 Sir& operator=( const Sir&);
27 Sir& operator+=( const Sir&);
28 Sir& operator+=( const ptip_caracter);
29 Sir operator+( const Sir&) const ;
30 private:
31 tip_natural lungimea;
32 ptip_caracter sirul;
33 Sir(tip_natural);
34 Sir& operator+=( const rtip_intreg);
35 tip_intreg operator!() const ;
36 tip_caracter operator[]( tip_intreg);
37 };
38 }
39 #endif
Supraıncarcarea operatorilor: sir.cpp
1 #include "sir.h"
2 #include <string.h>
3 #include <errno.h>
4
5 #undef VERIFICARE
6 #define VERIFICARE 1
7 #undef VERIFICARE
8
122
9 octavian ::Sir::Sir(){
10 s t a t i c tip_natural
11 numar_standard = s ta t i c cas t <tip_natural >(
12 s i z eo f ("eusebiu") - 1
13 );
14 lungimea = numar_standard;
15 int numar_intern = s ta t i c cas t < int >( numar_standard)
16 + 1 /* + 30 */ ;
17 s t a t i c ptip_caracter sir_standard = "eusebiu";
18 sirul = new tip_caracter[numar_intern];
19 strcpy s ( s ta t i c cas t <char*>(sirul),
20 numar_intern ,
21 s ta t i c cas t <char*>(sir_standard)
22 );
23 #i fd e f VERIFICARE
24 pr int f s ("\n=====\n"
25 "Ctor. fara argumente pentru Sir!\n"
26 "Datele standard: sirul - %s, lungimea - %d."
27 "\n=====\n",
28 s ta t i c cas t <char*>(sirul),
29 s ta t i c cas t < int >( lungimea )
30 );
31 #endif
32 }
33 octavian ::Sir::Sir(const ptip_caracter ssirul){
34 int numar_intern = s ta t i c cas t < int >(
35 std:: str len (ssirul)
36 )
37 + 1 /* + 30 */ ;
38 lungimea = s ta t i c cas t <tip_natural >(
39 numar_intern - 1 /* - 30 */
40 );
41 sirul = new octavian :: tip_caracter[numar_intern];
42 strcpy s ( s ta t i c cas t <char*>(sirul),
43 numar_intern ,
44 s ta t i c cas t <char*>(ssirul)
45 );
46 #i fd e f VERIFICARE
47 pr int f s ("\n=====\n"
48 "Ctor. cu argument secv. pentru Sir!\n"
49 "Datele sale: sirul - %s, lungimea - %d."
50 "\n=====\n",
51 s ta t i c cas t <char*>(sirul),
123
52 s ta t i c cas t < int >( lungimea ));
53 #endif
54 }
55 octavian ::Sir::Sir(const Sir& un_sir){
56 lungimea = un_sir.lungimea ;
57 int numar_intern = s ta t i c cas t < int >( lungimea)
58 + 1 /* + 30 */ ;
59 sirul = new octavian :: tip_caracter[numar_intern];
60 strcpy s ( s ta t i c cas t <char*>(sirul),
61 numar_intern ,
62 s ta t i c cas t <char*>(un_sir.sirul)
63 );
64 #i fd e f VERIFICARE
65 pr int f s ("\n=====\n"
66 "Ctor. cu argument Sir& pentru Sir!\n"
67 "Datele sale: sirul - %s, lungimea - %d."
68 "\n=====\n",
69 s ta t i c cas t <char*>(sirul),
70 s ta t i c cas t < int >( lungimea )
71 );
72 #endif
73 }
74 octavian ::Sir::∼Sir(){
75
76 #i fd e f VERIFICARE
77 pr int f s ("\n=====\n"
78 "Dtor. pentru Sir!\n"
79 "Datele inaintea stergerii: "
80 "sirul - %s, lungimea - %d."
81 "\n=====\n",
82 s ta t i c cas t <char*>(sirul),
83 s ta t i c cas t < int >( lungimea )
84 );
85 #endif
86 delete [] sirul;
87 lungimea = tip_natural();
88 }
89 octavian ::Sir&
90 octavian ::Sir::
91 operator=( const octavian ::Sir& ssir){
92 i f ( th is == &ssir){
93 #i fd e f VERIFICARE
94 pr int f s ("\n=====\n"
124
95 "Cazul \"a == a\" la atribuire!"
96 "\n=====\n"
97 );
98 #endif
99 return * th is ;
100 }
101 delete [] sirul;
102 lungimea = ssir.lungimea ;
103 int numar_intern = s ta t i c cas t < int >( lungimea )
104 + 1 /* + 30 */ ;
105 sirul = new octavian :: tip_caracter[numar_intern];
106 strcpy s ( s ta t i c cas t <char*>(sirul),
107 numar_intern ,
108 s ta t i c cas t <char*>(ssir.sirul));
109 #i fd e f VERIFICARE
110 pr int f s ("\n=====\n"
111 "Oper. de atribuire pentru Sir!\n"
112 "Dupa aplicare , datele sunt: "
113 "sirul - %s, lungimea - %d."
114 "\n=====\n",
115 s ta t i c cas t <char*>(sirul),
116 s ta t i c cas t < int >( lungimea)
117 );
118 #endif
119 return * th is ;
120 }
121 octavian ::Sir&
122 octavian ::Sir::
123 operator+=( const octavian ::Sir& un_sir){
124 lungimea += un_sir.lungimea;
125 int numar_intern = s ta t i c cas t < int >( lungimea )
126 + 1 /* + 30 */ ;
127 ptip_caracter sir_intern = new octavian ::
128 tip_caracter[numar_intern];
129 strcpy s ( s ta t i c cas t <char*>(sir_intern),
130 numar_intern ,
131 s ta t i c cas t <char*>(sirul)
132 );
133 s t rcat s ( s ta t i c cas t <char*>(sir_intern),
134 numar_intern ,
135 s ta t i c cas t <char*>(un_sir.sirul)
136 );
137 delete [] sirul;
125
138 sirul = new tip_caracter[numar_intern];
139 strcpy s ( s ta t i c cas t <char*>(sirul),
140 numar_intern ,
141 s ta t i c cas t <char*>(sir_intern)
142 );
143 #i fd e f VERIFICARE
144 pr int f s ("\n=====\n"
145 "Oper. \"+=\" cu argument Sir& "
146 "pentru Sir!\n"
147 "Dupa aplicare , datele sunt: "
148 "sirul - %s, lungimea - %d."
149 "\n=====\n",
150 s ta t i c cas t <char*>(sirul),
151 s ta t i c cas t < int >( lungimea)
152 );
153 #endif
154 delete [] sir_intern;
155 return * th is ;
156 }
157 octavian ::Sir&
158 octavian ::Sir::
159 operator+=( const ptip_caracter alt_sir){
160 lungimea += s ta t i c cas t <tip_natural >(
161 std:: str len (alt_sir)
162 );
163 int numar_intern = s ta t i c cas t < int >(
164 lungimea
165 )
166 + 1 /* + 30 */ ;
167 ptip_caracter sir_intern = new octavian ::
168 tip_caracter[numar_intern];
169 strcpy s ( s ta t i c cas t <char*>(sir_intern),
170 numar_intern ,
171 s ta t i c cas t <char*>(sirul)
172 );
173 s t rcat s ( s ta t i c cas t <char*>(sir_intern),
174 numar_intern ,
175 s ta t i c cas t <char*>(alt_sir)
176 );
177 delete [] sirul;
178 sirul = new tip_caracter[numar_intern];
179 strcpy s ( s ta t i c cas t <char*>(sirul),
180 numar_intern ,
126
181 s ta t i c cas t <char*>(sir_intern)
182 );
183 #i fd e f VERIFICARE
184 pr int f s ("\n=====\n"
185 "Oper. \"+=\" cu argument Sir& "
186 "pentru Sir!\n"
187 "Dupa aplicare , datele sunt: "
188 "sirul - %s, lungimea - %d."
189 "\n=====\n",
190 s ta t i c cas t <char*>(sirul),
191 s ta t i c cas t < int >( lungimea)
192 );
193 #endif
194 delete [] sir_intern;
195 return * th is ;
196 }
197 octavian ::Sir
198 octavian ::Sir::
199 operator+( const Sir& iar_sir) const{
200 #i fd e f VERIFICARE
201 pr int f s ("\n=====\n"
202 "Oper. \"+\" - membru "
203 "este apelat!\n"
204 "Ce se intampla aici:"
205 );
206 #endif
207 Sir rezultat = * th is ;
208 rezultat += iar_sir;
209 #i fd e f VERIFICARE
210 pr int f s ("Final de apel pentru oper.\"+\""
211 " - membru!"
212 "\n=====\n"
213 );
214 #endif
215 return rezultat;
216 }
217 octavian ::Sir
218 octavian ::
219 operator+( const ptip_caracter ssir ,Sir sirr){
220 tip_natural numar_lucru = sirr.lungimea
221 + s ta t i c cas t <tip_natural >(
222 std:: str len (ssir)
223 );
127
224 int numar_intern = s ta t i c cas t < int >( numar_lucru)
225 + 1 /* + 30 */ ;
226 ptip_caracter sir_intern = new octavian ::
227 tip_caracter[numar_intern];
228 strcpy s ( s ta t i c cas t <char*>(sir_intern),
229 numar_intern ,
230 s ta t i c cas t <char*>(ssir)
231 );
232 s t rcat s ( s ta t i c cas t <char*>(sir_intern),
233 numar_intern ,
234 s ta t i c cas t <char*>(sirr.sirul)
235 );
236 #i fd e f VERIFICARE
237 pr int f s ("\n=====\n"
238 "Oper. \"+\" -nemembru este apelat!\n"
239 "Ce se intampla aici:");
240 pr int f s ("\n=====\n"
241 "Actiuni interne !\n"
242 "Datele intermediare sunt: "
243 "sirul - %s, lungimea - %d."
244 "\n=====\n",
245 s ta t i c cas t <char*>(sir_intern),
246 s ta t i c cas t < int >( numar_lucru)
247 );
248 #endif
249 octavian ::Sir alt_sir(sir_intern);
250 delete [] sir_intern;
251 #i fd e f VERIFICARE
252 pr int f s ("Final de apel pentru oper.\"+\""
253 " - nemembru !"
254 "\n=====\n"
255 );
256 #endif
257 return alt_sir;
258 }
259 octavian :: rtip_flux_iesire
260 octavian ::
261 operator <<(octavian :: rtip_flux_iesire os, Sir& ss){
262 return os << "\nSirul este: "
263 << s ta t i c cas t <char*>(ss.sirul) << ’\n’
264 << "Lungimea sa este: "
265 << s ta t i c cas t < int >(ss.lungimea)
266 << std::endl;
128
267 }
268 void octavian :: verificare(){
269 //verific implementarea:
270 Sir a("comert");
271 Sir aa = Sir();
272 Sir b(a);
273 Sir c = a + b;
274 c += aa;
275 octavian :: tip_flux_iesire*
276 ss = & std::cout;
277 (*ss) << c;
278 }
Program:> In continuare, implementam minimal clasa octavian::Cuvant pentru aafisa ın consola informatii despre diverse staruri de cinema — ele au legaturacu. . .matematica61 —. Unul dintre campurile clasei reprezinta o data de tipoctavian::Sir din proiectul VS precedent. El va ınmagazina prenumeleacestor staruri. Deoarece durata de viata a obiectelor de tip Sir este con-trolata de destructorul clasei ın cauza, clasa Cuvant nu are destructor iarproliferarea obiectelor de tip Cuvant este supervizata de un contor static.
Proiectul prezent se compune din fisierele program.cpp, diverse.h, diverse.cpp — vezi pagina 104—, sir.h, sir.cpp, cuvant.h, cuvant.cpp.
Atunci cand un obiect al clasei Cuvant are drept camp un obiect al claseiSir, spunem ca clasa Cuvant este ıntr-o relatie de tip are–un62 (cu clasa)Sir.
Relatii has-a: program.cpp
1 #include "diverse.h"
2 #include "sir.h"
3 #include "cuvant.h"
4
5 int main(){
6 octavian :: Cuvant McKellar("Danica" ,33);
7 McKellar .afisare ();
8 octavian ::Sir Portman("Natalie");
9 octavian :: Cuvant Oscar(Portman ,31);
10 Oscar.afisare ();
11 octavian :: Cuvant
12 doiMcKellar(Portman ,31),
13 treiMcKellar("Danica" ,33)
14 /*,patruMcKellar(Portman ,31)*/;
61Let’s google them!62 In limba engleza, has–a relationship [41, p. 741].
129
15 octavian :: iesire();
16 return 0;
17 }
Relatii has-a: cuvant.h
1 #ifndef _CUVANT_
2 #define _CUVANT_
3 #include "sir.h"
4 namespace octavian{
5 typedef unsigned int nr_natural;
6 c la s s Sir;// declaratia clasei Sir
7 c la s s Cuvant{
8 public :
9 Cuvant(const char*, nr_natural);
10 Cuvant(const Sir&, nr_natural);
11 void afisare () const;
12 void control ();
13 private:
14 Cuvant();
15 Cuvant(const char*);
16 Cuvant(const Sir&);
17 Cuvant(nr_natural);
18 nr_natural numar_poz;
19 Sir sir_car;
20 };
21 }
22 #endif
Relatii has-a: cuvant.cpp
1 #include "cuvant.h"
2 #include "sir.h"
3 #include <iostream >
4 #include <iomanip >
5
6 #undef CONTROLOR
7 #define CONTROLOR 1
8 #undef CONTROLOR
9
10 void octavian :: Cuvant:: control (){
11 s t a t i c
12 nr_natural contor = s ta t i c cas t <nr_natural >(1);
13 #i fd e f CONTROLOR
14 pr int f s ("\n+++%d+++\n",
130
15 s ta t i c cas t < int >( contor)
16 );
17 #endif
18 i f (contor == 5){
19 pr int f s ("\n=============\n"
20 "\nPrea multe cuvinte ... "
21 "La revedere !"
22 "\n=============\n"
23 );
24 exit (EXIT FAILURE);
25 }
26 i f (contor++ == 4)
27 pr int f s ("\n=============\n"
28 "Nu mai definiti alt Cuvant!"
29 "\n=============\n"
30 );
31 }
32 octavian ::Cuvant::
33 Cuvant(const char* ssir , nr_natural nr) :
34 sir_car( const cast <octavian ::ptip_caracter >(ssir)),
35 numar_poz(nr) { control (); }
36 octavian ::Cuvant::
37 Cuvant(const Sir& ssir , nr_natural nnr){
38 control ();
39 sir_car = ssir;
40 numar_poz = nnr;
41 }
42 void octavian :: Cuvant::
43 afisare () const {
44 std::cout << "Pozitia in clasament: "
45 << s ta t i c cas t < int >( numar_poz) << ’\n’
46 << "Detalii :\n"
47 << const cast <Sir&>(sir_car)
48 << std::endl;
49 }
Operatorul const_cast<T> este folosit pentru “ındepartarea” califica-tivului const al unei date de tip T, vezi [41, p. 131].
Program:> (Let’s get. . .math!) Reamintesc identitatea dublului produs vectorial (Gra-ssmann)
(u× v)× w = (u · w)v − (v · w)u, (1)
unde u, v si w sunt vectori liberi ın spatiul fizic (SF), cf. [28, p. 61]. In pro-iectul VS urmator implementam clasa octavian::VectLiber, cu care vom
131
modela vectorii liberi: u = xi+yj+zk ≡ (x, y, z) ∈ R3. Deoarece ın limbajul
C++ nu este permisa introducerea de noi operatori, ci numai supraıncarcareacelor predefiniti, vezi [22, p. 304], [41, p. 265], vom folosi operatorii “%” si “/”pentru a defini produsul scalar , respectiv produsul vectorial al vectorilor liberi(directiilor) din SF. La randul sau, forma determinant va fi implementata defunctia octavian::m.
Proiectul este alcatuit din fisierele program.cpp, headerulnostru.h —pagina 5 —, format_afisare.h, format_afisare.cpp — paginile 69, 71 —si vectliber.h, vectliber.cpp, listate ın continuare.
Cum “functioneaza” codul din programul principal program.cpp: afisamın consola componentele x, y si z pentru cei doi vectori liberi reprezentatide membrul stang, respectiv membrul drept al identitatii (1). Folosim douatipuri de date pentru cei trei vectori liberi din identitate: mai ıntai compo-nente int, apoi componente double. Marea dificultate a calculelor de acestfel o constituie precizia rezultatelor, deci avem nevoie de o functie “de for-mat” — nu uitati sa activati instructiunea #undef VERIFICARE din codulsursa al fisierului format_afisare.cpp! —.
Un produs scalar profesional este algoritmul inner_product<T1,T2,T3>din <numeric>, vezi [41, p. 683].
Identitatea lui Grassmann: program.cpp
1 #include "headerulnostru.h"
2 #include "vectliber.h"
3 #include <iostream >
4 #include <iomanip >
5
6 int main(){
7 system("cls");
8 octavian :: VectLiber unu(1,2,3),
9 doi(0,4,-1),
10 trei(7,5,6);
11 octavian :: verificare(unu ,doi ,trei ,5);
12 std::cout << ’\n’
13 << std::endl;
14 octavian :: verificare(unu ,doi ,trei ,30);
15 std::cout << "\n\n++++++++++\n"
16 << std::endl;
17 octavian :: VectLiber uunu(2 ,3 ,44.5),
18 ddoi( -2.12 ,8.09 ,1),
19 ttrei(0.002 ,1.3, 76.5);
20 octavian :: verificare(uunu ,ddoi ,ttrei ,5);
21 std::cout << ’\n’
132
22 << std::endl;
23 octavian :: verificare(uunu ,ddoi ,ttrei ,30);
24 LA_REVEDERE
25 return 0;
26 }
Identitatea lui Grassmann: vectliber.h
1 #ifndef _VECTLIBER_
2 #define _VECTLIBER_
3 namespace octavian{
4 c la s s VectLiber{
5 fr iend void verificare(VectLiber&,
6 VectLiber&,
7 VectLiber&,
8 unsigned int
9 );
10 fr iend
11 void afis_verificare(VectLiber&,unsigned int );
12 fr iend bool operator==( VectLiber&,VectLiber&);
13 fr iend VectLiber operator+( VectLiber&,VectLiber&);
14 fr iend VectLiber operator -( VectLiber&,VectLiber&);
15 fr iend VectLiber operator*(double ,VectLiber&);
16 fr iend VectLiber operator*( VectLiber&,double);
17 fr iend double operator%( VectLiber&,VectLiber&);
18 fr iend VectLiber operator/( VectLiber&,VectLiber&);
19 fr iend double m(VectLiber&,VectLiber&,VectLiber&);
20 public :
21 VectLiber();
22 VectLiber(double ,double ,double);
23 VectLiber(const VectLiber&);
24 ∼VectLiber();
25 VectLiber& operator=( const VectLiber&);
26 private:
27 VectLiber& operator+=( const VectLiber&);
28 VectLiber& operator -=( const VectLiber&);
29 double operator[]( int );
30 double operator()();
31 double* componente;
32 };
33 }
34 #endif
133
Identitatea lui Grassmann: vectliber.cpp
1 #include "vectliber.h"
2 #include "format_afisare.h"
3 #include <iostream >
4 #include <iomanip >
5 octavian :: VectLiber:: VectLiber(){
6 componente = new double[3];
7 for ( int i = 0; i < 3; i++)
8 componente[i] = double();
9 }
10 octavian :: VectLiber::
11 VectLiber(double x, double y, double z){
12 componente = new double[3];
13 componente[0] = x;
14 componente[1] = y;
15 componente[2] = z;
16 }
17 octavian :: VectLiber::
18 VectLiber(const VectLiber& un_vect){
19 componente = new double[3];
20 for ( int i = 0; i < 3; i++)
21 componente[i] = un_vect.componente[i];
22 }
23 octavian :: VectLiber::∼VectLiber(){
24 delete [] componente;
25 }
26 octavian :: VectLiber&
27 octavian :: VectLiber::
28 operator=( const octavian :: VectLiber& vlib){
29 i f ( th is == &vlib) return * th is ;
30 delete [] componente;
31 componente = new double[3];
32 for ( int i = 0; i < 3; i++)
33 componente[i] = vlib.componente[i];
34 return * th is ;
35 }
36 octavian :: VectLiber
37 octavian ::
38 operator+( octavian :: VectLiber& vlib ,
39 octavian :: VectLiber& vvlib
40 ){
41 VectLiber lucru;
42 for ( int i = 0; i < 3; i++)
134
43 lucru.componente[i] = vlib.componente[i]
44 + vvlib.componente[i];
45 return lucru;
46 }
47 octavian :: VectLiber
48 octavian ::
49 operator -( octavian :: VectLiber& vlib ,
50 octavian :: VectLiber& vvlib
51 ){
52 VectLiber lucru;
53 for ( int i = 0; i < 3; i++)
54 lucru.componente[i] = vlib.componente[i]
55 - vvlib.componente[i];
56 return lucru;
57 }
58 octavian :: VectLiber
59 octavian ::
60 operator*(double scal ,VectLiber& vlibb){
61 VectLiber lucru = vlibb;
62 for ( int i = 0; i < 3; i++)
63 lucru.componente[i] *= scal;
64 return lucru;
65 }
66 octavian :: VectLiber
67 octavian ::
68 operator*( VectLiber& vlib ,double scal){
69 VectLiber lucru = scal * vlib;
70 return lucru;
71 }
72 double
73 octavian ::
74 operator%( VectLiber& primul ,
75 VectLiber& aldoilea
76 ){
77 double numar = double();
78 for ( int i = 0; i < 3; i++)
79 numar += primul.componente[i]
80 * aldoilea.componente[i];
81 return numar;
82 }
83 octavian :: VectLiber
84 octavian ::
85 operator/( VectLiber& primul ,
135
86 VectLiber& aldoilea
87 ){
88 VectLiber vlb;
89 vlb.componente[0] = primul.componente[1]
90 * aldoilea.componente[2]
91 - aldoilea.componente[1]
92 * primul.componente[2];
93 vlb.componente[1] = primul.componente[2]
94 * aldoilea.componente[0]
95 - aldoilea.componente[2]
96 * primul.componente[0];
97 vlb.componente[2] = primul.componente[0]
98 * aldoilea.componente[1]
99 - aldoilea.componente[0]
100 * primul.componente[1];
101 return vlb;
102 }
103 double
104 octavian ::
105 m(VectLiber& unu ,VectLiber& doi ,VectLiber& trei){
106 double lucru = double();
107 lucru += unu.componente[0] * doi.componente[1]
108 * trei.componente[2];
109 lucru += unu.componente[2] * doi.componente[0]
110 * trei.componente[1];
111 lucru += unu.componente[1] * doi.componente[2]
112 * trei.componente[0];
113 lucru -= unu.componente[2] * doi.componente[1]
114 * trei.componente[0];
115 lucru -= unu.componente[0] * doi.componente[2]
116 * trei.componente[1];
117 lucru -= unu.componente[1] * doi.componente[0]
118 * trei.componente[2];
119 return lucru;
120 }
121 bool
122 octavian ::
123 operator==( VectLiber& stanga ,VectLiber& dreapta){
124 for ( int i = 0; i < 3; i++){
125 i f (
126 stanga.componente[i] != dreapta.componente[i]
127 )
128 return f a l s e ;
136
129 }
130 return true;
131 }
132 void octavian :: verificare(octavian :: VectLiber& a,
133 octavian :: VectLiber& b,
134 octavian :: VectLiber& c,
135 unsigned int precz){
136 VectLiber unu = (a/b)/c;
137 VectLiber doi = ((a%c)*b) -((b%c)*a);
138 afis_verificare(unu ,precz);
139 afis_verificare(doi ,precz);
140 i f (unu == doi)
141 std::cout << "Egali!"
142 << std::endl;
143 e l se
144 std::cout << "Inegali!"
145 << std::endl;
146 }
147 void octavian :: afis_verificare(VectLiber& vvlib ,
148 unsigned int prec){
149 std::cout << "\n==========="
150 << std::endl;
151 for ( int i = 0; i < 3; ++i)
152 std::cout << "Coordonata nr. " << i
153 << " este: "
154 << vvlib.componente[i]
155 << octavian ::Afisare (& std::cout ,prec)
156 << std::endl;
157 std::cout << "=============\n"
158 <<std::endl;
159 }
Program:> In proiectul VS anterior, ın afara afisarilor produse de functia de for-mat, a trebuit sa departajam anumite blocuri de date din consola “manual”,introducand “randuri decorative”. De aceea, ın programul de mai jos imple-mentam o formatare pentru mesajele “generale” de afisat ın consola.
Cu aceasta ocazie, revin la functia de tip getch a profesorului Stroustrup— vezi pagina 82 —. Aceasta seteaza la “buna” starea fluxului-de-intrare,apoi citeste urmatorul caracter (din flux). Varianta functiei, implementataın fisierul diverse.cpp de la pagina 104, si anume octavian::iesire, faceacelasi lucru, ınsa nu stocheaza caracterul citit — fluxurile de intrare si iesirefolosesc buffere pentru operatiile efectuate cu ele, vezi [41, p. 642] —. Cese ıntampla ınsa daca, dupa ce a “sarit” peste caracterul ın cauza, functia
137
iesire mai gaseste ın bufferul fluxului std::cin caractere necitite? Evident,ea ısi va ınceta executia, iar consola se va ınchide! O asemenea situatie poateavea loc ın timpul executiei programului de fata. Pentru a ımpiedica ınchi-derea consolei, modificam implementarea functiei iesire — vezi codul dinfisierul diverse.cpp listat ın continuare —, impunand golirea bufferului laınceputul executiei sale [41, p. 644]. Astfel, functia va trebui sa ıi cearautilizatorului introducerea unui caracter de la tastatura.
Un alt aspect al proiectului de fata ıl constituie supraıncarcarea functieioctavian::afisare, permisa de limbajul C++.
De asemeni, folosim date de tip std::string pentru a colecta sirul decaractere introdus de la tastatura pana la primul caracter “spatiu”, respectivfunctia get din <istream> pentru a citi caracterele de dupa spatiile goale[41, p. 619].
Afisari formatate: program.cpp
1 #include "diverse.h"
2 #include "afisare_gen.h"
3 #include <iostream >
4 #include <iomanip >
5 #include <string >
6
7 int main(){
8 std::cout << "Scrieti un cuvant cu maxim "
9 "cinsprezece litere: "
10 << std::endl;
11 /*---
12 Ce se intampla daca tastati:
13 acdert 23w
14 ---*/
15 std:: str ing cuvant;
16 std:: cin >> cuvant;
17 std::cout << "\nAti scris:\n"
18 << std::endl;
19 octavian ::afisare(cuvant);
20 octavian ::afisare (3,"intrebare");
21 /*for(int i = 1; i < 6; i++)
22 octavian :: afisare (3,"raspuns ");*/
23 char sir[] = "Un serif la panda!";
24 int numar = s ta t i c cas t < int >( countof(sir) / 2);
25 std::cout << "Scrieti un cuvant cu minim "
26 << numar
27 << " litere.\n"
28 "Daca este mai scurt , "
138
29 "incheiati -l cu litera "
30 "\"x\": "
31 << std::endl;
32 std:: cin.sync();
33 std:: cin. c lear ();
34 std:: cin.
35 get(sir ,
36 s ta t i c cas t <std:: streamsize >(numar),
37 ’x’
38 );
39 octavian ::afisare (3,sir);
40 octavian ::iesire();
41 return 0;
42 }
Afisari formatate: diverse.cpp
1 #include "diverse.h"
2 #include <iostream >
3 #include <iomanip >
4
5 void octavian :: iesire(){
6 for (
7 std:: cin.sync(),
8 std:: cin. c lear (),
9 std::cout << "\nApasati ENTER"
10 " pentru a incheia: "
11 << std::endl ,
12 std:: cin. ignore();;
13 ) return;
14 }
Afisari formatate: afisare_gen.h
1 #ifndef _AFISARE_GEN_
2 #define _AFISARE_GEN_
3 #include <string >
4
5 namespace octavian{
6 void afisare( std:: str ing &);
7 void afisare(unsigned int ,const char*);
8 void desen(unsigned int );
9 }
10 #endif
139
Afisari formatate: afisare_gen.cpp
1 #include "afisare_gen.h"
2 #include "diverse.h"
3 #include <iostream >
4 #include <iomanip >
5 #include <string >
6
7 void
8 octavian ::desen(unsigned int variab){
9 std::cout.width(variab);
10 std::cout. f i l l (’+’);
11 std::cout << "";
12 }
13
14 void
15 octavian :: afisare( std:: str ing & ccuvant){
16 unsigned int
17 numar = s ta t i c cas t <unsigned int >( ccuvant. s i ze ());
18 i f (( numar == 0) || (numar > 15)){
19 std::cout << "Prea multe litere !!!!!\n";
20 octavian :: iesire();
21 exit (EXIT FAILURE);
22 }
23 int lungime_afis = 12;
24 i f ((numar % 2) == 1) lungime_afis++;
25 int offset = lungime_afis - numar;
26 octavian ::desen(
27 s ta t i c cas t <unsigned int >( lungime_afis)
28 );
29 std::cout << std::endl;
30 octavian ::desen(
31 s ta t i c cas t <unsigned int >( offset /2)
32 );
33 std::cout << ccuvant;
34 octavian ::desen(
35 s ta t i c cas t <unsigned int >( offset /2)
36 );
37 std::cout << std::endl;
38 octavian ::desen(
39 s ta t i c cas t <unsigned int >( lungime_afis)
40 );
41 std::cout << ’\n’ << std::endl;
42 }
140
43
44 void
45 octavian ::
46 afisare(unsigned int nnr , const char* ssir){
47 i f (nnr == 1){//mod de apel: afisare (1," ");
48 std:: cin.unsetf ( std:: ios base :: skipws);
49 return;
50 }
51 e l se {
52 s t a t i c unsigned int contor = 1;
53 i f (contor++ < 5){
54 std:: str ing sir_intern = ssir;
55 octavian ::afisare(sir_intern);
56 }
57 e l se {
58 pr int f s ("\nPrea multe apeluri "
59 "\"afisare \"!"
60 );
61 octavian :: iesire();
62 exit (EXIT FAILURE);
63 }
64 }
65 }
Program:> (Let’s get math. . . again!) Utilizam clasa octavian::VectLiber ca sa pro-bam urmatoarea identitate fundamentala privind produsul mixt a trei vectoriliberi din SF [28, p. 47]:
(u, v, w) = (u× v) · w = (v × w) · u = (w × u) · v.
Pentru aceasta vom folosi pointeri la functii [20, p. 201], a caror initia-lizare poate fi facuta ca mai jos:
1 extern double octavian :: o_functie( int unu ,char doi);
2 double (* nume_pointer)( int ,char) = octavian :: o_functie;
Reamintesc ca tipul unei functii este dat de tipurile argumentelor sale63
si de tipul valorilor returnate [22, p. 201]. De asemeni, apelul unei func-tii se compune din numele functiei, operatorul de apel (), respectiv listaparametrilor reali . Astfel, luat de unul singur, numele functiei constituie unpointer la o functie de tipul curent, cf. [22, p. 202]. Prin suprasarcina64 func-tiei ıntelegem timpul de ıncarcare/descarcare a informatiilor pe stiva [22, p.
63Lista argumentelor unei functii este numita uneori si semnatura functiei. In limbaengleza, signature [22, p. 121].
64 In limba engleza, overhead .
141
112], care — la apelul prin valoare al functiei, atunci cand compilatorul ıitransmite acesteia cate o copie a fiecarui parametru real — poate fi semni-ficativ [18, p. 183]. Limbajul C++ introduce datele de tip referinta, T& [41,p. 97], unde T este un tip predefinit sau UDT, pentru a usura apelul prinreferinta al functiilor. Astfel, ın locul apelului a la limbajul C:
1 tip1 variabila1 = valoare_initiala1;
2 tip2 variabila2 = valoare_initiala2;
3
4 tip_date o_functie(tip1 *argument1 , tip2 *argument2)
5 {/* implementare */};
6 o_functie(&variabila1 , &variabila2);
unde argument1 este parametru formal si &variabila1 parametru real, pu-tem scrie ca
1 tip1 variabila1 = valoare_initiala1;
2 tip2 variabila2 = valoare_initiala2;
3
4 tip_date o_functie(tip1& argument1 , tip2& argument2)
5 {/* implementare */};
6 o_functie(variabila1 , variabila2);
Proiectul se compune din fisierele program.cpp, headerulnostru.h, diverse.h, diverse.cpp — de la pagina 139 —, vectliber.h, vectliber.cpp,format_afisare.h, format_afisare.cpp — activati instructiunea #undef
VERIFICARE din codul sursa al fisierului format_afisare.cpp! —, prodmixt.h, prodmixt.cpp.
Pointeri la functii: program.cpp
1 #include "diverse.h"
2 #include "vectliber.h"
3 #include "prodmixt.h"
4 #include <iostream >
5 #include <iomanip >
6
7 int main(){
8 system("cls");
9 octavian :: VectLiber unu(1,2,3);
10 octavian :: VectLiber doi(0,4,-1);
11 octavian :: VectLiber trei(7,5,6);
12 std::cout << "Testam identitatea lui Grassmann:"
13 << std::endl;
14 octavian :: verificare(unu ,doi ,trei ,5);
15 std::cout << "\n\n(unu x doi) . trei =" << std::endl;
142
16 octavian :: test_mix (unu ,doi ,trei ,octavian ::pm ,10);
17 std::cout << "\n\n(doi x trei) . unu =" << std::endl;
18 octavian :: test_mix (doi ,trei ,unu ,octavian ::pm ,10);
19 std::cout << "\n\n(trei x unu) . doi =" << std::endl;
20 octavian :: test_mix (trei ,unu ,doi ,octavian ::pm ,10);
21 std::cout << "\n\n(unu ,doi ,trei) =" << std::endl;
22 octavian :: test_mix (unu ,doi ,trei ,octavian ::m,10);
23 std::cout << std::endl;
24 octavian :: iesire();
25 return 0;
26 }
Pointeri la functii: prodmixt.h
1 #ifndef _PRODMIXT_
2 #define _PRODMIXT_
3 #include "vectliber.h"
4 namespace octavian{
5 typedef octavian :: VectLiber& tip;
6 typedef unsigned int ui;
7 typedef double(* functii)(tip ,tip ,tip);
8 double pm(tip ,tip ,tip);
9 void test_mix (tip ,tip ,tip ,functii ,ui);
10 }
11 #endif
Pointeri la functii: prodmixt.cpp
1 #include "prodmixt.h"
2 #include "vectliber.h"
3 #include "format_afisare.h"
4 #include <iostream >
5 #include <iomanip >
6
7 double octavian ::pm(tip a,tip b,tip c){
8 octavian :: VectLiber lucru = a / b;
9 return (lucru % c);
10 }
11 void
12 octavian ::
13 test_mix (tip a,tip b,tip c,functii f,ui prec){
14 double raspuns = f(a,b,c);
15 std::cout << raspuns
16 << octavian ::
17 Afisare (& std::cout ,
143
18 s ta t i c cas t < int >(prec)
19 )
20 << std::endl;
21 }
Program:> O structura reprezinta o agregare de date de diverse tipuri [20, p. 127],[41, p. 101]. Practic, ea este o clasa avand membrii aprioric publici al careiconstructor — daca exista! — trebuie folosit numai pentru simplificareainitializarii datelor componente, vezi [41, p. 234]. Un exemplu de structuraeste std::char_traits<T> din <iosfwd>, cf. [41, p. 580].
Structuri: program.cpp
1 #include "diverse.h"
2 #include "fise.h"
3
4 int main(){
5 octavian :: Fisa_guest vizitator;
6 vizitator.identificare = 134;
7 vizitator.nume = "Mustafa";
8 vizitator.prenume = "Octavian";
9 vizitator.raspuns ();
10 octavian :: Fisa_member popescu(1,
11 10,
12 "Popescu",
13 "Ionel",
14 "11.11.2011"
15 );
16 popescu.raspuns ();
17 octavian :: iesire();
18 #undef GAZDA
19 #undef OASPETE
20 #undef TEXT_FISA
21 return 0;
22 }
Structuri: fise.h
1 #ifndef _FISE_
2 #define _FISE_
3
4 namespace octavian{
5 struct Fisa_guest{
6 typedef int fisa_guest_intregi;
7 typedef char fisa_guest_caractere;
8 typedef
144
9 fisa_guest_caractere* pfisa_guest_caractere;
10 fisa_guest_intregi identificare;
11 pfisa_guest_caractere nume , prenume;
12 void raspuns ();
13 };
14 struct Fisa_member{
15 typedef int fisa_member_intregi;
16 typedef char fisa_member_caractere;
17 typedef
18 fisa_member_caractere* pfisa_member_caractere;
19 typedef
20 Fisa_guest::
21 pfisa_guest_caractere tip_data_inscriere;
22 fisa_member_intregi identificare , parola;
23 pfisa_member_caractere nume , prenume;
24 tip_data_inscriere data_inscriere;
25 void raspuns ();
26 Fisa_member( int , int ,char*,char*,char*);
27 };
28 }
29 #endif
Structuri: fise.cpp
1 #include "fise.h"
2 #include "diverse.h"
3 #include <iostream >
4 #include <iomanip >
5 #include <string.h>
6
7 #undef GAZDA
8 #define GAZDA octavian :: Fisa_member
9 #undef OASPETE
10 #define OASPETE octavian :: Fisa_guest
11 #undef TEXT_FISA
12 #define TEXT_FISA(q) \
13 std::cout << "Salut , " \
14 << s ta t i c cas t <char*>( ## q ::nume) \
15 << " " \
16 << s ta t i c cas t <char*>( ## q ::prenume) \
17 << "!\nID: " \
18 << s ta t i c cas t < int >( ## q :: identificare)
19
20 void octavian :: Fisa_guest::raspuns (){
145
21 TEXT_FISA(octavian :: Fisa_guest) << std::endl;
22 }
23 void octavian :: Fisa_member::raspuns (){
24 TEXT_FISA(octavian :: Fisa_member)
25 << "\nDrepturi: "
26 << s ta t i c cas t < int >( octavian :: Fisa_member:: parola)
27 << "\nInscris pe data: "
28 << s ta t i c cas t <char*>(
29 octavian :: Fisa_member:: data_inscriere
30 )
31 << std::endl;
32 }
33 octavian ::
34 Fisa_member:: Fisa_member( int iidentificare ,
35 int pparola ,
36 char* nnume ,
37 char* pprenume ,
38 char* ddata_inscriere
39 ) :
40 identificare(iidentificare),
41 parola(pparola)
42 {
43 int lungime_nume = std:: str len (nnume),
44 lungime_prenume = std:: str len (pprenume ),
45 lungime_data_inscriere = std:: str len (
46 ddata_inscriere
47 );
48 i f (lungime_nume > 100 ||
49 lungime_prenume > 100 ||
50 lungime_data_inscriere > countof(
51 "32 decembrie 10000"
52 )
53 ){
54 pr int f s ("\nSiruri prea lungi!");
55 octavian ::iesire();
56 exit (EXIT FAILURE);
57 }
58 nume = nnume;
59 prenume = pprenume;
60 data_inscriere = ddata_inscriere;
61 }
Program:> In afara fluxurilor de intrare si de iesire, ın limbajul C++ se folosesc fluxuripentru “comunicarea” cu fisierele. Astfel, ca sa citim, vezi [42, p. 344], dintr-
146
un fisier–text — ASCII —, vom utiliza un obiect al clasei65 std::ifstream,iar ca sa scriem ıntr-un fisier, de acelasi tip, un obiect al clasei66 std::ofstream din <fstream>.
In proiectul VS de fata implementam un contor global — structura —pentru a depista adresele de e-mail dintr-un fisier–text, salvat ın directorulC:\ProiecteleMele_Cpp\NumeleProiectului\NumeleProiectului. Con-torul ne ofera si informatii auxiliare: cate cuvinte exista ın fisier, cate contincaracterul “@” si la cate dintre acestea din urma caracterul respectiv este ıninterior 67. Reamintesc si programul UNIX intitulat wc — word counting —din [20, p. 20], bazat pe starea de ınauntrul/ın afara unui cuvant.
Structuri, fluxuri de fisier: program.cpp
1 #include "diverse.h"
2 #include "caractere.h"
3 #include "contoare.h"
4 #include <iostream >
5 #include <iomanip >
6 #include <fstream >
7 #include <string >
8
9 int main(){
10 std::cout << "\nIntroduceti numele "
11 "unui fisier din folderul curent.\n"
12 "Numele este: ";
13 std:: str ing nume;
14 std:: cin >> nume;
15 std:: i fstream citesc(nume. c s t r ());
16 i f (! citesc){
17 std::cout << "\nAvem probleme cu fisierul !"
18 << std::endl;
19 octavian :: iesire();
20 exit (EXIT FAILURE);
21 }
22
23 octavian ::
24 patch_coada_maimuta(citesc ,octavian :: coada_maimuta);
25
26 std:: str ing cuvant;
27 citesc.seekg(0, std:: ios ::beg);
65De la “input f ile stream”, cf. [41, p. 638]. Mai precis, un obiect std::ifstream esteun obiect al clasei std::basic_ifstream<char>.
66De la “output f ile stream”, cf. [22, p. 550].67O adresa de e-mail are forma partea_stanga@partea_dreapta!
147
28 octavian :: Contoare contor(0,0,0,0,0);
29 while(citesc >> cuvant){
30 unsigned int ciclare = 0;
31 ciclare = octavian :: detect_poz(cuvant ,contor);
32 octavian :: afis_cuvant(cuvant ,contor ,ciclare);
33 }
34
35 std::cout << "\nAm cautat simbolul \""
36 << octavian :: coada_maimuta
37 << "\".\nNumarul de cuvinte citite este "
38 << contor.contor_cuv
39 << ".\ nNumarul de cuvinte ce contin \""
40 << octavian :: coada_maimuta
41 << "\" citite este "
42 << contor.contor_cm
43 << ".\ nNumarul de cuvinte cu \""
44 << octavian :: coada_maimuta
45 << "\" in interior citite este "
46 << contor.contor_cmb
47 << ".\n"
48 << std::endl;
49 octavian :: iesire();
50 #undef INCHID_IN_EROARE
51 return 0;
52 }
Structuri, fluxuri de fisier: caractere.h
1 #ifndef _CARACTERE_
2 #define _CARACTERE_
3 #include <fstream >
4 #include "diverse.h"
5 namespace octavian{
6 typedef char litere;
7 extern litere coada_maimuta;
8 void patch_coada_maimuta( std:: i fstream&,litere);
9 }
10 #endif
Structuri, fluxuri de fisier: caractere.cpp
1 #include "caractere.h"
2 #include "diverse.h"
3 #include <iostream >
4 #include <iomanip >
148
5 #include <fstream >
6 #include <string >
7
8 #undef INCHID_IN_EROARE
9 #define INCHID_IN_EROARE \
10 octavian ::iesire(); \
11 exit (EXIT FAILURE);
12
13 typedef octavian :: litere octalt;
14 octalt octavian :: coada_maimuta =’\100’;
15 void octavian ::
16 patch_coada_maimuta( std:: i fstream& fisier ,
17 octalt litera
18 ){
19 std:: str ing cuvant;
20 fisier >> cuvant;
21 i f (cuvant. s i ze () == 0){
22 std::cout << "\nFisierul este gol!"
23 << std::endl;
24 INCHID_IN_EROARE
25 }
26 i f (cuvant [0] == litera)
27 std::cout << "\nPrimul cuvant "
28 "incepe cu \""
29 << s ta t i c cas t <char >( litera)
30 << "\"!"
31 << std::endl;
32 i f (fisier. eof ()){
33 std::cout << "Avem un singur cuvant , "
34 "si anume \""
35 << cuvant. c s t r ()
36 << "\".\nFisierul s-a incheiat !"
37 << std::endl;
38 INCHID_IN_EROARE
39 }
40 }
Structuri, fluxuri de fisier: contoare.h
1 #ifndef _CONTOARE_
2 #define _CONTOARE_
3 #include < string >
4
5 namespace octavian{
149
6 struct Contoare{
7 typedef unsigned long numere_naturale_mari;
8 typedef unsigned int numere_naturale;
9 numere_naturale_mari contor_cuv ,
10 contor_cm ,
11 contor_cmb;
12 numere_naturale contor_lucru ,
13 lungime_cuv;
14 Contoare (numere_naturale_mari ,
15 numere_naturale_mari ,
16 numere_naturale_mari ,
17 numere_naturale ,
18 numere_naturale
19 );
20 };
21 Contoare :: numere_naturale_mari
22 detect_poz( std:: str ing &,octavian ::Contoare &);
23 void
24 afis_cuvant( std:: str ing &,
25 octavian :: Contoare &,
26 octavian :: Contoare :: numere_naturale
27 );
28 }
29 #endif
Structuri, fluxuri de fisier: contoare.cpp
1 #include "contoare.h"
2 #include "caractere.h"
3 #include <iostream >
4 #include <iomanip >
5 #include <string >
6
7 typedef
8 octavian :: Contoare :: numere_naturale_mari mare;
9 typedef
10 octavian :: Contoare :: numere_naturale numere;
11
12 /*---
13 Semnificatia datelor:
14 "interior ": nici prima , nici ultima dintre litere
15 - ccontor_cuv: nr. total de cuvinte
16 - ccontor_cm: nr. de cuvinte cu "@"
17 - ccontor_cmb: nr. cuvinte cu "@" in interior
150
18 - ccontor_lucru: - 1 + prima pozitie interioara
19 a lui "@" in cuvantul curent
20 - llungime_cuv: lungimea cuvantului curent
21 ---*/
22
23 octavian ::
24 Contoare ::
25 Contoare (mare ccontor_cuv ,
26 mare ccontor_cm ,
27 mare ccontor_cmb ,
28 numere ccontor_lucru ,
29 numere llungime_cuv
30 ) :
31 contor_cuv(ccontor_cuv),
32 contor_cm(ccontor_cm),
33 contor_cmb(ccontor_cmb),
34 contor_lucru(ccontor_lucru),
35 lungime_cuv(llungime_cuv) {}
36
37 mare
38 octavian ::
39 detect_poz( std:: str ing & ccuvant ,
40 octavian :: Contoare & ccontor
41 ){
42 (ccontor.contor_cuv)++;//am citit un cuvant
43 ccontor.lungime_cuv = ccuvant. s i ze ();
44 i f (ccuvant [0] == octavian :: coada_maimuta){
45 (ccontor.contor_cm)++;//"@" e prima litera
46 return 0;
47 }
48 i f (ccuvant[ccontor.lungime_cuv - 1] == octavian ::
49 coada_maimuta
50 ){
51 (ccontor.contor_cm)++;//"@" e ultima litera
52 return 0;
53 }
54 for (numere i = 1;i < ccontor.lungime_cuv - 1; i++){
55 i f (ccuvant[i] == octavian :: coada_maimuta){
56 //incarc contorul doar daca gasesc un ’@ ’:
57 ccontor.contor_lucru = i;
58 (ccontor.contor_cm)++;
59 (ccontor.contor_cmb)++;
60 return 1;
151
61 }
62 }
63 return 2;
64 }
65 void
66 octavian ::
67 afis_cuvant(std:: str ing & ccuvant ,
68 octavian ::Contoare & ccontor ,
69 numere cciclare
70 ){
71 i f (cciclare == 1)
72 std::cout << "\n-----------\n"
73 "Cuvantul este: \""
74 << ccuvant. c s t r ()
75 << "\".\nEl are lungimea "
76 << s ta t i c cas t < int >(
77 ccontor.lungime_cuv
78 )
79 << ".\nPozitia (prima pozitie a)"
80 " caracterului \""
81 << s ta t i c cas t <char >(
82 octavian :: coada_maimuta
83 )
84 << "\" este "
85 << s ta t i c cas t < int >(
86 (ccontor.contor_lucru) + 1
87 )
88 << ".\n-----------\n"
89 << std::endl;
90 return;
91 }
Program:> In proiectul VS care urmeaza implementam clasele “financiare” octavian:
:Euro si octavian::Lei, respectiv clasele “bancare” octavian::Client sioctavian::Banca. Vom folosi operatorul de conversie68, cu sintaxa operato
r T(), unde numele T desemneaza un tip predefinit ori UDT de date, cuexceptia sirurilor — array —. In plus, T nu poate reprezenta o functie69,cf. [22, p. 342]. Programul din cadrul proiectului converteste obiectele de
68 In limba engleza, conversion operator .69 In limbajul C, functiile sunt un tip derivat [20, pg. 196, 201], iar ın limbajul C++
vorbim despre tipul obiectelor-functie [39, p. 571/557]. Prin obiect-functie — sau functor ,cf. [48, p. 418] — ıntelegem orice instanta a unei clase ce poseda o supraıncarcare aoperatorului de apel [41, p. 515].
152
tip octavian::Euro sau octavian::Lei ın variabile double cu ajutorul ca-rora instantele clasei octavian::Client, care sunt campuri ale unui obiectoctavian::Banca, vor realiza tranzactii . Mai precis, o banca are doi clienti,fiecare client poseda cate doua conturi, unul ın lei si celalalt ın euro, iartranzactiile facute de clienti ın cadrul bancii presupun conversia ın euro asumei din contul ın lei si transferarea acesteia ın contul ın euro. Evident,banca percepe un comision pe tranzactie si decide rata de schimb leu/euro.
Operatorul de conversie trebuie folosit ın mod judicios, vezi [22, p. 346],data fiind multitudinea de conversii implicite care apar la rularea programe-lor C++. In legatura cu conversiile, se cuvin mentionati operatorii static_cast<T>, const_cast<T> — deja ıntalniti —, respectiv dynamic_cast<T>70 sireinterpret_cast<T> [41, pg. 130, 131, 413].
Introducem ın discutie sabloanele de functii71, cu sintaxa:
1 template<typename Unu ,typename Doi>
2 void octavian :: tranzactie(Unu&,Doi&,double);
3 // specializari:
4 using namespace octavian ;
5 template<typename Unu >
6 void tranzactie(Unu&,Client&,double);
7 /* ---
8 specializarea completa nu se declara in
9 cadrul claselor carora le este "friend"
10 ---*/
11 template<> void tranzactie(Banca&,Client&,double);
Sablonul constituie elementul central al programarii generice, ın cadrulcareia tipurile datelor sunt parametri, vezi [41, p. 327]. Utilitatea unuisablon este evidenta atunci cand avem nevoie de functii, cum ar fi un con-vertor valutar — sau clase — care sa realizeze aceeasi prelucrare pentru omultitudine de tipuri de date. Atunci cand prelucrarea (generala) furnizatade sablon trebuie alterata, putem ıntrebuinta fie specializarile partiale, fiespecializarea completa a sablonului [41, pg. 342, 344]. Exista, ın plus, posi-bilitatea introducerii unor valori predefinite pentru parametrii sablonului,cf. [41, p. 340]. In Visual Studio numai sabloanele de clase beneficiaza deasemenea valori ale parametrilor de tip.
Cand invocam o functie–sablon72, inserand valorile reale ale parametrilorsablonului, are loc instantierea sablonului [22, p. 183]. Verificarile corespon-
70El se ocupa de “recuperarea” tipului unui obiect la run-time [41, p. 407]. In limbajulC#, aceasta idee conduce la reflexie, [1, p. 681].
71 In limba engleza, function templates .72Se folosesc, ın egala masura, si sintagmele sablon de functie sau functie generica, cf.
[18, p. 827].
153
dentelor de tip73, respectiv conversiile implicite nu se suspenda cand lucramcu functii–sablon, ınsa capata un regim special, vezi [22, pg. 185, 187, 199].
In cadrul proiectelor cu mai multe fisiere, declaratiile si definitiile (imple-mentarile) sabloanelor pot crea o serie de dificultati [41, p. 350 si urm.], [22,p. 198]. In limbajul C++ a fost introdus, ın scopul simplificarii chestiunilor delinkare, cuvantul cheie export [41, ibid.], care este ınsa doar rezervat pentrucompilatorul C++ din VS. Cf. [48, p. 12], ın momentul compilarii, acesta arenevoie de codul sursa al functiei–sablon, nu numai de declaratia acesteia.
Sabloane de functii: program.cpp
1 #include "diverse.h"
2 #include "headerulnostru.h"
3 #include "format_afisare.h"
4 #include "tranzactii.h"
5 #include <iostream >
6 #include <iomanip >
7 #include "sabloane.cpp"
8
9 int main(){
10 system("cls");
11 octavian ::Euro a(23.55 ,’e’);
12 octavian ::Lei b(144.0098,’r’);
13 octavian ::Client c(a,b,"Anghel");
14 octavian ::Euro d(133,’e’);
15 octavian ::Lei e(4358.2, ’r’);
16 octavian ::Client f(d,e,"Alina");
17 octavian ::Client hh(a,e,"Popa");
18 octavian ::Banca RoUnited (c,f,0.26 ,0.13 ,4.82);
19 octavian :: tranzactie(RoUnited ,c,0.07);
20 // octavian :: tranzactie(RoUnited ,hh ,0.07);
21
22 octavian :: iesire_versiunea2();
23 #undef FRAZA_PROVIZORIE_EURO
24 #undef FRAZA_PROVIZORIE_LEI
25 return 0;
26 }
Sabloane de functii: tranzactii.h
1 #ifndef _TRANZACTII_
2 #define _TRANZACTII_
3
73 In limba engleza, type-checking.
154
4 namespace octavian{
5 typedef unsigned int ui;
6 template<typename Unu , typename Doi >
7 void conversie(Unu&,Doi&,double ,double);
8
9 c la s s Euro{
10 template<typename Unu >
11 fr iend void verificare(Unu&);
12 template<typename Unu >
13 fr iend void afis_verificare(Unu&,ui);
14 template<typename Unu >
15 fr iend void afis_dobanda(Unu&,double ,ui);
16 template<typename Unu >
17 fr iend double stoc_dobanda(Unu&,double);
18 template<typename Unu >
19 fr iend Unu& aplic_dobanda(Unu&,double);
20 template<typename Unu >
21 fr iend Unu& actualizare(Unu&,double);
22 /* ---
23 impiedicam operatiile aritmetice nedorite :
24 ---*/
25 fr iend void operator+(Euro&,double);
26 fr iend void operator+(double ,Euro&);
27 fr iend void operator -(Euro&,double);
28 fr iend void operator -(double ,Euro&);
29 fr iend void operator*(Euro&,double);
30 fr iend void operator*(double ,Euro&);
31 fr iend void operator/(Euro&,double);
32 fr iend void operator/(double ,Euro&);
33 fr iend void operator==(Euro&,Euro&);
34 public :
35 Euro();
36 Euro(double ,char);
37 Euro(const Euro&);
38 Euro& operator=( const Euro&);
39 ∼Euro();
40 private:
41 // operatorul de conversie:
42 operator double();
43 double* suma;
44 char* valuta;
45 };
46
155
47 c la s s Lei{
48 template<typename Unu >
49 fr iend void verificare(Unu&);
50 template<typename Unu >
51 fr iend void afis_verificare(Unu&,ui);
52 template<typename Unu >
53 fr iend void afis_dobanda(Unu&,double ,ui);
54 template<typename Unu >
55 fr iend double stoc_dobanda(Unu&,double);
56 template<typename Unu >
57 fr iend Unu& aplic_dobanda(Unu&,double);
58 template<typename Unu >
59 fr iend Unu& actualizare(Unu&,double);
60 fr iend void operator+(Lei&,double);
61 fr iend void operator+(double ,Lei&);
62 fr iend void operator -(Lei&,double);
63 fr iend void operator -(double ,Lei&);
64 fr iend void operator*(Lei&,double);
65 fr iend void operator*(double ,Lei&);
66 fr iend void operator/(Lei&,double);
67 fr iend void operator/(double ,Lei&);
68 fr iend void operator==(Lei&,Lei&);
69 public :
70 Lei();
71 Lei(double ,char);
72 Lei(const Lei&);
73 Lei& operator=( const Lei&);
74 ∼Lei();
75 private:
76 operator double();
77 double* suma;
78 char* valuta;
79 };
80
81 c la s s Client{
82 template<typename Unu ,typename Doi >
83 fr iend void tranzactie(Unu&,Doi&,double);
84 /* ---
85 pentru verificarea specializarilor:
86 template <typename Unu >
87 friend void tranzactie(Unu&,Client&,double);
88 ---*/
89 fr iend bool operator==( Client&,Client&);
156
90 public :
91 Client();
92 Client(Euro ,Lei ,char*);
93 Client(const Client&);
94 Client& operator=( const Client&);
95 ∼Client();
96 private:
97 Euro* conteuro;
98 Lei* contlei;
99 char* nume;
100 };
101
102 c la s s Banca{
103 template<typename Unu ,typename Doi >
104 fr iend void tranzactie(Unu&,Doi&,double);
105 /* ---
106 pentru verificarea specializarilor:
107 template <typename Unu >
108 friend void tranzactie(Unu&,Client&,double);
109 ---*/
110 public :
111 Banca();
112 Banca(Client ,Client ,double ,double ,double);
113 Banca(const Banca&);
114 Banca& operator=( const Banca&);
115 ∼Banca();
116 // securizeaza tranzactiile
117 void actiune(octavian ::Client&);
118 private:
119 Client* clienti;
120 double* dobandaeuro;
121 double* dobandalei;
122 double* ratadeschimb;
123 };
124 }
125 #endif
Sabloane de functii: sabloane.cpp
1 #ifndef _SABLOANE_
2 #define _SABLOANE_
3 #include "tranzactii.h"
4 #include "format_afisare.h"
5 #include <iostream >
157
6 #include <iomanip >
7
8 // sabloane de functii "friends"
9 template<typename Unu >
10 void
11 octavian ::
12 afis_verificare(Unu& moneda ,octavian ::ui precizie){
13 std::cout << "\n=========\nSuma: "
14 << moneda.suma[0]
15 << "\nValuta: "
16 << moneda.valuta [0]
17 << "\n=========="
18 << octavian ::Afisare (& std::cout ,
19 s ta t i c cas t < int >( precizie )
20 )
21 << std::endl;
22 }
23 template<typename Unu >
24 void
25 octavian ::
26 afis_dobanda(Unu& moneda ,
27 double dobanda ,
28 octavian ::ui precizie
29 ){
30 double lucru = octavian ::
31 stoc_dobanda(moneda ,dobanda);
32 std::cout << "\n===========\n"
33 "Dobanda este: "
34 << lucru
35 << "\n==========="
36 << octavian ::Afisare (& std::cout ,
37 s ta t i c cas t < int >( precizie )
38 )
39 << std::endl;
40 }
41 template<typename Unu >
42 double
43 octavian ::
44 stoc_dobanda(Unu& moneda ,double dobanda){
45 double lucru = dobanda * double(moneda);
46 return lucru;
47 }
48 template<typename Unu >
158
49 Unu&
50 octavian ::
51 aplic_dobanda(Unu& moneda ,double dobanda){
52 double lucru = double(moneda)
53 + octavian :: stoc_dobanda(moneda ,
54 dobanda
55 );
56 moneda.suma[0] = lucru;
57 return moneda;
58 }
59 template<typename Unu >
60 Unu&
61 octavian ::
62 actualizare(Unu& moneda ,double valoare){
63 double lucru = valoare;
64 double bani = double(moneda);
65 i f (lucru < 0)
66 i f ((bani+lucru) < 0){
67 std::cout << "\n======\n"
68 "Fonduri insuficiente!"
69 "\n======"
70 << std::endl;
71 return moneda;
72 }
73 bani += lucru;
74 moneda.suma[0] = bani;
75 return moneda;
76 }
77 template<typename Unu , typename Doi >
78 void
79 octavian ::
80 conversie(Unu& moneda1 ,
81 Doi& moneda2 ,
82 double rata ,
83 double comision
84 ){
85 //determin cantitatea de bani din cont
86 double lucru = octavian ::
87 stoc_dobanda(moneda1 ,1);
88 //extrag comisionul de tranzactie
89 i f (lucru < comision ){
90 std::cout << "\n======\n"
91 "Comision prea mare!"
159
92 "\n======"
93 << std::endl;
94 return;
95 }
96 /*in acest moment al tranzactiei ,
97 actualizez contul initial */
98 moneda1 = octavian ::
99 actualizare(moneda1 ,-comision);
100 /*verific cantitatea de bani din cont
101 dupa extragerea comisionului*/
102 lucru = octavian :: stoc_dobanda(moneda1 ,1);
103 //ii aplic sumei din cont rata de schimb
104 lucru *= rata;
105 /*in acest moment al tranzactiei ,
106 adaug cantitatea de bani (convertita)
107 sumei din contul final:
108 actualizez contul final*/
109 moneda2 = octavian :: actualizare(moneda2 ,lucru);
110 /*inchei tranzactia:
111 golesc contul initial */
112 moneda1 = octavian ::
113 actualizare(moneda1 ,
114 - octavian :: stoc_dobanda(moneda1 ,1)
115 );
116 }
117
118 template<typename Unu ,typename Doi>
119 void
120 octavian ::
121 tranzactie(Unu& banca ,Doi& client ,double comision){
122 /*efectuam tranzactii din lei in euro*/
123 banca.actiune(client);
124 std::cout << "\n=======\n"
125 "Buna ziua , domnule/doamna "
126 << client.nume
127 << " !\ nIncepem schimbul valutar ...\n"
128 "Primul cont:\n"
129 << std::endl;
130 octavian :: afis_verificare(client.contlei [0] ,12);
131 std::cout << "\nAl doilea cont:\n"
132 << std::endl;
133 octavian :: afis_verificare(client.conteuro [0] ,12);
134 std::cout << "\nTranzactie...\n"
160
135 << std::endl;
136 octavian :: conversie(client.contlei [0],
137 client.conteuro [0],
138 banca.ratadeschimb[0],
139 comision
140 );
141 std::cout << "\nIncheiat tranzactie!\n"
142 "Rezultate:\ nPrimul cont:\n"
143 << std::endl;
144 octavian :: afis_verificare(client.contlei [0] ,12);
145 std::cout << "\nAl doilea cont:\n"
146 << std::endl;
147 octavian :: afis_verificare(client.conteuro [0] ,12);
148 }
149 /* ---
150 Pentru verificarea specializarilor ,
151 introduceti urmatorul cod:
152 template <typename Unu ,typename Doi >
153 void octavian :: tranzactie(Unu& banca ,
154 Doi& client ,
155 double comision
156 ){
157 ;
158 }
159 template <typename Unu >
160 void octavian :: tranzactie(Unu& banca ,
161 Client& client ,
162 double comision
163 ){
164 ;
165 }
166 Inlocuiti definitia "activa" (vezi deasupra )
167 a functiei tranzactie cu definitia:
168 template <>
169 void octavian :: tranzactie(Banca& banca ,
170 Client& client ,
171 double comision
172 ){
173 // inserati definitia
174 ;
175 }
176 ---*/
177 #endif
161
Sabloane de functii: diverse.h
1 #ifndef _DIVERSE_
2 #define _DIVERSE_
3
4 #include <cstdlib >
5 #include <cstdio >
6 #include <conio.h>
7
8 namespace octavian{
9 void iesire_versiunea2();
10 }
11
12 #endif
Sabloane de functii: diverse.cpp
1 #include "diverse.h"
2 #include <iostream >
3 #include <iomanip >
4
5 void octavian :: iesire_versiunea2(){
6 for (
7 std:: cin.sync(),
8 std:: cin. c lear (),
9 std::cout << "\nApasati ENTER"
10 " pentru a incheia: "
11 << std::endl ,
12 std:: cin. ignore();;
13 ) return;
14 }
Sabloane de functii: euro.cpp
1 #include "tranzactii.h"
2 #include "diverse.h"
3 #include <iostream >
4 #include <iomanip >
5
6 #undef FRAZA_PROVIZORIE_EURO
7 #define FRAZA_PROVIZORIE_EURO(q) \
8 std::cout << "Operatie ilegala: " ## q \
9 << std::endl; \
10 octavian :: iesire_versiunea2(); \
11 exit (EXIT FAILURE);
12
162
13 octavian ::Euro::Euro(){
14 suma = new double[1];
15 suma[0] = double();
16 valuta = new char [1];
17 valuta [0] = ’E’;
18 }
19 octavian ::Euro::Euro(double bani ,char euval){
20 suma = new double[1];
21 suma[0] = bani;
22 valuta = new char [1];
23 valuta [0] = euval;
24 }
25 octavian ::Euro::∼Euro()
26 {
27 delete [] suma;
28 delete [] valuta;
29 }
30 octavian ::Euro::Euro(const octavian ::Euro& euval){
31 suma = new double[1];
32 suma[0] = euval.suma[0];
33 valuta = new char [1];
34 valuta [0] = euval.valuta [0];
35 }
36 octavian ::Euro&
37 octavian ::
38 Euro::operator=( const octavian ::Euro& euval){
39 i f ( th is == &euval) return * th is ;
40 delete [] suma;
41 delete [] valuta;
42 suma = new double[1];
43 suma[0] = euval.suma[0];
44 valuta = new char [1];
45 valuta[0] = euval.valuta [0];
46 return * th is ;
47 }
48 void
49 octavian ::
50 operator+( octavian ::Euro& euval ,double numar){
51 FRAZA_PROVIZORIE_EURO("+ double!")
52 }
53 void
54 octavian ::
55 operator+(double numar ,octavian ::Euro& euval){
163
56 FRAZA_PROVIZORIE_EURO("double +!")
57 }
58 void
59 octavian ::
60 operator -(double numar ,octavian ::Euro& euval){
61 FRAZA_PROVIZORIE_EURO("double -!")
62 }
63 void
64 octavian ::
65 operator -( octavian ::Euro& euval ,double numar){
66 FRAZA_PROVIZORIE_EURO("- double!")
67 }
68 void
69 octavian ::
70 operator*( octavian ::Euro& euval ,double numar){
71 FRAZA_PROVIZORIE_EURO("* double!")
72 }
73 void
74 octavian ::
75 operator*(double numar ,octavian ::Euro& euval){
76 FRAZA_PROVIZORIE_EURO("double *!")
77 }
78 void
79 octavian ::
80 operator/( octavian ::Euro& euval ,double numar){
81 FRAZA_PROVIZORIE_EURO("/ double!")
82 }
83 void
84 octavian ::
85 operator/(double numar ,octavian ::Euro& euval){
86 FRAZA_PROVIZORIE_EURO("double /!")
87 }
88 void
89 octavian ::
90 operator==( octavian ::Euro& val ,
91 octavian ::Euro& euval
92 ){
93 FRAZA_PROVIZORIE_EURO("== Euro!")
94 }
95 octavian ::Euro::operator double(){
96 return suma[0];
97 }
164
Sabloane de functii: lei.cpp
1 #include "tranzactii.h"
2 #include "diverse.h"
3 #include <iostream >
4 #include <iomanip >
5
6 #undef FRAZA_PROVIZORIE_LEI
7 #define FRAZA_PROVIZORIE_LEI(q) \
8 std::cout << "Operatie ilegala: " ## q \
9 << std::endl; \
10 octavian :: iesire_versiunea2(); \
11 exit (EXIT FAILURE);
12
13 octavian ::Lei::Lei(){
14 suma = new double[1];
15 suma[0] = double();
16 valuta = new char [1];
17 valuta [0] = ’R’;
18 }
19 octavian ::Lei::Lei(double bani , char euval){
20 suma = new double[1];
21 suma[0] = bani;
22 valuta = new char [1];
23 valuta [0] = euval;
24 }
25 octavian ::Lei::∼Lei(){
26 delete [] suma;
27 delete [] valuta;
28 }
29 octavian ::Lei::Lei(const octavian ::Lei& euval){
30 suma = new double[1];
31 suma[0] = euval.suma[0];
32 valuta = new char [1];
33 valuta [0] = euval.valuta [0];
34 }
35 octavian ::Lei&
36 octavian ::Lei::operator=( const octavian ::Lei& euval){
37 i f ( th is == &euval) return * th is ;
38 delete [] suma;
39 delete [] valuta;
40 suma = new double[1];
41 suma[0] = euval.suma[0];
42 valuta = new char [1];
165
43 valuta [0] = euval.valuta [0];
44 return * th is ;
45 }
46 void
47 octavian ::
48 operator+( octavian ::Lei& euval ,double numar){
49 FRAZA_PROVIZORIE_LEI("+ double!")
50 }
51 void
52 octavian ::
53 operator+(double numar ,octavian ::Lei& euval){
54 FRAZA_PROVIZORIE_LEI("double +!")
55 }
56 void
57 octavian ::
58 operator -(double numar ,octavian ::Lei& euval){
59 FRAZA_PROVIZORIE_LEI("double -!")
60 }
61 void
62 octavian ::
63 operator -( octavian ::Lei& euval ,double numar){
64 FRAZA_PROVIZORIE_LEI("- double!")
65 }
66 void
67 octavian ::
68 operator*( octavian ::Lei& euval ,double numar){
69 FRAZA_PROVIZORIE_LEI("* double!")
70 }
71 void
72 octavian ::
73 operator*(double numar ,octavian ::Lei& euval){
74 FRAZA_PROVIZORIE_LEI("double *!")
75 }
76 void
77 octavian ::
78 operator/( octavian ::Lei& euval ,double numar){
79 FRAZA_PROVIZORIE_LEI("/ double!")
80 }
81 void
82 octavian ::
83 operator/(double numar ,octavian ::Lei& euval){
84 FRAZA_PROVIZORIE_LEI("double /!")
85 }
166
86 void
87 octavian ::
88 operator==( octavian ::Lei& val ,
89 octavian ::Lei& euval
90 ){
91 FRAZA_PROVIZORIE_LEI("== Lei!")
92 }
93 octavian ::Lei::operator double(){
94 return suma[0];
95 }
Sabloane de functii: banca.cpp
1 #include "tranzactii.h"
2 #include "diverse.h"
3 #include <iostream >
4 #include <iomanip >
5
6 octavian ::Banca::Banca(){
7 clienti = new Client [2];
8 clienti [0] = Client();
9 clienti [1] = Client();
10 dobandaeuro = new double[1];
11 dobandaeuro[0] = 0.23;
12 dobandalei = new double[1];
13 dobandalei[0] = 0.18;
14 ratadeschimb = new double[1];
15 ratadeschimb[0] = 4.8;
16 }
17 octavian ::
18 Banca::
19 Banca(Client cclient1 ,
20 Client cclient2 ,
21 double dobeu ,
22 double dobro ,
23 double rasch
24 ){
25 clienti = new Client [2];
26 clienti [0] = cclient1;
27 clienti [1] = cclient2;
28 dobandaeuro = new double[1];
29 dobandaeuro[0] = dobeu;
30 dobandalei = new double[1];
31 dobandalei[0] = dobro;
167
32 ratadeschimb = new double[1];
33 ratadeschimb[0] = rasch;
34 }
35 octavian ::Banca::Banca(const Banca& bbanca){
36 clienti = new Client [2];
37 clienti [0] = bbanca.clienti [0];
38 clienti [1] = bbanca.clienti [1];
39 dobandaeuro = new double[1];
40 dobandaeuro[0] = bbanca.dobandaeuro[0];
41 dobandalei = new double[1];
42 dobandalei[0] = bbanca.dobandalei[0];
43 ratadeschimb = new double[1];
44 ratadeschimb[0] = bbanca.ratadeschimb[0];
45 }
46 octavian ::Banca&
47 octavian ::
48 Banca::operator=( const Banca& bbanca){
49 i f ( th is == &bbanca) return * th is ;
50 delete [] clienti;
51 delete [] dobandaeuro;
52 delete [] dobandalei;
53 delete [] ratadeschimb;
54 clienti = new Client [2];
55 clienti [0] = bbanca.clienti [0];
56 clienti [1] = bbanca.clienti [1];
57 dobandaeuro = new double[1];
58 dobandaeuro[0] = bbanca.dobandaeuro[0];
59 dobandalei = new double[1];
60 dobandalei[0] = bbanca.dobandalei[0];
61 ratadeschimb = new double[1];
62 ratadeschimb[0] = bbanca.ratadeschimb[0];
63 return * th is ;
64 }
65 octavian ::Banca::∼Banca(){
66 delete [] clienti;
67 delete [] dobandaeuro;
68 delete [] dobandalei;
69 delete [] ratadeschimb;
70 }
71 void
72 octavian ::Banca:: actiune(Client& cclient){
73 octavian :: Client lucru = cclient;
74 i f (( clienti [0] == lucru) == f a l s e )
168
75 i f ((clienti [1] == lucru) == f a l s e ){
76 std::cout << "\n===========\n"
77 "Domnule/Doamna ,\n"
78 "nu sunteti clientul nostru!\n"
79 "La revedere !\n"
80 "=============="
81 << std::endl;
82 octavian :: iesire_versiunea2();
83 exit (EXIT FAILURE);
84 }
85 }
Sabloane de functii: client.cpp
1 #include "tranzactii.h"
2 #include "diverse.h"
3 #include <iostream >
4 #include <iomanip >
5 #include <cstring >
6 #include <errno.h>
7
8 octavian ::Client::Client(){
9 conteuro = new Euro[1];
10 conteuro [0] = Euro();
11 contlei = new Lei[1];
12 contlei [0] = Lei();
13 int numar_intern = s ta t i c cas t < int >(
14 std:: str len ("Popescu")
15 )
16 + 1 /* + 30 */;
17 nume = new char[numar_intern];
18 strcpy s (nume ,numar_intern ,"Popescu");
19 }
20 octavian ::Client::Client(Euro eu,Lei ro, char* nnume){
21 conteuro = new Euro[1];
22 conteuro [0] = eu;
23 contlei = new Lei[1];
24 contlei [0] = ro;
25 int numar_intern = s ta t i c cas t < int >(
26 std:: str len (nnume)
27 )
28 + 1 /* + 30 */;
29 nume = new char[numar_intern];
30 strcpy s (nume ,numar_intern ,nnume);
169
31 }
32 octavian ::Client::∼Client(){
33 delete [] conteuro;
34 delete [] contlei;
35 delete [] nume;
36 }
37 octavian ::
38 Client::
39 Client(const octavian ::Client& cclient){
40 conteuro = new Euro[1];
41 conteuro [0] = cclient.conteuro [0];
42 contlei = new Lei [1];
43 contlei [0] = cclient.contlei [0];
44 int numar_intern = s ta t i c cas t < int >(
45 std:: str len (cclient.nume)
46 )
47 + 1 /* + 30 */;
48 nume = new char[numar_intern];
49 strcpy s (nume ,numar_intern ,cclient.nume);
50 }
51 octavian ::Client&
52 octavian ::
53 Client::
54 operator=( const octavian ::Client& cclient){
55 i f ( th is == &cclient) return * th is ;
56 delete [] conteuro ;
57 delete [] contlei;
58 delete [] nume;
59 conteuro = new Euro[1];
60 conteuro [0] = cclient.conteuro [0];
61 contlei = new Lei [1];
62 contlei [0] = cclient.contlei [0];
63 int numar_intern = s ta t i c cas t < int >(
64 std:: str len (cclient.nume)
65 )
66 + 1 /* + 30 */;
67 nume = new char[numar_intern];
68 strcpy s (nume ,numar_intern ,cclient.nume);
69 return * th is ;
70 }
71 bool
72 octavian ::
73 operator==( Client& client1 ,Client& client2){
170
74 i f (
75 std::strcmp(client1.nume ,client2.nume) != 0
76 )
77 return f a l s e ;
78 return true;
79 }
Program:> In proiectul VS de fata construim o lista simpla. Chestiunea listelor esteuna fundamentala pentru manipularea sirurilor de obiecte. Exemple de listese gasesc ın [20, p. 144], [22, p. 356 si urm.] si [41, pg. 333, 403]. Lista deaici poate fi imaginata ca un lantisor caruia nu i-a fost (ınca) atasat niciunpandantiv. Lista — goala — contine doua adrese, cap si coada, ce cores-pund celor doua mici piese metalice care alcatuiesc ıncuietoarea lantisorului.Obiectele ce urmeaza sa fie atasate listei trebuie “pregatite”; exact la fel cumun pandantiv are nevoie de o toarta pentru a fi agatat de lantisor. Toarta ıncauza este o adresa, numita cheie.
Implementarea functiei octavian::iesire se gaseste la pagina 104.
O lista de obiecte: program.cpp
1 #include "diverse.h"
2 #include "lista1.h"
3 #include <iostream >
4 #include <iomanip >
5
6 int main(){
7 system("cls");
8 /*---
9 Pregatim obiecte pentru
10 introducerea in lista:
11 au toate "adresa standard ".
12 ---*/
13 octavian :: ObiectLista ob;
14 octavian :: ObiectLista ob_unu(23,ob);
15 octavian :: ObiectLista ob_doi(54,ob);
16 octavian :: ObiectLista ob_trei (124,ob);
17 octavian :: ObiectLista ob_patru (32,ob);
18 octavian :: ObiectLista ob_cinci (176,ob);
19 octavian :: Lista lst;
20 std::cout << "\n++++++++"
21 "Incepem lista:"
22 << std::endl;
23 (lst.adaug_la_coada)(ob_unu);
24 (lst.adaug_la_coada)(ob_doi);
171
25 (lst.adaug_la_coada)(ob_trei);
26 (lst.adaug_la_coada)(ob_patru );
27 (lst.adaug_la_coada)(ob_cinci );
28 std::cout << "\n++++++++"
29 "S-a incheiat lista!"
30 << std::endl;
31 octavian :: listare(lst);
32 /*---
33 Primele doua "ObiectLista" vor fi sterse
34 din lista , iar adresele inmagazinate in
35 ele vor fi "eliberate".
36 ---*/
37 lst.sterg_la_cap();
38 lst.sterg_la_cap();
39 octavian :: listare(lst);
40 octavian :: iesire();
41 return 0;
42 }
O lista de obiecte: lista1.h
1 #ifndef _LISTA1_
2 #define _LISTA1_
3
4 namespace octavian{
5 c la s s ObiectLista{
6 int numar;
7 ObiectLista* cheie;
8 public :
9 ObiectLista();
10 ObiectLista( int ,ObiectLista&);
11 ∼ObiectLista();
12 operator double();
13 void afis_numar() const;
14 void afis_cheie() const;
15 int intorc_numar() const;
16 ObiectLista* intorc_cheie() const ;
17 void sterg_cheie();
18 void scriu_cheie(ObiectLista&);
19 void test_invariant();
20 };
21 c la s s Lista{
22 fr iend void listare(Lista&);
23 ObiectLista* cap;
172
24 ObiectLista* coada;
25 public :
26 Lista();
27 ∼Lista();
28 void adaug_la_coada(ObiectLista&);
29 void sterg_la_cap();
30 bool e_goala () const;
31 };
32 }
33 #endif
O lista de obiecte: lista1.cpp
1 #include "diverse.h"
2 #include "lista1.h"
3 #include <iostream >
4 #include <iomanip >
5
6 octavian ::
7 ObiectLista:: ObiectLista(){
8 numar = 0; cheie = 0;
9 }
10 octavian ::
11 ObiectLista::
12 ObiectLista( int nnumar ,ObiectLista& objlst) :
13 numar(nnumar), cheie(&objlst) {}
14 void
15 octavian ::
16 ObiectLista:: afis_numar() const{
17 std::cout << "\nNumarul este: "
18 << numar;
19 std::cout. f lush ();
20 }
21 void
22 octavian ::
23 ObiectLista:: afis_cheie() const{
24 std::cout << "\nAdresa este: "
25 << (void*) cheie;
26 std::cout. f lush ();
27 }
28 int
29 octavian ::
30 ObiectLista:: intorc_numar() const{
31 return numar;
173
32 }
33 octavian :: ObiectLista*
34 octavian :: ObiectLista:: intorc_cheie() const{
35 return cheie;
36 }
37 octavian :: ObiectLista::∼ObiectLista(){
38 numar = 0; cheie = 0;
39 }
40 octavian :: ObiectLista::operator double(){
41 // recuperarea numarului:
42 return numar;
43 }
44 void octavian :: ObiectLista:: sterg_cheie(){
45 cheie = 0;
46 }
47 void
48 octavian ::
49 ObiectLista:: scriu_cheie(ObiectLista& objlst){
50 cheie = &objlst;
51 }
52 void octavian :: ObiectLista:: test_invariant(){
53 /* ---
54 Daca este bine definit ca "obiect din lista",
55 un obiect va avea la campul cheie adresa unei
56 instante ObiectLista construite cu construc -
57 torul fara argumente!
58 ---*/
59 ObiectLista* ob_intern = cheie ->intorc_cheie();
60 i f (ob_intern != 0){
61 pr int f s ("\nObiectul care contine "
62 "numarul %d\nnu este corect "
63 "formatat pentru inserarea "
64 "in lista!\ nInchei ...",
65 numar
66 );
67 octavian :: iesire();
68 exit (EXIT FAILURE);
69 }
70 }
71 octavian ::Lista::Lista(){
72 cap = coada = 0;
73 }
74 octavian ::Lista::∼Lista(){
174
75 cap = coada = 0;
76 }
77 bool octavian ::Lista:: e_goala () const{
78 return coada == 0 ? true : f a l s e ;
79 }
80 void
81 octavian ::
82 Lista::
83 adaug_la_coada(ObiectLista& objlst){
84 //testez obiectul :
85 objlst.test_invariant();
86 i f (e_goala ()){
87 coada = &objlst;
88 pr int f s ("\nAdaug: %d\n",
89 coada ->intorc_numar()
90 );
91 return;
92 }
93 i f (cap==0){
94 cap = coada;
95 (cap ->scriu_cheie)(objlst);
96 coada = &objlst;
97 pr int f s ("\nAdaug: %d\n",
98 coada ->intorc_numar()
99 );
100 return;
101 }
102 (coada ->scriu_cheie)(objlst);
103 coada = &objlst;
104 pr int f s ("\nAdaug: %d\n",
105 coada ->intorc_numar()
106 );
107 }
108 void octavian ::Lista:: sterg_la_cap(){
109 i f (e_goala ()){
110 pr int f s ("\nNimic de sters!");
111 return;
112 }
113 i f (cap==0){
114 pr int f s ("\nLista are un singur "
115 "element: il sterg...\n"
116 );
117 coada ->sterg_cheie();
175
118 return;
119 }
120 octavian :: ObiectLista*
121 ob_intern = cap ->intorc_cheie();
122 i f (ob_intern == 0){
123 pr int f s ("\nCiudat ...\n");
124 return;
125 }
126 i f (ob_intern ->intorc_cheie() == 0){
127 pr int f s ("\nSuntem la ultimul element:"
128 " il sterg..."
129 "\nValoarea sa inainte de "
130 "stergere : %d\n",
131 cap ->intorc_numar()
132 );
133 cap ->sterg_cheie();
134 // curat lista:
135 cap = coada = 0;
136 return;
137 }
138 pr int f s ("\nSterg ...\n");
139 cap ->sterg_cheie();
140 cap = ob_intern;
141 pr int f s ("\nCapul: %d\n",cap ->intorc_numar());
142 }
143 void octavian :: listare(Lista& llista){
144 Lista* lis = &llista;
145 i f (lis ->e_goala ()){
146 pr int f s ("\nLista este goala!\ nNimic "
147 "de listat ...\n"
148 );
149 return;
150 }
151 i f (lis ->cap == 0){
152 pr int f s ("\nLista are doar un singur "
153 "obiect!\nIl listam ...\n"
154 );
155 (lis ->coada)->afis_numar();
156 return;
157 }
158 // Obiectele din lista sunt BINE formatate!
159 octavian :: ObiectLista* ob_intern =lis ->cap;
160 for (; ob_intern != lis->coada;
176
161 ob_intern = ob_intern ->intorc_cheie()
162 ){
163 (ob_intern)->afis_numar();
164 (ob_intern)->afis_cheie();
165 }
166 (lis ->coada)->afis_numar();
167 }
Program:> Reluam proiectul listei anterioare, folosind ınsa mecanismul sabloanelor.
O lista<T> de obiecte: program.cpp
1 #include <cstdlib >
2 #include <cstdio >
3 #include <conio.h>
4 #include "sabloane.h"
5 #include "sabloane.cpp"
6 #include "diverse.h"
7 #include <iostream >
8 #include <iomanip >
9 using namespace octavian ;
10
11 int main(){
12 system("cls");
13 ObiectLista <char > ob;
14 ObiectLista <char > ob_unu(’a’,ob);
15 ObiectLista <char > ob_doi(’w’,ob);
16 ObiectLista <char > ob_trei(’9’,ob);
17 ObiectLista <char > ob_patru (’g’,ob);
18 ObiectLista <char > ob_cinci (’k’,ob);
19 Lista <char > lst;
20 (lst.adaug_la_coada)(ob_unu);
21 (lst.adaug_la_coada)(ob_doi);
22 (lst.adaug_la_coada)(ob_trei);
23 (lst.adaug_la_coada)(ob_patru);
24 (lst.adaug_la_coada)(ob_cinci);
25 lst.listare ();
26 lst.sterg_la_cap();
27 lst.sterg_la_cap();
28 lst.listare ();
29 char ss = char(ob_cinci );
30 pr int f s ("\n%c",ss);
31 iesire();
32 return 0;
33 }
177
O lista<T> de obiecte: sabloane.h
1 #ifndef _SABLOANE_
2 #define _SABLOANE_
3 #include <iostream >
4 #include <iomanip >
5 namespace octavian{
6 template<typename Tip > c la s s Lista;
7 template<typename Tip > c la s s ObiectLista{
8 fr iend c la s s Lista <Tip >;
9 public :
10 ObiectLista();
11 ObiectLista(const Tip&,ObiectLista <Tip >&);
12 ObiectLista(const ObiectLista <Tip >&);
13 ObiectLista <Tip >&
14 operator=( const ObiectLista <Tip >&);
15 ∼ObiectLista();
16 operator Tip();
17 void afis_numar() const ;
18 void afis_cheie() const ;
19 Tip intorc_numar() const;
20 ObiectLista <Tip >* intorc_cheie() const ;
21 void sterg_cheie();
22 void scriu_cheie(ObiectLista <Tip >&);
23 void test_invariant();
24 private:
25 Tip numar;
26 ObiectLista <Tip >* cheie;
27 };
28 template<typename Tip > c la s s Lista{
29 ObiectLista <Tip >* cap;
30 ObiectLista <Tip >* coada;
31 public :
32 Lista();
33 ∼Lista();
34 void adaug_la_coada(ObiectLista <Tip >&);
35 void sterg_la_cap();
36 bool e_goala () const;
37 void listare () const;
38 };
39 }
40 #endif
178
O lista<T> de obiecte: sabloane.cpp
1 #ifndef _SABLOANE1_
2 #define _SABLOANE1_
3 #include <iostream >
4 #include <iomanip >
5 #include "sabloane.h"
6 #include "diverse.h"
7 using namespace std;
8 using namespace octavian ;
9
10 #undef CAND_TIP_ESTE_NUMAR
11 #define CAND_TIP_ESTE_NUMAR 1
12 #undef CAND_TIP_ESTE_NUMAR
13
14 template<typename Tip > ObiectLista <Tip >:: ObiectLista()
15 : numar(Tip())
16 {
17 cheie = 0;
18 }
19 template<typename Tip > ObiectLista <Tip >::
20 ObiectLista(const Tip& nnum ,
21 ObiectLista <Tip >& objlst)
22 : numar(nnum)
23 {
24 cheie = &objlst;
25 }
26 template <typename Tip > ObiectLista <Tip >::
27 ObiectLista(const ObiectLista <Tip >& objlst)
28 : numar(objlst.numar)
29 {
30 cheie = objlst.cheie;
31 }
32 template<typename Tip > ObiectLista <Tip >&
33 ObiectLista <Tip >::
34 operator=( const ObiectLista <Tip >& objlst){
35 i f ( th is == &objlst) return * th is ;
36 numar = objlst.numar;
37 return * th is ;
38 }
39 template<typename Tip > ObiectLista <Tip >::∼ObiectLista()
40 {
41 numar = Tip(); cheie = 0;
42 }
179
43 template<typename Tip > void ObiectLista <Tip >::
44 afis_numar() const {
45 std::cout << "\nNumarul este: "
46 << numar;
47 std::cout. f lush ();
48 }
49 template<typename Tip > void ObiectLista <Tip >::
50 afis_cheie() const {
51 std::cout << "\nAdresa este: "
52 << (void*) cheie;
53 std::cout. f lush ();
54 }
55 template<typename Tip > Tip ObiectLista <Tip >::
56 intorc_numar() const{
57 return numar;
58 }
59 template<typename Tip > void ObiectLista <Tip >::
60 sterg_cheie(){
61 cheie = 0;
62 }
63 template<typename Tip > ObiectLista <Tip >*
64 ObiectLista <Tip >:: intorc_cheie() const{
65 return cheie;
66 }
67 template<typename Tip >
68 ObiectLista <Tip >::operator Tip(){
69 return numar;
70 }
71 template<typename Tip >
72 void ObiectLista <Tip >:: test_invariant(){
73 ObiectLista <Tip >*
74 ob_intern = cheie ->intorc_cheie();
75 i f (ob_intern != 0){
76 pr int f s ("\nObiectul care contine "
77 "numarul "
78 #i fd e f CAND_TIP_ESTE_NUMAR
79 "%d"
80 #endif
81 "\nnu este corect "
82 "formatat pentru inserarea "
83 "in lista!\ nInchei ..."
84 #i fd e f CAND_TIP_ESTE_NUMAR
85 ,
180
86 numar
87 #endif
88 );
89 octavian ::iesire();
90 exit (EXIT FAILURE);
91 }
92 }
93 template<typename Tip >
94 void ObiectLista <Tip >::
95 scriu_cheie(ObiectLista <Tip >& objlst){
96 cheie = &objlst;
97 }
98 template<typename Tip > Lista <Tip >:: Lista(){
99 cap = 0; coada = 0;
100 }
101 template<typename Tip >
102 Lista <Tip >::∼Lista(){
103 cap = coada = 0;
104 }
105 template<typename Tip >
106 bool octavian ::Lista <Tip >:: e_goala () const{
107 return coada == 0 ? true : f a l s e ;
108 }
109 template<typename Tip >
110 void octavian ::Lista <Tip >::
111 adaug_la_coada(ObiectLista <Tip >& objlst){
112 // testez obiectul :
113 objlst.test_invariant();
114 i f (e_goala ()){
115 coada = &objlst;
116 #i fd e f CAND_TIP_ESTE_NUMAR
117 pr int f s ("\nAdaug: %d\n",
118 coada ->intorc_numar()
119 );
120 #endif
121 return;
122 }
123 i f (cap==0){
124 cap = coada;
125 (cap ->scriu_cheie)(objlst);
126 coada = &objlst;
127 #i fd e f CAND_TIP_ESTE_NUMAR
128 pr int f s ("\nAdaug: %d\n",
181
129 coada ->intorc_numar()
130 );
131 #endif
132 return;
133 }
134 (coada ->scriu_cheie)(objlst);
135 coada = &objlst;
136 #i fd e f CAND_TIP_ESTE_NUMAR
137 pr int f s ("\nAdaug: %d\n",
138 coada ->intorc_numar()
139 );
140 #endif
141 }
142 template<typename Tip >
143 void octavian ::Lista <Tip >:: sterg_la_cap(){
144 i f (e_goala ()){
145 pr int f s ("\nNimic de sters!");
146 return;
147 }
148 i f (cap==0){
149 pr int f s ("\nLista are un singur "
150 "element: il sterg...\n"
151 );
152 coada ->sterg_cheie();
153 return;
154 }
155 octavian :: ObiectLista <Tip >*
156 ob_intern = cap ->intorc_cheie();
157 i f (ob_intern == 0){
158 pr int f s ("\nCiudat ...\n");
159 return;
160 }
161 i f (ob_intern ->intorc_cheie() == 0){
162 pr int f s ("\nSuntem la ultimul element:"
163 " il sterg..."
164 #i fd e f CAND_TIP_ESTE_NUMAR
165 "\nValoarea sa inainte de "
166 "stergere : %d\n",
167 cap ->intorc_numar()
168 #endif
169 );
170 cap ->sterg_cheie();
171 //curat lista:
182
172 cap = coada = 0;
173 return;
174 }
175 pr int f s ("\nSterg ...\n");
176 cap ->sterg_cheie();
177 cap = ob_intern;
178 #i fd e f CAND_TIP_ESTE_NUMAR
179 pr int f s ("\nCapul: %d\n",cap ->intorc_numar());
180 #endif
181 }
182 template<typename Tip >
183 void octavian ::Lista <Tip >::
184 listare () const{
185 Lista <Tip >*
186 lis = const cast <Lista <Tip >*>( th is );
187 i f (lis ->e_goala ()){
188 pr int f s ("\nLista este goala!\nNimic "
189 "de listat ...\n"
190 );
191 return;
192 }
193 i f (lis ->cap == 0){
194 pr int f s ("\nLista are doar un singur "
195 "obiect!\nIl listam ...\n"
196 );
197 (lis->coada)->afis_numar();
198 return;
199 }
200 // Obiectele din lista sunt BINE formatate!
201 octavian ::ObiectLista <Tip >* ob_intern =lis ->cap;
202 for (; ob_intern != lis ->coada;
203 ob_intern = ob_intern ->intorc_cheie()
204 ){
205 (ob_intern)->afis_numar();
206 (ob_intern)->afis_cheie();
207 }
208 (lis ->coada)->afis_numar();
209 }
210 #endif
Program:> In anumite situatii, este bine sa “prevenim” compilatorul ca utilizam unoperator–sablon, cf. [41, p. 855].
183
Operatori–sablon: program.cpp
1 #include <cstdio >
2 #include <cstdlib >
3 #include <conio.h>
4 #include <iostream >
5 #include <iomanip >
6 #include "sabloane.h"
7 #include "sabloane.cpp"
8
9 int main(){
10 Numere <double > nn = 23.4;
11 std::cout << nn << std::endl;
12 getch();
13 return 0;
14 }
Operatori–sablon: sabloane.h
1 #ifndef _SABLOANE_
2 #define _SABLOANE_
3
4 using namespace std;
5 template<typename T> c la s s Numere{
6 /* ---
7 Folosim una din declaratiile de mai jos
8 pentru a informa compilatorul ca avem
9 un operator -sablon:
10 ---*/
11 fr iend ostream& operator << <T>(ostream&,Numere&);
12 //friend ostream& operator << <>(ostream&,Numere <T>&);
13 T numar;
14 public :
15 T afis();
16 Numere(T);
17 };
18 #endif
Operatori–sablon: sabloane.cpp
1 #ifndef _SABLOANE1_
2 #define _SABLOANE1_
3 #include <iostream >
4 #include <iomanip >
5 #include "sabloane.h"
6
184
7 using namespace std;
8 template<typename T>
9 T Numere <T>::afis(){
10 return numar;
11 }
12 template<typename T>
13 Numere <T>:: Numere(T nnt){
14 numar = nnt;
15 }
16 template<typename T>
17 ostream&
18 operator << (ostream& os,Numere <T>& nnum){
19 T sd = nnum.afis();
20 os << sd;
21 os. f lush ();
22 return os;
23 }
24 #endif
Program:> (Intro STL) Cu ajutorul algoritmului find [41, p. 525], depistam daca unnumar ıntreg se gaseste ıntr-un sir dat de numere.
Intro STL, algoritmul find: program.cpp
1 #include <conio.h>
2 #include <cstdlib >
3 #include <cstdio >
4 #include <cstring >
5 #include <iostream >
6 #include <vector >
7 #include <string >
8 #include <algorithm >
9
10 void cautare_numar( std::vector < int >& vect ,
11 int num){
12 std::vector < int >:: i terator
13 p = f ind (vect.begin(),vect.end(),num);
14 i f (p != vect.end())
15 std::cout << "Gasit!"
16 << std::endl;
17 e l se
18 std::cout << "N-am gasit!"
19 << std::endl;
20 }
21
185
22 int main(){
23 system("cls");
24 std::vector < int > secventa;
25 secventa .push back (12);
26 secventa .push back (34);
27 secventa .push back(-3);
28 secventa .push back(1);
29 secventa .push back (37);
30 std::cout << "Scrieti un numar intreg:"
31 << std::endl;
32 std:: str ing numar;
33 std:: cin >> numar;
34 cautare_numar(secventa , std:: atoi (numar. c s t r ()));
35 getch();
36 return 0;
37 }
Program:> (Intro STL) Fluxurile std::stringstream74 din <sstream> [41, p. 640] seataseaza datelor de tip std::string pentru ca utilizatorul sa poata opera cuacestea din urma ca si cum ele ar fi fluxuri. Cu ajutorul iteratorilor de sensinvers75, ın programul de fata, preluam un rand de cuvinte de la consola siapoi afisam intrarile “de la dreapta la stanga”.
Intro STL, fluxuri la string, iteratori: program.cpp
1 #include <cstdlib >
2 #include <cstdio >
3 #include <conio.h>
4 #include <iostream >
5 #include <sstream >
6 #include <vector >
7 #include <string >
8 using namespace std;
9
10 int main(){
11 system("cls");
12 cout << "Scrieti un rand:"
13 << endl;
14 str ing text;
15 get l ine (cin ,text);
16 stringstream sir(text);
17 vector < string > cuvinte;
74Un stringstream este un std::basic_stringstream<char>, cf. [41, p. 641].75 In limba engleza, reverse iterators [41, pg. 443, 557].
186
18 str ing cuvant;
19 while(sir >> cuvant)
20 cuvinte.push back(cuvant);
21 cout << "\nElemente stanga - dreapta:"
22 "\n====="
23 << endl;
24 for (vector < string >:: i terator
25 p = cuvinte.begin();
26 p != cuvinte.end();
27 p++
28 )
29 cout << *p << endl;
30 cout << "Elemente dreapta - stanga:"
31 "\n====="
32 << endl;
33 for (vector < string >:: reverse i terator
34 p = cuvinte. rbegin();
35 p != cuvinte.rend();
36 p++
37 )
38 cout << *p << endl;
39 getch();
40 return 0;
41 }
Program:> (Intro STL) Cu ajutorul functiei–membru insert [41, p. 452] a containe-rului76 std::vector<T>, introducem litere ıntr-un cuvant dat.
Intro STL, inserare ıntr-un container: program.cpp
1 #include <cstdlib >
2 #include <cstdio >
3 #include <conio.h>
4 #include <iostream >
5 #include <iomanip >
6 #include <vector >
7 #include <string >
8 using namespace std;
9
10 int main(){
11 system("cls");
12 char cuv[] = "stereotip";
13 vector <char > cuvant;
76 In limba engleza, container [18, p. 912].
187
14 typedef vector <char >:: i terator numarator;
15 cuvant. assign (cuv ,&cuv[ s i z eo f (cuv) -1]);
16 for (numarator n = cuvant.begin();
17 n != cuvant.end();
18 n++
19 )
20 cout << *n << endl;
21 cout << "====" << endl;
22 vector <char > info;
23 info.push back(’y’);
24 info.push back(’x’);
25 cuvant. insert (cuvant.begin()+4,
26 info.begin(),
27 info.end()
28 );
29 for (numarator n = cuvant.begin();
30 n != cuvant.end();
31 n++
32 )
33 cout << *n;
34 cout << endl;
35 getch();
36 return 0;
37 }
Program:> (Intro STL) Folosim, ın continuare, containerul std::list<T> [41, p. 470]pentru a implementa un “editor de text”, care sa organizeze intrarile subforma de randuri afisate ın consola.
Intro STL, containerul std::list<T>: program.cpp
1 /* ---
2 Copyright:
3 Inspirat de (Closely following)
4 "C++, Special Edition" by B. Stroustrup
5 ---*/
6 #include <cstdlib >
7 #include <cstdio >
8 #include <conio.h>
9 #include <iostream >
10 #include <iomanip >
11 #include <vector >
12 #include <string >
13 #include <list >
14 using namespace std;
188
15
16 typedef vector <char > linie;
17 // constructia unui iterator :
18 c la s s numarator{
19 public :
20 numarator( l i s t <linie >:: i terator lln ,
21 linie:: i terator ppoz
22 ) : ln(lln), poz(ppoz){}
23 char& operator*(){return *poz;}
24 numarator& operator ++();
25 bool
26 operator==( const numarator& alt) const{
27 return (ln == alt.ln && poz == alt.poz);
28 }
29 bool
30 operator!=( const numarator& alt) const{
31 return !(* th is == alt);
32 }
33 private:
34 l i s t <linie >:: i terator ln;
35 linie:: i terator poz;
36 };
37 numarator&
38 numarator::operator++(){
39 ++poz;
40 i f (poz == (*ln).end()){
41 ++ln;
42 poz=(*ln).begin();
43 }
44 return * th is ;
45 }
46 //un document :
47 struct Document {
48 l i s t <linie > lin;
49 numarator inceput (){
50 return numarator(lin.begin(),
51 (*(lin.begin())).begin()
52 );
53 }
54 numarator sfarsit (){
55 l i s t <linie >:: i terator last =lin.end();
56 --last;
57 return numarator(last ,(* last).end() -1);
189
58 }
59 };
60 void tipar(Document & doc){
61 for (numarator p = doc.inceput ();
62 p != doc.sfarsit ();
63 ++p
64 )
65 cout << *p;
66 }
67
68 int main(){
69 system("cls");
70 linie unu;
71 unu.push back(’A’);
72 unu.push back(’n’);
73 unu.push back(’a’);
74 unu.push back(’\n’);
75 linie doi;
76 doi.push back(’a’);
77 doi.push back(’r’);
78 doi.push back(’e’);
79 doi.push back(’\n’);
80 linie trei;
81 trei.push back(’m’);
82 trei.push back(’e’);
83 trei.push back(’r’);
84 trei.push back(’e’);
85 trei.push back(’.’);
86 //linie de final:
87 linie patru;
88 patru.push back(’\n’);
89 cout << "Teste:\nAfisare prima linie:"
90 << endl;
91 for (linie:: i terator x = unu.begin();
92 x != unu.end();
93 ++x
94 )
95 cout << *x;
96 cout << "+++" << endl;
97 Document doc;
98 doc.lin.push back(unu);
99 doc.lin.push back(doi);
100 doc.lin.push back(trei);
190
101 doc.lin.push back(patru);
102 cout << "Incepem documentul:\n======"
103 << endl;
104 tipar(doc);
105 cout << "\n====\ nIncheiat documentul!"
106 << endl;
107 getch();
108 return 0;
109 }
Program:> (Intro STL) Aici implementam o clasa de obiecte–functie si le folosim capredicate [41, p. 515] ıntr-o sortare [41, p. 539].
Intro STL, obiecte–functie, predicate, sortari: program.cpp
1 #include <cstdlib >
2 #include <cstdio >
3 #include <conio.h>
4 #include <iostream >
5 #include <iomanip >
6 #include <vector >
7 #include <string >
8 #include <algorithm >
9 using namespace std;
10
11 // constructia unui obiect -functie:
12 c la s s CuTel{
13 fr iend
14 ostream& operator <<(ostream& os, const CuTel&);
15 public :
16 CuTel() : am_tel(’N’){}
17 exp l i c i t CuTel(char aam_tel) :
18 am_tel(aam_tel){}
19 // operatorul de apel:
20 bool operator()(char aam_tel) const{
21 return (aam_tel == ’D’);
22 }
23 CuTel& operator=( const CuTel& alt){
24 i f ( th is == &alt) return * th is ;
25 am_tel = alt.am_tel;
26 return * th is ;
27 }
28 CuTel(const CuTel& alt) :
29 am_tel(alt.am_tel){}
30 ∼CuTel(){am_tel = char();}
191
31 char citesc() const {
32 return am_tel;
33 }
34 private:
35 char am_tel;
36 };
37 ostream& operator <<(ostream& os,const CuTel& ct){
38 return (os << ct.am_tel);
39 }
40 struct Inreg{
41 str ing nume;
42 CuTel tel;
43 };
44 ostream& operator << (ostream& os,
45 const Inreg& intrare
46 ){
47 os << "\n====\ nNume abonat:\t"
48 << intrare.nume
49 << "\nAre tel:\t"
50 << intrare.tel;
51 CuTel ss = intrare.tel;
52 // folosim operatorul de apel pt. ss:
53 i f (ss(ss.citesc()))
54 os << "\nAre telefon!";
55 os. f lush ();
56 return os;
57 }
58 //obiect -functie:
59 struct CompNum{
60 bool operator()(const Inreg& unu ,
61 const Inreg& doi) const{
62 return (unu.nume < doi.nume);
63 }
64 };
65
66 int main(){
67 vector <Inreg > lista_tel;
68 CuTel aretel(’D’);
69 Inreg Popescu;
70 Popescu.nume = "Ion Popescu";
71 Popescu.tel = aretel;
72 lista_tel.push back(Popescu);
73 Inreg Ionescu;
192
74 Ionescu.nume = "Maria Ionescu";
75 Ionescu.tel;
76 lista_tel.push back(Ionescu);
77 Inreg Petrescu;
78 Petrescu .nume = "Camil Petrescu ";
79 Petrescu .tel = aretel;
80 lista_tel.push back(Petrescu);
81 //sortare cu predicatul "CompNum ":
82 sort (lista_tel.begin(),lista_tel.end(),CompNum ());
83 for (vector <Inreg >:: i terator p = lista_tel.begin();
84 p != lista_tel.end();
85 ++p
86 ){
87 cout << *p << endl;
88 }
89 getch();
90 return 0;
91 }
Program:> (Intro IHP 77) Urmatoarea afirmatie, “Ursul Panda e un urs!” [22, p. 395],introduce un nou tip de relatie ıntre clasa Panda si clasa Urs, si anume relatiaeste–un78. Reamintesc tehnica de populare79 a obiectelor unei clase cu sub-obiecte din alte clase, ceea ce conduce la relatiile are–un — vezi pagina 129—. Noul mecanism C++ se numeste derivare80 (a claselor) si permite punereaın practica a unei idei esentiale a OO, mostenirea81. Adica, ursul Panda“mosteneste” toate trasaturile unui urs82.
In proiectul de fata implementam o mostenire public, plecand de la clasade baza83 octavian::Numar si ajungand la clasa derivata octavian::Numar
CuSemn.O problema tehnica ın cadrul mostenirii priveste rescrierea84 functiilor–
membru care pastreaza numele, semnatura si tipul datelor de ıntoarcere (dela clasa de baza85) [41, p. 305], [22, p. 402]. Pentru a evita aceasta dificul-
77Adica, Inheritance — mostenire —, Hierarchies — ierarhii de clase —, Polymorphism— polimorfism —.
78 In limba engleza, is–a relationship, cf. [22, p. 414].79Numita si compunere. In limba engleza, composition [22, p. 415] ori containment [41,
p. 740].80 In limba engleza, (class) derivation [22, pg. 391, 394].81 In limba engleza, inheritance.82 In plus, este “simpatic”. . .83 In limba engleza, base class [22, ibid.].84Ori suprascrierea. In limba engleza, overriding [41, p. 311].85Un exemplu imediat este oferit chiar de. . . ursi! Fie ca este Panda ori brun, orice urs
193
tate, utilizam functii–membru virtuale — apelate prin pointeri sau referintela o baza public, cf. [22, p. 445] —, ce “stiu” sa o aleaga dintre functi-ile–membru identice ale (obiectului) unei clase derivate, vezi [22, p. 450],pe aceea care apartine ın mod direct clasei obiectului implicat ın executiacurenta86. Tipurile de date cu functii virtuale constituie tipuri polimorfe,vezi [41, p. 312]. Pentru a “tine minte” aceste corespondente clasa derivata –functie-membru, de obicei compilatorul va converti numele functiei virtualeıntr-o intrare ın tabela (tabelul) functiei virtuale — vtbl —, formata dinpointeri la functii, cf. [41, pg. 36, 420].
Alta chestiune interesanta se refera la ordinea executiei constructorilor,respectiv destructorilor pentru obiectele unor clase implicate ın relatii are–un, este–un. La liniile 286–290 din codul fisierului format_afisare.cpp, dela pagina 71, am comentat ordinea apelarii destructorilor ın relatia are–un.Lucrurile stau la fel ın cazul mecanismului derivarii: ıntai se executa des-tructorul clasei derivate, apoi cel al clasei de baza [41, p. 307]. De altminteri,pentru o corecta apelare a lor, destructorii ıntr-o ierarhie sunt virtuali [22,p. 457], [41, p. 319] — ca sa obtinem acest efect, este suficient sa etichetamvirtual destructorul clasei de baza —. Voi introduce destructori virtualiın urmatorul proiect VS. Aici, destructorul clasei derivate va fi sintetizat decompilator.
Fireste, pot fi implementati operatori virtual [22, pg. 480, 481], dar nusi constructori virtuali87 [41, p. 424].
Cuvantul cheie protected desemneaza membrii clasei care sunt inaccesi-bili unui apelant obisnuit ınsa pot fi accesati de catre functiile–membru aleclasei care deriva din clasa ın cauza [41, pg. 305, 402, 406].
Intro IHP, functii virtuale: program.cpp
1 #include <cstdlib >
2 #include <cstdio >
3 #include <conio.h>
4 #include "ierarhie.h"
5 int main(){
6 {// pentru evidentierea destructorilor
7 octavian :: NumarCuSemn a( -1.13);
8 octavian ::Numar b(45);
are gheare, deci admite functia urs::sfasie!86Spunem ca functiile virtuale realizeaza legari dinamice sau legari la executie [18, p.
816]. In limba engleza, dynamic binding [22, p. 446] sau run-time binding [41, p. 724].87Un constructor nu poate fi virtual pentru ca trebuie sa “stie” ce construieste la mo-
mentul compilarii. Putem ınsa “mima” un asemenea comportament din partea obiectelorclasei, introducand o clasa fabrica [41, p. 323], cu functii–membru virtuale care sa seocupe de constructia obiectelor.
194
9 octavian ::Numar* cautare;
10 cautare = &a;
11 cautare ->citire();
12 a.citire2 ();
13 cautare = &b;
14 cautare ->citire();
15 }
16 getch();
17 return 0;
18 }
Intro IHP, functii virtuale: ierarhie.h
1 #ifndef _IERARHIE_
2 #define _IERARHIE_
3
4 namespace octavian{
5 c la s s Numar{
6 public :
7 Numar();
8 exp l i c i t Numar(double);
9 Numar(const Numar&);
10 Numar& operator=( const Numar&);
11 ∼Numar();
12 double citire_numar() const ;
13 void scriere_numar(double);
14 virtua l void citire() const ;
15 s t a t i c int citesc_contor();
16 protected:
17 void citire_departata() const;
18 private:
19 double numar_real;
20 s t a t i c int contor_distrugere;
21 };
22 c la s s NumarCuSemn : public Numar {
23 public :
24 NumarCuSemn();
25 exp l i c i t NumarCuSemn(double);
26 NumarCuSemn(const NumarCuSemn&);
27 NumarCuSemn& operator=( const NumarCuSemn&);
28 void citire() const ;
29 void citire2 () const;
30 private:
31 bool pozitiv;
195
32 };
33 }
34 #endif
Intro IHP, functii virtuale: ierarhie.cpp
1 #include "ierarhie.h"
2 #include <conio.h>
3 #include <iostream >
4 #include <iomanip >
5 using namespace octavian ;
6
7 #undef ACTIUNE
8 #define ACTIUNE \
9 pr int f s ("\nSuntem in constructorul de baza!"); \
10 i f (contor_distrugere++ == 100){ \
11 pr int f s ("\n++++++++\n" \
12 "Prea multe obiecte " \
13 "din clasa de baza...\n" \
14 ); \
15 getch(); \
16 exit (EXIT FAILURE); \
17 }
18
19 int Numar:: contor_distrugere = 0;
20 int Numar:: citesc_contor(){
21 return Numar:: contor_distrugere;
22 }
23 Numar::Numar() :
24 numar_real(double()) { ACTIUNE }
25 Numar::Numar(double nnum) :
26 numar_real(nnum) { ACTIUNE }
27 Numar::Numar(const Numar& nnumar) :
28 numar_real(nnumar.numar_real) { ACTIUNE }
29 Numar& Numar::operator=( const Numar& nnumar){
30 i f ( th is == &nnumar) return * th is ;
31 numar_real = nnumar.numar_real;
32 return * th is ;
33 }
34 Numar::∼Numar(){
35 Numar:: contor_distrugere --;
36 pr int f s ("\nSuntem in destructorul clasei de baza!"
37 "\nContor: %d\nTastati o litera: ",
38 Numar:: citesc_contor()
196
39 );
40 getch();
41 }
42 double Numar:: citire_numar() const {
43 return numar_real;
44 }
45 void Numar:: citire_departata() const{
46 pr int f s ("\nNe gasim intr -o clasa derivata!"
47 "\nData citita este in clasa de baza!"
48 "\nValoarea ei este: %f!",
49 citire_numar()
50 );
51 }
52 void Numar:: citire() const{
53 pr int f s ("\nFolosim o functie virtuala!"
54 "\nSuntem in clasa de baza!"
55 "\nValoarea datei este: %f!",
56 citire_numar()
57 );
58 }
59 void Numar:: scriere_numar(double nnu){
60 numar_real = nnu;
61 }
62 NumarCuSemn:: NumarCuSemn() : Numar(), pozitiv( true) {}
63 NumarCuSemn:: NumarCuSemn(double nnum): Numar(nnum) {
64 i f (nnum < 0)
65 pozitiv = f a l s e ;
66 e l se
67 pozitiv = true;
68 }
69 NumarCuSemn:: NumarCuSemn(const NumarCuSemn& nnumar) :
70 Numar(nnumar.Numar:: citire_numar()) {
71 pozitiv = (nnumar.Numar:: citire_numar() >= 0)
72 ? true : f a l s e ;
73 }
74 NumarCuSemn&
75 NumarCuSemn::operator=( const NumarCuSemn& nnumi){
76 i f ( th is == &nnumi) return * th is ;
77 double numar_intern = nnumi.Numar:: citire_numar();
78 pozitiv = (numar_intern >= 0) ? true : f a l s e ;
79 (* th is ).Numar:: scriere_numar(numar_intern);
80 return * th is ;
81 }
197
82 void NumarCuSemn::citire() const{
83 pr int f s ("\nFolosim o functie virtuala!"
84 "\nSuntem in clasa derivata !"
85 "\nValoarea datei este: %f!",
86 (* th is ).citire_numar()
87 );
88 }
89 void NumarCuSemn:: citire2 () const{
90 pr int f s ("\nSemnul datei este\"%c\"!",
91 pozitiv == true ? ’+’ : ’-’
92 );
93 Numar:: citire_departata();
94 }
Program:> (Intro IHP) In proiectul de fata, folosim campuri protected. Pe termenlung, utilizarea datelor–membru — si nu functiilor–membru — protected
constituie o eroare de design [41, p. 405], existand posibilitatea coruperii lorvia mostenire. Ideea esentiala a arhitecturii unei ierarhii de clase este ca ba-za ierarhiei sa fie o interfata, adica o clasa avand doar functii–membru, faraconstructor ori destructor, ın timp ce datele sa intervina pe parcurs, dreptcampuri ın clasele derivate. O asemenea abordare apare ın limbajul C#, un-de toate clasele deriva din System.Object, vezi [32, p. 167/166, Chap. 18].Ca ın orice chestiune de design, si acestui model i se poate adresa o critique,vezi [41, pg. 417, 418].
Folosirea campurilor protected tine de ierarhiile clasice de clase [41, p.315], [22, p. 407].
198
Intrare
#index : ui (unsigned int)
#contor distrugere : ui
+<<create>>Intrare()+<<create>>Intrare(ui)+<<create>>Intrare(const Intrare&)+operator=(const Intrare&) : Intrare&
- operator int()+<<destroy>>∼Intrare()+afisare() : void
Nume
#nume intr : char*
#<<create>>Nume()+<<create>>Nume(ui)+<<create>>Nume(ui, char*)+<<create>>Nume(const Nume&)+operator=(const Nume&) : Nume&
+<<destroy>>∼Nume()+salut() : void
+salutdoi() : void
#afisare() : void
Telefon
#tip tel : char*#nr tel : char*
#<<create>>Telefon()+<<create>>Telefon(char*)+<<create>>Telefon(char*, char*)+<<create>>Telefon(const Telefon&)+operator=(const Telefon&) : Telefon&
+<<destroy>>∼Telefon()- operator char*()
NumeSiPrenume
#prenume intr : char*
#<<create>>NumeSiPrenume()#<<create>>NumeSiPrenume(ui)#<<create>>NumeSiPrenume(ui, char*)+<<create>>NumeSiPrenume(ui, char*, char*)+<<create>>NumeSiPrenume(const NumeSiPrenume&)+operator=(const NumeSiPrenume&) : NumeSiPrenume&+<<destroy>>∼NumeSiPrenume()+salutare() : void
IntrTel
- <<create>>IntrTel()- <<create>>IntrTel(ui)- <<create>>IntrTel(ui, char*)- <<create>>IntrTel(ui, char*, char*)- <<create>>IntrTel(ui, char*, char*, char*)+<<create>>IntrTel(ui, char*, char*, char*, char*)- <<create>>IntrTel(const IntrTel&)- operator=(const IntrTel&) : IntrTel&+<<destroy>>∼IntrTel()+afistel() : void
- salutare() : void
199
Intro IHP, destructori virtuali, mostenire multipla: program.cpp
1 #include <cstdlib >
2 #include <cstdio >
3 #include <conio.h>
4 #include "ierarhie.h"
5 using namespace octavian ;
6
7 int main(){
8 {/* ---
9 Punem in evidenta destructorii:
10 activati MODUL_VERIFICARE din
11 fisierul "ierarhie .cpp"!
12 ---*/
13 NumeSiPrenume a(23,"Knut","Hamsun");
14 NumeSiPrenume b(14,"Kurt","Vonnegut ");
15 }
16 getch();
17 system("cls");
18 {
19 IntrTel unu(7,"Khaled","Hosseini ",
20 "mobil","123444444"
21 );
22 unu.afistel ();
23 }
24 getch();
25 return 0;
26 }
Intro IHP, destructori virtuali, mostenire multipla: ierarhie.h
1 #ifndef _IERARHIE_
2 #define _IERARHIE_
3
4 namespace octavian{
5 typedef unsigned int ui;
6 c la s s Intrare{
7 public :
8 Intrare ();
9 exp l i c i t Intrare(ui);
10 Intrare(const Intrare &);
11 Intrare& operator=( const Intrare &);
12 virtua l ∼Intrare ();
13 virtua l void afisare ();
14 protected:
200
15 ui index;
16 s t a t i c ui contor_distrugere;
17 private:
18 operator int ();
19 };
20
21 void afisare(Intrare&);
22
23 c la s s Nume: public Intrare{
24 public :
25 exp l i c i t Nume(ui);
26 Nume(ui, char*);
27 Nume(const Nume&);
28 Nume& operator=( const Nume&);
29 virtua l ∼Nume();
30 void salut();
31 virtua l void salutdoi ();
32 protected:
33 Nume();
34 char* nume_intr;
35 void afisare ();
36 };
37
38 c la s s NumeSiPrenume: private Nume{
39 public :
40 NumeSiPrenume(ui,char*,char*);
41 NumeSiPrenume(const NumeSiPrenume&);
42 NumeSiPrenume& operator=( const NumeSiPrenume&);
43 virtua l ∼NumeSiPrenume();
44 using octavian ::Nume::salut;
45 // vezi Stroustrup , C++ Special Edition , p. 393
46 virtua l void salutare ();
47 protected:
48 NumeSiPrenume();
49 exp l i c i t NumeSiPrenume(ui);
50 NumeSiPrenume(ui, char*);
51 char* prenume_intr;
52 };
53
54 c la s s Telefon{
55 public :
56 exp l i c i t Telefon(char*);
57 Telefon(char*,char*);
201
58 Telefon(const Telefon &);
59 Telefon& operator=( const Telefon &);
60 virtua l ∼Telefon ();
61 protected:
62 Telefon ();
63 char* tip_tel;
64 char* nr_tel;
65 private:
66 operator char*();
67 };
68
69 c la s s IntrTel: public NumeSiPrenume ,
70 private Telefon{
71 public :
72 IntrTel(ui,char*,char*,char*,char*);
73 ∼IntrTel ();
74 void afistel ();
75 private:
76 IntrTel ();
77 exp l i c i t IntrTel(ui);
78 IntrTel(ui,char*);
79 IntrTel(ui,char*,char*);
80 IntrTel(ui,char*,char*,char*);
81 IntrTel(const IntrTel &);
82 IntrTel& operator=( const IntrTel &);
83 void salutare ();
84 };
85 }
86 #endif
Intro IHP, destructori virtuali, mostenire multipla: ierarhie.cpp
1 #include "ierarhie.h"
2 #include <conio.h>
3 #include <cstring >
4 #include <iostream >
5 #include <iomanip >
6
7 #undef MODUL_VERIFICARE
8 #define MODUL_VERIFICARE 1
9 #undef MODUL_VERIFICARE
10 #undef NOTATIE_CONVENABILA
11 #define NOTATIE_CONVENABILA int numar_intern;
12 #undef EXPRESIE_CONVENABILA
202
13 /* ---
14 Atentie la macrourile cu argument :
15 fara spatiu intre "_CONVENABILA" si "(z,q)"!
16 ---*/
17 #define EXPRESIE_CONVENABILA(z,q) \
18 numar_intern = s ta t i c cas t < int >( \
19 std:: str len ( \
20 ## q \
21 ) \
22 ) + 1 /* + 30 */; \
23 z ## = new char[numar_intern]; \
24 strcpy s (z ## , \
25 numar_intern ,\
26 ## q \
27 );
28
29 #undef TESTARE_CONTOR_DISTRUGERE
30 #define TESTARE_CONTOR_DISTRUGERE \
31 i f (octavian :: Intrare :: contor_distrugere++ == 10){ \
32 pr int f s ("\nPrea multe obiecte Intrare ...\n" \
33 "Inchid programul!"); \
34 getch(); \
35 exit (EXIT FAILURE); \
36 }
37
38 octavian ::ui
39 octavian :: Intrare :: contor_distrugere = 0;
40 octavian ::Intrare :: Intrare (){
41 TESTARE_CONTOR_DISTRUGERE
42 index = ui();
43 }
44 octavian ::Intrare :: Intrare(ui iindex){
45 TESTARE_CONTOR_DISTRUGERE
46 index = iindex;
47 }
48 octavian ::Intrare ::∼Intrare (){
49 octavian :: Intrare :: contor_distrugere --;
50 #i fd e f MODUL_VERIFICARE
51 pr int f s ("\nNumarul de obiecte \"Intrare \" "
52 "inca in viata: %d\n",
53 s ta t i c cas t < int >(
54 octavian :: Intrare :: contor_distrugere
55 )
203
56 );
57 std::cout << "\nSters Intrarea : "
58 << index
59 << std::endl;
60 #endif
61 }
62 octavian ::
63 Intrare ::Intrare(const octavian :: Intrare& intr){
64 TESTARE_CONTOR_DISTRUGERE
65 index = intr.index;
66 }
67 octavian ::Intrare&
68 octavian ::
69 Intrare ::operator=( const octavian :: Intrare& intr){
70 i f ( th is ==&intr) return * th is ;
71 index = intr.index;
72 return * th is ;
73 }
74 void octavian :: Intrare ::afisare (){
75 std::cout << "\n=======\ n"
76 "Intrarea nr. "
77 << index
78 << "\n========\n"
79 << std::endl;
80 }
81 void octavian :: afisare(octavian :: Intrare& intr){
82 intr.afisare ();
83 }
84 octavian ::Nume::Nume()
85 : octavian ::Intrare (){
86 NOTATIE_CONVENABILA
87 EXPRESIE_CONVENABILA(nume_intr ,"fara nume")
88 }
89 octavian ::Nume::Nume(ui iindex)
90 : octavian ::Intrare(iindex){
91 NOTATIE_CONVENABILA
92 EXPRESIE_CONVENABILA(nume_intr ,"fara nume")
93 }
94 octavian ::Nume::Nume(ui iindex , char* nnume)
95 : octavian ::Intrare(iindex){
96 NOTATIE_CONVENABILA
97 EXPRESIE_CONVENABILA(nume_intr ,nnume)
98 }
204
99 octavian ::Nume::∼Nume(){
100 delete [] nume_intr;
101 #i fd e f MODUL_VERIFICARE
102 std::cout << "\nSters Nume: "
103 << index
104 << std::endl;
105 #endif
106 }
107 octavian ::Nume::Nume(const octavian ::Nume& nnume){
108 index = nnume.index;
109 NOTATIE_CONVENABILA
110 EXPRESIE_CONVENABILA(nume_intr ,nnume.nume_intr)
111 }
112 octavian ::Nume&
113 octavian ::
114 Nume::operator=( const octavian ::Nume& nnume){
115 i f ( th is ==& nnume) return * th is ;
116 index = nnume.index;
117 delete [] nume_intr;
118 NOTATIE_CONVENABILA
119 EXPRESIE_CONVENABILA(nume_intr ,nnume.nume_intr)
120 return * th is ;
121 }
122 void octavian ::Nume::salut(){
123 std::cout << "\nSalut de la nr. "
124 << index
125 << std::endl;
126 }
127 void octavian ::Nume:: salutdoi (){
128 std::cout << "\nSalut din clasa Nume!"
129 << std::endl;
130 }
131 void octavian ::Nume::afisare (){
132 std::cout << "\n=======\n"
133 "Intrarea nr. "
134 << index
135 << "\nNume: "
136 << nume_intr
137 << "\n========"
138 << std::endl;
139 }
140 octavian :: NumeSiPrenume:: NumeSiPrenume()
141 : octavian ::Nume(){
205
142 NOTATIE_CONVENABILA
143 EXPRESIE_CONVENABILA(prenume_intr ,"Fara prenume!")
144 }
145 octavian :: NumeSiPrenume:: NumeSiPrenume(ui iindex)
146 : octavian ::Nume(iindex){
147 NOTATIE_CONVENABILA
148 EXPRESIE_CONVENABILA(prenume_intr ,"Fara prenume!")
149 }
150 octavian ::
151 NumeSiPrenume:: NumeSiPrenume(ui iindex , char* nnume)
152 : octavian ::Nume(iindex ,nnume){
153 NOTATIE_CONVENABILA
154 EXPRESIE_CONVENABILA(prenume_intr ,"Fara prenume!")
155 }
156 octavian ::
157 NumeSiPrenume::
158 NumeSiPrenume(ui iindex , char* nnume , char* pprenume )
159 : octavian ::Nume(iindex ,nnume){
160 NOTATIE_CONVENABILA
161 EXPRESIE_CONVENABILA(prenume_intr ,pprenume )
162 }
163 octavian :: NumeSiPrenume::∼NumeSiPrenume(){
164 delete [] prenume_intr;
165 #i fd e f MODUL_VERIFICARE
166 std::cout << "\nSters NumeSiPrenume: "
167 << index
168 << std::endl;
169 #endif
170 }
171 octavian ::
172 NumeSiPrenume::
173 NumeSiPrenume(const octavian :: NumeSiPrenume& nnume){
174 index = nnume.index;
175 NOTATIE_CONVENABILA
176 EXPRESIE_CONVENABILA(nume_intr ,nnume.nume_intr)
177 EXPRESIE_CONVENABILA(prenume_intr ,nnume.prenume_intr)
178 }
179 octavian :: NumeSiPrenume&
180 octavian ::
181 NumeSiPrenume::
182 operator=( const octavian :: NumeSiPrenume& nnume){
183 i f ( th is ==& nnume) return * th is ;
184 index = nnume.index;
206
185 delete [] nume_intr;
186 NOTATIE_CONVENABILA
187 EXPRESIE_CONVENABILA(nume_intr ,nnume.nume_intr)
188 delete [] prenume_intr;
189 EXPRESIE_CONVENABILA(prenume_intr ,nnume.prenume_intr)
190 return * th is ;
191 }
192 void octavian :: NumeSiPrenume:: salutare (){
193 std::cout << "\n=======\n"
194 "Intrarea nr. "
195 << index
196 << "\nNume: "
197 << nume_intr
198 << "\nPrenume : "
199 << prenume_intr
200 << "\nFunctia \"salutdoi \" mostenita:"
201 << std::endl;
202 salutdoi ();
203 std::cout << "\n========";
204 std::cout. f lush ();
205 }
206 octavian ::Telefon :: Telefon (){
207 NOTATIE_CONVENABILA
208 EXPRESIE_CONVENABILA(tip_tel ,"Fara tip tel!")
209 EXPRESIE_CONVENABILA(nr_tel ,"Fara nr tel!")
210 }
211 octavian ::Telefon :: Telefon(char* tel){
212 NOTATIE_CONVENABILA
213 EXPRESIE_CONVENABILA(tip_tel ,"Neprecizat!")
214 EXPRESIE_CONVENABILA(nr_tel ,tel)
215 }
216 octavian ::
217 Telefon ::Telefon(char* ttip_tel ,char* nnr_tel){
218 NOTATIE_CONVENABILA
219 EXPRESIE_CONVENABILA(tip_tel ,ttip_tel )
220 EXPRESIE_CONVENABILA(nr_tel ,nnr_tel)
221 }
222 octavian ::
223 Telefon ::Telefon(const octavian :: Telefon& tel){
224 NOTATIE_CONVENABILA
225 EXPRESIE_CONVENABILA(tip_tel ,tel.tip_tel)
226 EXPRESIE_CONVENABILA(nr_tel ,tel.nr_tel)
227 }
207
228 octavian ::Telefon&
229 octavian ::
230 Telefon ::
231 operator=( const octavian :: Telefon& tel){
232 i f ( th is ==&tel) return * th is ;
233 delete [] tip_tel;
234 NOTATIE_CONVENABILA
235 EXPRESIE_CONVENABILA(tip_tel ,tel.tip_tel)
236 delete [] nr_tel;
237 EXPRESIE_CONVENABILA(nr_tel ,tel.nr_tel)
238 return * th is ;
239 }
240 octavian ::Telefon ::∼Telefon (){
241 #i fd e f MODUL_VERIFICARE
242 std::cout << "\nSters Telefon: "
243 << tip_tel
244 << " "
245 << nr_tel
246 << std::endl;
247 #endif
248 delete [] tip_tel;
249 delete [] nr_tel;
250 }
251 octavian ::
252 IntrTel ::
253 IntrTel(ui iindex ,char* nnume ,char* pprenume ,
254 char* ttip ,char* ttel
255 ) :
256 octavian :: NumeSiPrenume(iindex ,nnume ,pprenume ),
257 octavian :: Telefon(ttip ,ttel) {}
258 octavian ::IntrTel ::∼IntrTel (){}
259 void octavian :: IntrTel ::salutare (){
260 ( s ta t i c cas t <octavian ::NumeSiPrenume >(* th is )).
261 salutare ();
262 }
263 void octavian :: IntrTel ::afistel (){
264 std::cout << "\n++++++++++";
265 std::cout. f lush ();
266 salutare ();
267 std::cout << "\nFunctia \"salut\" mostenita:";
268 std::cout. f lush ();
269 salut();
270 std::cout << "+++++++++"
208
271 << std::endl;
272 }
5 Si acum?
Odata ajunsi aici, sa ne tragem rasuflarea! Putem face infinite calatorii. . .Iata cateva directii — si cateva carti, din cele care mi-au placut! —:
mecanismul try – catch de tratare a erorilor (exceptiilor) ın C++ [41, p. 355si urm.]; sabloane de design (design patterns , GOF, etc) [41, p. 709], [34,Cap. 6]; Qt [30]; Boost [5]; MFC [2]; COM, ATL [44, 35]; C++/CLI [17]; C#[32, 45, 1] — [16] este chiar standardul limbajului, adnotat —; Java [19].
Inchei prezentarea acestor note de laborator cu doua proiecte “vizuale”privind convertorul de temperatura (Fahrenheit −→ Celsius) — vezi pagina18 —.
Program:> (Intro Windows C/C++) In Figura 13 se gaseste fereastra de calcul — acce-sibila via meniul Activitati — a programului. Figurile 14, 15 contin iconita(sigla) convertorului ın variantele 32× 32, respectiv 16× 16 pixeli, cf. [31, p.364].
Figura 13
Intro “visual” C/C++: convertor_FC_4.c
1 #include "headerulnostru.h"
209
Figura 14
2
3 // functia main: "entry point"
4 int WINAPI WinMain(HINSTANCE hInstance,
5 HINSTANCE hPrevInstance ,
6 PSTR szCmdLine ,
7 int iCmdShow ){
8
9 s t a t i c TCHAR
10 szNumeleClasei[] = TEXT("MeniulMare"),
11 szTitlulProgramului[] = TEXT("Aplicatie Convertor"),
12 szNumeCutieDialog[] = TEXT("Cutie de dialog:");
13 HWND hwnd;
14 MSG msg;
15 WNDCLASS wndclass;
16
17 // implementam structura WNDCLASS
18 //(clasa ferestrei principale)
19 wndclass . sty le = CSHREDRAW | CSVREDRAW;
20 wndclass .lpfnWndProc = ProcesFereastra;
21 wndclass .cbClsExtra = 0;
22 wndclass .cbWndExtra = 0;
23 wndclass .hInstance = hInstance;
24 //iconita (sigla) programului
25 //daca nu avem iconita folosim instructiunea:
210
Figura 15
26 //wndclass .hIcon = LoadIcon (NULL ,IDI_APPLICATION);
27 wndclass .hIcon = LoadIcon(
28 hInstance,
29 MAKEINTRESOURCE(IDI_ICON ));
30 wndclass .hCursor = LoadCursor(NULL,IDC_ARROW) ;
31 wndclass .hbrBackground = (HBRUSH) (COLORWINDOW - 3);
32 wndclass .lpszMenuName = szNumeleClasei;
33 wndclass . lpszClassName = szNumeleClasei;
34
35 // inregistram clasa de ferestre
36 i f (!RegisterClass (& wndclass)){
37 MessageBox(
38 NULL,
39 TEXT("Probleme cu inregistrarea clasei!"),
40 szNumeCutieDialog ,
41 MBICONERROR
42 );
43 return 0 ;
44 }
45
46 //cream fereastra:
47 hwnd = CreateWindow(szNumeleClasei ,
48 szTitlulProgramului ,
49 WSOVERLAPPEDWINDOW,
211
50 CWUSEDEFAULT,
51 CWUSEDEFAULT,
52 CWUSEDEFAULT,
53 CWUSEDEFAULT,
54 NULL,
55 NULL,
56 hInstance,
57 NULL
58 );
59
60 // verificarea crearii ferestrei
61 i f (!hwnd){
62 MessageBox(
63 NULL,
64 TEXT("Nu putem crea clasa!\ nIesim..."),
65 szNumeCutieDialog ,
66 MBICONERROR
67 );
68 return 0;
69 }
70
71 //aratam fereastra:
72 ShowWindow(hwnd ,iCmdShow );
73 UpdateWindow(hwnd) ;
74
75 //bucla de mesaje:
76 while (GetMessage(&msg,NULL,0,0)){
77 TranslateMessage(&msg);
78 DispatchMessage(&msg);
79 }
80 return msg.wParam ;
81 }
Intro “visual” C/C++: headerulnostru.h
1 #ifndef _HEADERULNOSTRU_
2 #define _HEADERULNOSTRU_
3
4 #include <Windows.h>
5 #include "resource.h"
6
7 LRESULT CALLBACK
8 ProcesFereastra(HWND,
9 UINT,
212
10 WPARAM,
11 LPARAM
12 );
13
14 BOOL CALLBACK
15 ProcesDialogConvertor(HWND,
16 UINT,
17 WPARAM,
18 LPARAM
19 );
20
21 BOOL CALLBACK
22 ProcesDialogInformatie(HWND,
23 UINT,
24 WPARAM,
25 LPARAM
26 );
27
28 #endif
Intro “visual” C/C++: resource.h
1 #define IDI_ICON 101
2 #define IDM_DESPRE 40001
3 #define IDM_CONVERSIE 40002
4 #define IDM_IESIRE 40003
5 #define IDC_EDIT1 40004
6 #define IDC_EDIT2 40005
7 #define IDC_STATIC -1
Intro “visual” C/C++: ajutor.c
1 #include "headerulnostru.h"
2
3 LRESULT CALLBACK
4 ProcesFereastra(HWND hwnd ,
5 UINT message ,
6 WPARAM wParam ,
7 LPARAM lParam
8 ){
9
10 s t a t i c HINSTANCE hInstance;
11
12 switch(message){
13 case WMCREATE:
213
14 hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
15 return 0;
16
17 case WMCOMMAND:
18 switch(LOWORD(wParam)){
19 case IDM_DESPRE:
20 DialogBox(hInstance,
21 TEXT("Informatie"),
22 hwnd ,
23 ProcesDialogInformatie
24 );
25 break;
26 case IDM_CONVERSIE:
27 DialogBox(hInstance,
28 TEXT("Caseta"),
29 hwnd ,
30 ProcesDialogConvertor
31 );
32 break;
33 case IDM_IESIRE:
34 SendMessage(hwnd ,WMCLOSE,0,0);
35 break;
36 }//final switch
37 return 0;//final WM_COMMAND
38
39 case WMDESTROY:
40 PostQuitMessage (0);
41 return 0;
42 }//final switch(message)
43
44 return DefWindowProc(hwnd ,message ,wParam ,lParam);
45 }
46
47 BOOL CALLBACK
48 ProcesDialogInformatie(HWND hdlg ,
49 UINT message ,
50 WPARAM wParam ,
51 LPARAM lParam
52 ){
53 switch(message){
54 case WMINITDIALOG:
55 return TRUE;
56
214
57 case WMCOMMAND:
58 switch (LOWORD(wParam)){
59 case IDOK:
60 case IDCANCEL:
61 EndDialog(hdlg ,FALSE);
62 return TRUE;
63 }// final switch LOWORD(wParam)
64 break;
65 }//final switch(message)
66 return FALSE;
67 }
68
69 BOOL CALLBACK
70 ProcesDialogConvertor(HWND hdlg ,
71 UINT message ,
72 WPARAM wParam ,
73 LPARAM lParam
74 ){
75
76 s t a t i c int numar;
77
78 switch(message){
79 case WMINITDIALOG:
80 return TRUE;
81
82 case WMCOMMAND:
83 switch (LOWORD(wParam)){
84 case IDOK:{
85 BOOL bTran = FALSE;
86 DOUBLE calcul = 0.0;
87 numar = GetDlgItemInt(hdlg ,
88 IDC_EDIT1 ,
89 &bTran ,
90 TRUE
91 );
92 calcul = 0.56 * (numar - 32);
93 numar = ( int ) calcul;
94 SetDlgItemInt(hdlg ,
95 IDC_EDIT2 ,
96 numar ,
97 TRUE
98 );
99 return TRUE;
215
100 }//final IDOK
101
102 case IDCANCEL:
103 EndDialog(hdlg ,FALSE);
104 return TRUE;
105 }//final switch LOWORD(wParam)
106 break;
107 }//final switch(message)
108 return FALSE;
109 }
Inseram codul de mai jos ıntr-un fisier txt, pe care ıl salvam dreptresurse.rc si ıl introducem ın directorul C:\ProiecteleMele_Cpp\numeleproiectului\numeleproiectului. Apoi, ın Visual Studio, cautam “iconi-ta” Show All Files a ferestrei Solution Explorer. Daca totul functionea-za corect, ın lista din interiorul ferestrei vom remarca fisierul resurse.rc.Pozitionand cursorul pe mica imagine a acestuia, apasam butonul drept almouse-ului si alegem, din fereastra pop-up de optiuni, varinta Include In
Project.
Intro “visual” C/C++: convertor_FC_4.rc
1 #include "resource.h"
2 #include <Windows.h>
3
4 IDI_ICON ICON "convertor_FC_4.ico"
5
6 MENIULMARE MENU DISCARDABLE
7 BEGIN
8 POPUP "Activitati"
9 BEGIN
10 MENUITEM "Despre", IDM_DESPRE
11 MENUITEM "Conversie", IDM_CONVERSIE
12 MENUITEM "Iesire", IDM_IESIRE
13 END
14 END
15 INFORMATIE DIALOG DISCARDABLE 20,20,150,70
16 STYLE DSMODALFRAME | WSPOPUP | WS VISIBLE |
17 WSCAPTION | WSSYSMENU
18 CAPTION "Info: Versiunea 1.1"
19 FONT 10, "MS Sans Serif"
20 BEGIN
21 LTEXT "Autor: Octavian",IDC_STATIC ,10,8,150,8
22 LTEXT "Data: 5 martie 2013",IDC_STATIC ,10,24,150,8
216
23 LTEXT "Convertor Fahrenheit --> Celsius",IDC_STATICց
(cont.) ,10,40,100,8
24 LTEXT "Formula: C = 0.56 * (F - 32)",IDC_STATICց
(cont.) ,10,56,100,8
25 DEFPUSHBUTTON "Iesire",IDCANCEL,100 ,20 ,30 ,12
26 END
27 CASETA DIALOG DISCARDABLE 20,20,260,70
28 STYLE DSMODALFRAME | WSPOPUP | WS VISIBLE |
29 WSCAPTION | WSSYSMENU
30 CAPTION "Operator de conversie"
31 FONT 10, "MS Sans Serif"
32 BEGIN
33 RTEXT "Temperatura in F:",IDC_STATIC ,36,8,80,8
34 EDITTEXT IDC_EDIT1 ,140,6,61,13
35 RTEXT "Temperatura in C:",IDC_STATIC ,36,24,80,8
36 EDITTEXT IDC_EDIT2 ,140 ,22 ,61 ,13
37 PUSHBUTTON "Executie ",IDOK,60,50,50,14
38 DEFPUSHBUTTON "Renuntare",IDCANCEL,150 ,50 ,50 ,14
39 END
Program:> (Intro C#) Construim un director nou, C:\ProiecteleMele_Cs, dupacare apelam Visual Studio-ul. Alegem New Project, apoi, vezi Figura 2,ın lista Installed Templates, optam pentru Visual C#. In tabelul central,selectam Windows Forms Application. Numele proiectului — ın primul dincampurile albe din partea de jos a ferestrei pop-up New Project — poatefi primul_convertor_cs. Apoi, din fereastra Solution Explorer, folosindbutonul drept al mouse-ului, optam — la fel ca ın cazul proiectelor C++
— pentru varianta Add New Item. Din fereastra de optiuni declansata deaceasta alegere, selectam C# Code File.
Am ajuns unde trebuia! In fereastra dedicata acestui Code File — pro-babil, numele sau este CodeFile1.cs — inseram liniile de cod listate ıncontinuare. Dupa aceea, ınainte de a ıncepe compilarea, stergem fisierulProgram.cs din proiectul VS — adica, ne pozitionam cu cursorul pe mi-ca imagine a acestui item din Solution Explorer si alegem Exclude From
Project din fereastra de optiuni declansata de apasarea pe butonul drept almouse-ului — !
Intro C#: CodFile1.cs
1 // Copyright: Octavian , 2011 -- 2014
2 using System;
3 using System.Windows.Forms;
4 using System.Drawing;
5 namespace convertor_nou{
217
6 // fereastra mare a programului
7 c la s s MainWindow : Form{
8 private
9 MenuStrip meniuprincipal = new MenuStrip();
10 private
11 ToolStripMenuItem
12 meniuActivitati = new ToolStripMenuItem ();
13 private
14 ToolStripMenuItem
15 meniuActivitatiConversie = new ToolStripMenuItem ();
16 private
17 ToolStripMenuItem
18 meniuActivitatiIesire = new ToolStripMenuItem ();
19 private
20 ToolStripMenuItem
21 meniuDespre = new ToolStripMenuItem ();
22 private
23 ToolStripMenuItem
24 meniuDespreInfo = new ToolStripMenuItem ();
25 public MainWindow() { }
26 public
27 MainWindow( str ing titlu , int inaltime , int latime){
28 Text = titlu;
29 Width = latime;
30 Height = inaltime;
31 CenterToScreen();
32 ConstructiaMeniului();
33 }
34 private void ConstructiaMeniului(){
35 meniuActivitati.Text = "Activit\u0103\u0163i";
36 meniuprincipal.Items.Add(meniuActivitati);
37 meniuDespre.Text = "Despre";
38 meniuprincipal.Items.Add(meniuDespre);
39 // meniul de conversie:
40 meniuActivitatiConversie.Text = "Conversie";
41 meniuActivitati.DropDownItems.
42 Add(meniuActivitatiConversie);
43 meniuActivitatiConversie.Click += (o, s) =>
44 {
45 FereastraConversie fer = new FereastraConversie();
46 fer.Show();
47 };
48 // meniul info:
218
49 meniuDespreInfo.Text = "Info";
50 meniuDespre.DropDownItems.Add(meniuDespreInfo);
51 meniuDespreInfo.Click += (o, s) =>
52 {
53 FereastraInfo fer = new FereastraInfo();
54 fer.Show();
55 };
56 // meniul iesire:
57 meniuActivitatiIesire.Text = "Ie\u015Fire";
58 meniuActivitati.DropDownItems.
59 Add(meniuActivitatiIesire);
60 meniuActivitatiIesire.
61 Click += (o, s) => Application .Exit();
62 // gruparea meniurilor:
63 Controls .Add( th is .meniuprincipal);
64 MainMenuStrip = th is .meniuprincipal;
65 }
66 }
67 //helper pentru TextBox -uri multilinie:
68 c la s s Ajutor{
69 public
70 void CutieMare( re f TextBox cutie ,
71 bool scroll_uri = f a l s e ){
72 cutie.Multil ine = true;
73 cutie.WordWrap = true;
74 i f (scroll_uri == true)
75 cutie.ScrollBars = ScrollBars.Vertical ;
76 }
77 }
78 //partea de conversie:
79 c la s s FereastraConversie : Form{
80 public TextBox txtFahr = new TextBox();
81 public TextBox txtCels = new TextBox();
82 public FereastraConversie(){
83 FormBorderStyle = FormBorderStyle.FixedDialog;
84 MinimizeBox = f a l s e ;
85 MaximizeBox = f a l s e ;
86 CenterToParent ();
87 ShowInTaskbar = f a l s e ;
88 Text = "Conversia";
89 Width = 400;
90 Height = 200;
91 ConstructiaFerestreiConversie();
219
92 }
93 private void ConstructiaFerestreiConversie(){
94 //TexBox -ul cu Fahrenheit:
95 Ajutor ajut = new Ajutor();
96 ajut.CutieMare( re f txtFahr);
97 txtFahr.Width = 200;
98 txtFahr.Height = 100;
99 txtFahr.Location = new Point(25, 25);
100 txtFahr.Text = "Fahrenheit: Cite\u015Fte -m\u0103!"
101 + Environment.NewLine
102 + "\u015Eterge\u0163i acest text ,"
103 + Environment.NewLine
104 + "apoi scrie\u0163i aici temperatura \u00EEn F,"
105 + Environment.NewLine
106 + "dup\u0103 care da\u0163i \"dublu click\" "
107 + Environment.NewLine
108 + "cu mouse -ul (tot \u00EEn aceast\u0103 cutie).";
109 //TextBox -ul cu Celsius:
110 txtCels.Width = 120;
111 txtCels.Text = "Celsius: ";
112 txtCels.Left = txtFahr.Left + 220;
113 txtCels.Top = txtFahr.Top;
114 // introducerea acestor controale
115 //in fereastra de conversie:
116 Controls .AddRange(new Control []{txtFahr ,
117 txtCels });
118 //contor de input cu greseli:
119 int contor = 0;
120 // evenimentul central al aplicatiei:
121 txtFahr.MouseDoubleClick += (o, s) =>
122 {
123 //logica aplicatiei de conversie:
124 try{
125 th is .Width = 400;
126 txtFahr.Width = 200;
127 str ing preiau_date = txtFahr.Text;
128 double intern_calcul = Double.Parse(preiau_date);
129 // daca gresesc odata , contorul devine 1.
130 // Nefiind 3, daca scriu corect (este a doua incercare ,
131 // practic ...) contorul nu se reseteaza , deci , in
132 //viitor , nu voi mai putea gresi decat de 2 ori ,
133 // ceea ce nu este corect ...
134 // Regula de aur: daca , dupa o greseala , introduc
220
135 // datele corect , atunci greseala se anuleaza ... :)))
136 contor = 0;
137 double celsius = 0.56 * (intern_calcul - 32);
138 str ing afisare_rezultat = celsius.ToString();
139 txtCels.Left = txtFahr.Left + 220;
140 txtCels.Width = 120;
141 txtCels.Text = "Celsius: " + afisare_rezultat;
142 }
143 catch{
144 contor ++;
145 i f (contor == 3){
146 txtFahr.Width = 130;
147 txtFahr.
148 Text = "Ierta\u0163i -m\u0103 , dar cred c\u0103"
149 + Environment.NewLine
150 + "v-a\u0163i plictisit...";
151 str ing data_de_azi = DateTime.Now.ToString();
152 txtCels.Left = txtFahr.Left + 150;
153 txtCels.Width = 180;
154 txtCels.Text = "Suntem \u00EEn: " + data_de_azi;
155 contor = 0;
156 th is .Width = 450;
157 }
158 e l se {
159 th is .Width = 400;
160 txtCels.Width = 120;
161 txtCels.Text = "Celsius: ";
162 txtFahr.Width = 200;
163 txtFahr.
164 Text = "A\u0163i gre\u015Fit :((("
165 + Environment.NewLine
166 + "la introducerea datelor."
167 + Environment.NewLine
168 + "Se mai \u00EEnt\u00E2mpl\u0103!"
169 + Environment.NewLine
170 + "\u015Eterge\u0163i totul \u015Fi :)))"
171 + Environment.NewLine
172 + "relua\u0163i introducerea datelor ...";
173 txtCels.Left = txtFahr.Left + 220;
174 }
175 }
176 };
177 }
221
178 }
179 //partea de info:
180 c la s s FereastraInfo : Form{
181 public TextBox txtVers = new TextBox();
182 public TextBox txtAut = new TextBox();
183 public TextBox txtCopyr = new TextBox();
184 public TextBox txtData = new TextBox();
185 public TextBox txtTransformare = new TextBox();
186 public TextBox txtFormula = new TextBox();
187 public FereastraInfo(){
188 FormBorderStyle = FormBorderStyle.FixedDialog;
189 MinimizeBox = f a l s e ;
190 MaximizeBox = f a l s e ;
191 CenterToParent ();
192 ShowInTaskbar = f a l s e ;
193 Text = "Informa\u0163ii";
194 Width = 290;
195 Height = 320;
196 ConstructiaFerestreiInfo();
197 }
198 private void ConstructiaFerestreiInfo(){
199 int ecartament = 50;
200 int sus = 25;
201 TextBox[] sir = new TextBox[] {txtTransformare ,
202 txtFormula ,
203 txtVers ,
204 txtData ,
205 txtAut ,
206 txtCopyr };
207 Ajutor ajut = new Ajutor();
208 ajut.CutieMare( re f txtVers , true);
209 txtVers.
210 Text = "Versiune: 2.0"
211 + Environment.NewLine
212 + "Realizat\u0103 \u00EEn C#, platforma: .NET 4.0"
213 + Environment.NewLine
214 + "Prima versiune : Win32 API , COM";
215 txtData.Text = "Data lans\u0103rii : 31 iulie 2011";
216 txtAut.Text = "Autor: Octavian ";
217 txtCopyr .Text = "Drepturi de autor: DAL";
218 ajut.CutieMare( re f txtTransformare);
219 txtTransformare.Text = "Sensul de transformare:"
220 + Environment.NewLine
222
221 + "Fahrenheit ==> Celsius";
222 ajut.CutieMare( re f txtFormula);
223 txtFormula.Text = "Formula de calcul:"
224 + Environment.NewLine
225 + "C = 0.56 * (F - 32)";
226 foreach (TextBox cutie in sir){
227 cutie.Location = new Point(25, sus);
228 cutie.Width = 230;
229 cutie.Height = 40;
230 i f (cutie.Multil ine == true)
231 sus += ecartament;
232 e l se
233 sus += ( int )(0.6 * ecartament);
234 }
235 Controls .AddRange(sir);
236 }
237 }
238 // punctul de intrare:
239 c la s s Program{
240 s t a t i c void Main( str ing [] args ){
241 Application .
242 Run(new MainWindow("Convertor", 300, 450));
243 }
244 }
245 }
Surse bibliografice
[1] Albahari, J.;Albahari, B., C# in a nutshell. The definitive reference,
Fourth edition, O’Reilly, Beijing, 2010
[2] Archer, T.; Whitechapel, A., Visual C++.NET Bible, Wiley Publishing,
Inc., Indiana, 2002
[3] ASCII,
http://en.wikipedia.org/wiki/ASCII
[4] Fisiere batch,
http://en.wikipedia.org/wiki/Batch_file
[5] Boost,
http://www.boost.org/
223
[6] BenGan, I., Microsoft SQL Server 2008. TSQL fundamentals, Mi
crosoft Press, Redmond, 2009
[7] Microsoft C,
http://msdn.microsoft.com/en-us/library/02y9a5ye.aspx
[8] Linia de comanda ın C,
http://msdn.microsoft.com/en-us/library/b4b6wz4t.aspx
http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
[9] Catrina, O.; Cojocaru, I., Turbo C++, Ed. Teora, Bucuresti, 1993
[10] Consola ın Windows,
http://msdn.microsoft.com/en-us/library/ms682087.aspx
[11] Convertoare on-line,
http://www.wbuf.noaa.gov/tempfc.htm
http://chemistry.about.com/library/weekly/
bltempconvert.htm
[12] CRT,
http://msdn.microsoft.com/en-us/library/634ca0c2.aspx
[13] Deaconu, A., Programarea ın limbajele C/C++ si aplicatii, Ed. Al
bastra, ClujNapoca, 2007
[14] Fotache, M., SQL. Dialecte DB2, Oracle, PostgreSQL si SQL Server,
Editia a IIa revazuta si adaugita, Ed. Polirom, Bucuresti, 2009
[15] Goodrich, M.T.; Tamassia, R.; Mount, D., Data structures and algo
rithms in C++. Second edition, J. Wiley & Sons, New York, 2011
[16] Hejlsberg, A.; Torgersen, M.; Wiltamuth, S.; Golde, P., The C# pro
gramming language. Fourth edition, AddisonWesley, Upper Saddle
River, NJ, 2011
[17] Hogenson, G., Foundations of C++/CLI. The Visual C++ language for
.NET 3.5, Apress, Berkeley, CA, 2008
[18] Jamsa, K.; Klander, L., Totul despre C si C++, Ed. Teora, Bucuresti,
2007
224
[19] Keogh, J., Java fara mistere, Ed. Rosetti Educational, Bucuresti, 2004
[20] Kernighan, B.W.; Ritchie, D.M., The C programming language. Sec
ond edition, Prentice Hall, Englewood Cliffs, NJ, 1988. Erata cartii se
gaseste la adresa:
http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html
[21] Kpathsea,
http://www.tug.org/svn/texlive/trunk/Build
/source/texk/kpathsea/
[22] Lippman, S.B., C++ primer. 2nd edition, reprinted with corrections,
AddisonWesley, Reading, Mass., 1992
[23] Lippman, S.B., Essential C++, AddisonWesley, Reading, Mass., 2000.
Erata cartii se gaseste la adresa:
http://ptgmedia.pearsoncmg.com/images/0201485184/errata
/errata.pdf
[24] Meyers, S., Effective STL. 50 specific ways to improve your use of the
standard template library, Fifth printing, AddisonWesley, Boston,
2005
[25] MiKTEX,
http://www.miktex.org
[26] MSDN,
http://www.msdn.microsoft.com
[27] Mustafa, O.G., Note de TEX, DAL, 2009. On-line la adresa:
https://www.dropbox.com/s/n1mm0um79a14fme/knuth.pdf
[28] Mustafa, O.G., Curbe si suprafete, DAL, 2009. On-line la adresa:
https://www.dropbox.com/sh/gi3yyjt1rsq58vl/6R_nE49U9j
[29] Windows NT,
http://en.wikipedia.org/wiki/Windows_NT
[30] Qt,
http://qt.nokia.com/products/
225
[31] Petzold, C., Programming Windows. Fifth edition, Microsoft Press,
Redmond, 1998
[32] Petzold, C., .NET Book Zero. What the C or C++ programmer needs
to know about C# and the .NET framework, 2007. On-line la adresa:
http://www.charlespetzold.com/dotnet/index.html
[33] POSIX,
http://en.wikipedia.org/wiki/POSIX
[34] Preda, M.C.; Mirea, A.M.; Preda, D.L.; TeodorescuMihai, C., Intro
ducere ın programarea orientataobiect. Concepte fundamentale din
perspectiva ingineriei software, Ed. Polirom, Bucuresti, 2010
[35] Richter, J.; Nasarre, C., Windows via C/C++, Microsoft Press, Red
mond, 2008
[36] The Rule of Three,
http://drdobbs.com/cpp/184401400
http://www.artima.com/cppsource/bigtwo.html
http://www.artima.com/cppsource/bigtwo2.html
http://www.artima.com/cppsource/bigtwo3.html
[37] SEH,
http://msdn.microsoft.com/en-us/library/ms680657.aspx
[38] signal,
http://msdn.microsoft.com/en-us/library/xdkz3x12.aspx
[39] Standardul C++,
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011
/n3242.pdf
[40] Stroustrup, Bjarne,
http://en.wikipedia.org/wiki/Bjarne_Stroustrup
[41] Stroustrup, B., The C++ programming language. Special edition,
AddisonWesley, New York, 1997. Seventh printing, 2003. Erata cartii
se gaseste la adresa:
http://www2.research.att.com/~bs/3rd_printing20.html
226
[42] Stroustrup, B., Programming: principles and practice using C++, Third
printing, AddisonWesley, Upper Saddle River, NJ, 2010
[43] TEXnicCenter,
http://www.texniccenter.org/
[44] Troelsen, A., Developer’s workshop to COM and ATL 3.0, Wordware
Publish., Inc., Plano, Texas, 2000
[45] Troelsen, A., Pro C# 2010 and the .NET 4 platform, Fifth edition,
Apress, New York, 2010
[46] TUG,
http://www.tug.org/
[47] TEX Live,
http://www.tug.org/texlive/
[48] Vandevoorde, D.; Josuttis, N.M., C++ templates. The complete guide,
Second printing, AddisonWesley, Boston, 2003
[49] Visual C++ 2010 Express,
http://www.microsoft.com/visualstudio/en-us/products/
2010-editions/visual-cpp-express
[50] Windows SDK,
http://www.microsoft.com/download/en/
details.aspx?displaylang=en&id=8279
227