Limbajul de programare C++ (tutorial)
February 9, 2017 | Author: api-19523472 | Category: N/A
Short Description
Download Limbajul de programare C++ (tutorial) ...
Description
THE C++ PROGRAMMING LANGUAGE BJARNE STROUSTRUP
ADDISON-WESLEY PUBLISHING COMPANY 1986
PREFATA =========== C++ este un limbaj de programare cu scop universal.El contine facilitati flexibile si eficiente pentru a definii tipuri noi. Programatorul poate partitiona o aplicatie in bucati manevrabile prin definiri de tipuri noi, care corespund mai bine la conceptele aplicatiei. Aceasta tehnica de construire a programului se numeste adesea abstractizare de date. Obiectele unui anumit tip definit de utilizator contin informatie de tip. Astfel de obiecte pot fi folosite convenabil in contextul in care tipul lor poate fi determinat in momentul compilarii. Programele utilizind
obiecte de astfel de tipuri se numesc adesea bazate pe obiecte. Cind se utilizeaza bine, aceste tehnici conduc la programe mai scurte, mai usor de inteles si mai usor de a le menine. Conceptul cheie din C++ este clasa. O clasa este un tip utilizator. Clasele furnizeaza ascunderea datelor, garantarea initializarii datelor, conversii de tip implicite pentru tipuri de date utilizator, tipuri dinamice, gestionarea memoriei controlate de utilizator si mecanismul de supraincarcare a operatorilor. C++ furnizeaza facilitati mai bune pentru verificarea tipului si pentru exprimarea modularitatii, decit o face limbajul C. De asemenea contine imbunatatiri care sint direct inrudite cu clasele, incluzind constantele simbolice, substitutia in linie a functiilor, argumente implicite ale functiilor care se supraincarca, operatori de gestionare a memoriei libere si un tip referinta.
OBSERVATII PENTRU CITITOR ===========================
Structura cartii ---------------Capitolul 1 este o trecere in revista rapida a caracteristicilor majore ale lui C++. La inceput sint caracteristici comune cu C. Cea de-a doua jumatate descrie facilitatile lui C++ pentru a definii tipuri noi. Capitolele 2, 3 si 4 descriu caracteristicile lui C+ + care nu sint implicate in definirea de tipuri noi. Deci se descrie subsetul lui C++ care este in esenta C. Informatia completa se da in manualul de referinta. Capitolele 5, 6, 7 descriu facilitatile lui C++ pentru a definii tipuri noi, trasaturi care nu fac parte
din C. Capitolul 5 prezinta conceptul de clasa, aratind cum obiectele de tip utilizator, pot fi initializate, accesate si in final eliminate. Capitolul 6 explica cum se pot definii operatorii unari si binari pentru un tip definit de utilizator, cum se pot face conversatii intre tipurile definite de utilizator si cum se specifica modul de creare, stergere si copiere a unei valori a unui tip definit de utilizator. Capitolul 7 descrie conceptul de clasa derivata, care permite programatorului sa construiasca clase mai complexe din unele mai simple, pentru a furniza interfete alternative pentru o clasa si a minui obiecte intr-o maniera eficienta si in deplina protectie, in contextul in care tipurile lor nu pot fi cunoscute la compilare. Capitolul 8 prezinta clasele ostream si istream furnizate pentru intrari si iesiri din biblioteca standard. Acest capitol prezinta o facilitate care este un exemplu real de utilizare a lui C++. In final este inclus manualul de referinta C++. Trimiterile se descriu astfel: &2.3.4 -> capitolul 2, sectiunea 3.4; &r8.5.5 -> trimitere in partea de referinta. Exercitiile sint gradate astfel: (*1) - exercitiul necesita 5 minute; (*2) - exercitiul necesita o ora; (*3) - exercitiul necesita o zi.
Observatii de proiectare -----------------------C++ nu are tipuri de date de nivel inalt si nici operatii primitive de nivel inalt. De exemplu, nu exista tipul matrice cu un operator de inversare sau tipul sir cu operatorul de concatenare. Daca un utilizator doreste
un astfel de tip, el poate fi definit. Defapt, definirea unui tip nou cu scopuri generale sau specific aplicative este scopul cel mai important al limbajului C++. Un tip definit de utilizator difera de unul predefinit numai in modul de definire si nu si in modul in care este utilizat.
Note istorice ------------C++ a aparut in vara anului 1983 (C cu clase). Incercari au fost facute inca din 1980. C++ inseamna C incrementat. C++ are ca scop principal scrierea de programe bune mai usor si mai placut pentru programatorul individual. O sursa de inspiratie a fost Simula 67; conceptul de clasa a fost imprumutat de aici. C si ANSI C sint foarte apropiate pentru a fi un subset a lui C++. C++ a fost dezvoltat din C si cu foarte mici exceptii C ramine un subset a lui C++. Observatii filozofice --------------------Un limbaj de programare serveste la doua scopuri inrudite: el furnizeaza un mijloc pentru programator de a specifica actiuni de executat si un set de concepte pentru programator care sa fie utilizate cind se gindeste in legatura cu ceea ce poate fi facut. Primul aspect in mod ideal cere un limbaj ce este "strins legat de masina" asa incit toate aspectele unei masini sa fie manevrate simplu si eficient intr-un mod care sa fie rezonabil de clar pentru programator.
Limbajul C initial a fost proiectat avind acest lucru in minte. Cel de al doilea aspect in mod ideal cere un limbaj care este "strins legat de problema de rezolvat", asa ca, conceptele unei solutii sa poata fi exprimate direct si concis. Facilitatile adaugate la C pentru a crea C++ initial au fost proiectate avind acest lucru in minte. Legatura dintre limbajul in care noi gindim programul si dintre cel in care ne imaginam problemele si solutiile este foarte strinsa. Din acest motiv, restringerea caracteristicilor cu scopul de a elimina erorile programatorului este cel mai periculos. Tot asa cu limbajele naturale, exista un beneficiu mare din faptul ca sint cel putin bilingve. Limbajul furnizeaza programatorului un set de instrumente conceptuale: daca acestea sint inadecvate pentru un task, ele pur si simplu vor fi ignorate. De exemplu, restringind serios conceptul de pointer, pur si simplu se forteaza programatorul ca sa utilizeze un vector plus aritmetica intreaga pentru a implementa structuri, pointeri, etc. Un proiect bun si absenta erorilor nu poate fi garantata numai prin caracteristicile limbajului. Sistemul tipurilor ar trebui sa fie in special util pentru task-uri netriviale.
Ginduri despre programare in C++ Ideal sarcina de concepere a unui program este impartita in 3 stadii: primul consta in intelegerea clara a problemei, apoi identificare conceptelor cheie implicate intr-o solutie si in final exprimarea solutiei printr-un program. Totusi, detaliile problemei si conceptele unei solutii adesea devin clar intelese numai prin efortul de a le exprima intr-un program; acesta este motivul alegerii limbajului de programare. In cele mai multe aplicatii exista concepte care nu sint reprezentate usor intr-un program nici printr-un tip fundamental si nici printr-o functie fara date statice asociate. Dindu-se un astfel de concept, se declara o clasa pentru a-l reprezenta in program. O clasa este un tip; adica, ea specifica cum obiectele din clasa se dezvolta: cum se creaza, cum pot fi manipulate, cum se anihileaza. O clasa de asemenea specifica cum se reprezinta obiectele, dar la un stadiu mai initial al proiectarii programu-lui aceasta nu
trebuie sa fie o conceptie majora. Cheia scrierii unui program bun este de a proiecta clasele in asa fel incit fiecare, in mod clar, sa reprezinte un singur concept. Adesea aceasta inseamna ca programatorul trebuie sa se concetreze asupra problemelor: cum se creaza obiectele din aceasta clasa? se poate ca obiectele din aceasta clasa sa fie copiate si/sau distruse? ce operatii pot fi facute cu astfel de obiecte? Daca nu sint raspun-suri bune la astfel de intrebari, conceptul probabil ca nu a fost clar definit si va trebui sa ne mai gindim asupra lui. Conceptele cu care este mai usor sa ne ocupam sint cele care au un formalism matematic traditional: numere de toate felurile, multimi, forme geometrice, etc.. Se cuvine sa fie biblioteci standard de clase care sa reprezinte astfel de concepte. Unul dintre cele mai puternice instrumente intelectuale pentru tratarea complexitatilor este ordonarea ierarhica; adica organizarea conceptelor inrudite intr-o structura de arbore cu cel mai general concept in radacina. In C++ clasele derivate reprezinta o astfel de structura. Un program poate fi adesea organizat ca o multime de arbori.
Reguli -----Iata citeva reguli care trebuiesc considerate cind invatam C++. [1] Cind programam, noi cream o reprezentare concreta a ideilor ce constituie solutia noastra la o anumita problema. Structura programului reflecta acele idei atit de direct cit este posibil: [a] Daca noi putem sa ne gindim la "el" ca la o idee separata, sa-l facem o clasa.
[b] Daca noi putem sa ne gindim la "el" ca la o entitate separata, sa-l facem obiect al unei anumite clase. [c] Daca doua clase au ceva seminificativ in comun, aceasta se face o clasa de baza. Majoritatea claselor din pro-gramul nostru vor avea ceva in comun: au o clasa de baza universala si ea trebuie proiectata cu multa atentie. [2] Cind noi definim o clasa care nu implementeaza o entitate matematica ca o matrice sau un numar complex sau un tip de nivel inferior ca o lista inlantuita: [a] Sa nu se utilizeze date globale. [b] Sa nu se utilizeze functii globale (care nu sint membri).
[c] Sa nu se utilizeze membri ale datelor publice.
[d] Sa nu se utilizeze frati, exceptind cazul in care ei se folosesc pentru a elimina [a], [b] sau [c]. [e] Sa nu se faca acces direct la membri de date a altor obiecte. [f] Sa nu se puna un tip 'cimp' intr-o clasa; sa se utilizeze functii virtuale. [g] Sa nu se utilizeze functii inline; exceptind cazul unei optimizari semnificative.
CUPRINS ======= NUME PAG. ========================================================= ======== 1 1
CAP.1 === "TUTORUL" LUI C++ 1.1.
Introducere 1.1.1. Iesire
1
1.1.2. Compilare
1
1.1.3. Intrare
1 2 2
1.2.
Comentariu
1.3.
Tipuri si Declaratii 1.3.1. Tipuri fundamentale
2
1.3.2. Tipuri derivate
3 3
1.4.
Expresii si Instructiuni
5 6 7 8 9
1.5.
Functii
1.6.
Structura programului
1.7.
Clase
1.8.
Operatorul overloading
1.9.
Referinte
10
1.10. Constructori
11
1.11. Vectori
13
1.12. Expandare inline
13
1.13. Clase derivate
15
1.14. Mai mult despre operatori
17
1.15. Prieteni (Friends)
18
1.16. Vectori generici 1.17. Vectori polimorfici
18 20
1.18. Functii virtuale CAP.2 === DECLARATII SI CONSTANTE
21 21 22 24 24
2.1. Declaratii 2.1.1. Domeniu 2.1.2. Obiecte si Lvalori 2.1.3. Durata de viata
25 25 26 27 28 29 30 31 32 34 36
2.2. Nume 2.3. Tipuri 2.3.1. Tipuri fundamentale 2.3.2. Conversia implicita de tip 2.3.3. Tipuri derivate 2.3.4. Void 2.3.5. Pointeri 2.3.6. Vectori 2.3.7. Pointeri si Vectori 2.3.8. Structuri 2.3.9. Echivalenta tipurilor
NUME
PAG. ========================================================= ======== 2.3.10. Referinte 36 2.3.11. Registrii 39 2.4. Constante 40 2.4.1. Constante intregi 40
41
2.4.2. Constante in flotanta
41
2.4.3. Constante caracter
42
2.4.4. Siruri
43
2.4.5. Zero
43
2.4.6. Const
45
2.4.7. Enumerari
46
2.5. Salvarea spatiului
46
2.5.1. Cimpuri
47
2.5.2. Reuniuni
49
2.6. Exercitii CAP.3 === EXPRESII SI INSTRUCTIUNI
51 51 52 56 58 60 61 62 63
3.1. Un calculator de birou 3.1.1. Analizorul 3.1.2. Functia de intrare 3.1.3. Tabela de simboluri 3.1.4. Tratarea erorilor 3.1.5. Driverul 3.1.6. Argumentele liniei de comanda 3.2. Sumar de operatori
65
3.2.1. Paranteze rotunde
66
3.2.2. Ordinea de evaluare
67
3.2.3. Incrementare si Decrementare
68
3.2.4. Operatori logici pe biti
69
3.2.5. Conversia tipului
70
3.2.6. Memoria libera
73
3.3. Sumarul instructiunilor
74
3.3.1. Teste
76
3.3.2. Goto
77
3.4. Comentarii si Decalari
79
3.5. Exercitii CAP.4 === FUNCTII SI FISIERE
83 83 84 86 88 90 92 93
4.1. Introducere 4.2. Linkare 4.3. Fisiere antet 4.3.1. Fisier antet unic 4.3.2. Fisiere antet multiple 4.3.3. Ascunderea datelor 4.4. Fisiere si Module
93 95 95 95 96 97 98 99 100
4.5. Cum se construieste o biblioteca 4.6. Functii 4.6.1. Declaratii de functii 4.6.2. Definitii de functii 4.6.3. Transferul argumentelor 4.6.4. Valoarea returnata 4.6.5. Argumente vector 4.6.6. Argumente implicite 4.6.7. Nume de functii supraincarcate
NUME PAG. ========================================================= ======== 4.6.8. Numar nespecificat de argumente 102 4.6.9. Pointer spre functie 104 4.7. Macrouri 107 4.8. Exercitii 110 CAP.5 === CLASE 113 5.1. Introducere si privire generala 113 5.2. Clase si Membri 114
114 115 116 118 120 121 121 122 125 128 128 131 131 132 133 134 137 137 138 139
5.2.1. Functii membru 5.2.2. Clase 5.2.3. Autoreferinta 5.2.4. Initializare 5.2.5. Curatire (Stergere) 5.2.6. In linie 5.3. Interfete si Implementari 5.3.1. Implementari alternative 5.3.2. O clasa completa 5.4. Prieteni si Reuniuni 5.4.1. Prieteni 5.4.2. Calificarea numelor membre 5.4.3. Clase imbricate 5.4.4. Membri statici 5.4.5. Pointeri spre membri 5.4.6. Structuri si Reuniuni 5.5. Constructori si Destructori 5.5.1. Goluri 5.5.2. Memoria statica 5.5.3. Memoria libera
140 142 143 144 145 147
5.5.4. Obiectele clasei de membri 5.5.5. Vectori si Obiecte clasa 5.5.6. Obiecte mici 5.5.7. Goluri 5.5.8. Obiecte de dimensiune variabila 5.6. Exercitii
CAP.6 === OPERATOR SUPRAINCARCAT 149 6.1. Introducere 149 6.2. Functiile operator 150 6.2.1. Operatori binari si unari 151 6.2.2. Sensul predefinit al operatorilor 151 6.2.3. Operatori si Tipuri definite de utilizatori 152 6.3. Conversia de tip definita de utilizator 152 6.3.1. Constructori 153 6.3.2. Operatori de conversie 154 6.3.3. Ambiguitati 155 6.4. Constante 157 6.5. Obiecte mari 157 6.6. Asignare si Initializare 158
160 162 163 166
6.7. Indexare 6.8. Apelul unei functii 6.9. O clasa sir 6.10. Prieteni si Membri
NUME PAG. ========================================================= ======== 6.11. Goluri 167 6.12. Exercitii 168 CAP.7 === CLASE DERIVATE 171 7.1. Introducere 171 7.2. Clase derivate 172 7.2.1. Derivare 172 7.2.2. Functii membru 173 7.2.3. Vizibilitate 175 7.2.4. Pointeri 176 7.2.5. Ierarhizarea claselor 177 7.2.6. Constructori si Destructori 178 7.2.7. Cimpuri de tip 179
181 183 183 184 186 187 189 190 191 193 193 193 196 198 200 202
7.2.8. Functii virtuale 7.3. Interfete alternative 7.3.1. O interfata 7.3.2. O implementare 7.3.3. Cum sa o folosim 7.3.4. Tratarea erorilor 7.3.5. Clase generice 7.3.6. Interfete restrictive 7.4. Adaugarea la o clasa 7.5. Liste eterogene 7.6. Un program complet 7.6.1. Controlul ecranului 7.6.2. Biblioteca de figuri 7.6.3. Programul de aplicatie 7.7. Memoria libera 7.8. Exercitii
CAP.8 === STREAMS 205 8.1. Introducere 205 8.2. Iesire 206
206
8.2.1. Iesirea tipurilor predefinite 8.2.2. Iesirea tipurilor utilizator
207 208 209 212 213 213 214 214 215 215
217 218
8.2.4. Iesire formatata 8.2.5. O functie de iesire virtuala 8.3. Fisiere si Streamuri 8.3.1. Initializarea iesire
streamurilor
de
8.3.2. Inchiderea streamurilor de iesire 8.3.3. Deschiderea fisierelor 8.3.4. Copierea streamurilor 8.4. Intrari tipurilor
predefi-
8.4.2. Starile streamului 8.4.3. Introducerea tipurilor de utilizator 8.4.4. Initializarea intrare
219
PAG.
de
8.2.3. Citeva detalii de implementare
8.4.1. Introducerea nite 216
definite
NUME
definite
streamurilor
de
========================================================= ======== 8.5. Manipularea sirurilor 220 8.6. Blocare in bufer 221 8.7. Eficienta 223 8.8. Exercitii 224 MANUAL DE REFERINTA 227 1. Introducere 227 2. Conventii lexicale 227 2.1. Comentarii 227 2.2. Identificatori (Nume) 227 2.3. Cuvinte cheie 228 2.4. Constante 228 2.4.1. Constante intregi 228 2.4.2. Constante long explicite 228 2.4.3. Constante caracter 229 2.4.4. Constante flotante 229 2.4.5. Constante enumerative 229 2.4.6. Constante declarate 229 2.5. Siruri 230
230 230 231 231 232 232 232 232 233 233 234 234
2.6. Caracteristici hardware 3. Notatia sintactica 4. Nume si Tipuri 4.1. Domenii 4.2. Definitii 4.3. Linkare 4.4. Clase de memorie 4.5. Tipuri fundamentale 4.6. Tipuri derivate 5. Obiecte si Lvalori 6. Conversii 6.1. Caractere si Intregi 6.2. Flotante cizie
234 234 235 235 235 236 236
in simpla si dubla
6.3. Flotante si Intregi 6.4. Pointeri si Intregi 6.5. Intregi fara semn 6.6. Conversii aritmetice 6.7. Conversii de pointeri 6.8. Conversie de referinta
pre-
236 237 239
7. Expresii 7.1. Expresii primare 7.2. Operatori unari 7.2.1. Incrementare si Decrementare
239
7.2.2. Sizeof
240
7.2.3. Conversie explicita de tip
240
7.2.4. Memoria libera
241 242 242 243 243 244 244 244
7.3. Operatori multiplicatori 7.4. Operatori aditivi 7.5. Operatori de deplasare 7.6. Operatori relationali 7.7. Operatori de egalitate 7.8. Operatorul SI pe biti 7.9. Operatorul SAU-EXCLUSIV pe biti
NUME PAG. ========================================================= ======== 7.10. Operatorul SAU-INCLUSIV pe biti 244 7.11. Operatorul logic SI 244
245 245 245 246 246 247 247 247 247 248 249 250 251 253 254 255 256 257 258 259
7.12. Operatorul logic SAU 7.13. Operator conditional 7.14. Operatori de asignare 7.15. Operatorul virgula 7.16. Operatori de supraincarcare 7.16.1. Operatori unari 7.16.2. Operatori binari 7.16.3. Operatori speciali 8. Declaratii 8.1. Specificatori de clasa de memorie 8.2. Specificatori de tip 8.3. Declaratori 8.4. Intelesul ( sensul ) declaratorilor 8.4.1. Exemple 8.4.2. Tablouri, Pointeri si Indici 8.5. Declaratii de clasa 8.5.1. Membri statici 8.5.2. Functii membru 8.5.3. Clase derivate 8.5.4. Functii virtuale
259 260 261 261 262 263 264 264 264 265 265 266 266 267 268 269 269 270 271 272
8.5.5. Constructori 8.5.6. Conversii 8.5.7. Destructori 8.5.8. Memoria libera 8.5.9. Vizibilitatea numelor membri 8.5.10. Prieteni 8.5.11. Functii operator 8.5.12. Structuri 8.5.13. Reuniuni 8.5.14. Cimpuri de biti 8.5.15. Clase imbricate 8.6. Initializare 8.6.1. Liste initializatoare 8.6.2. Obiecte de clasa 8.6.3. Referinte 8.6.4. Tablouri de caractere 8.7. Nume de tip 8.8. Typedef 8.9. Nume de functii supraincarcate 8.10. Declaratii de enumerare
273 273 273 273 274 274 274 274 275 276 276
8.11. Declaratia ASM 9. Instructiuni 9.1. Instructiunea expresie 9.2. Instructiunea compusa (blocul) 9.3. Instructiunea conditionala 9.4. Instructiunea WHILE 9.5. Instructiunea DO 9.6. Instructiunea FOR 9.7. Instructiunea SWITCH 9.8. Instructiunea BREAK 9.9. Instructiunea CONTINUE
NUME PAG. ========================================================= ======== 9.10. Instructiunea RETURN 276 9.11. Instructiunea GOTO 277 9.12. Instructiunea etichetata 277 9.13. Instructiunea NULL 277 9.14. Instructiunea declarativa 277
278 279 280 280 281 281 282 282 283 283 284 286 286 287 287 287 288 288
10. Definitii de functii 11. Linii de control ale compilatorului 11.1. Substitutia de siruri 11.2. Incluziune de fisiere 11.3. Compilarea conditionata 11.4. Linie de control 12. Expresii constante 13. Consideratii de portabilitate 14. Sumar de sintaxa 14.1. Expresii 14.2. Declaratii 14.3. Instructiuni 14.4. Definitii externe 14.5. Preprocesor 15. Diferente fata de C 15.1. Extensii 15.2. Sumar de incompatibilitati 15.3. Anacronisme
CAPITOLUL 1 =========== "TUTORUL" LUI C++ ================= 1.1 Introducere -----------
1.1.1 Iesire -----#include main() { cout aplicat la un pointer spre un obiect din clasa lui (&7.1). Membri clasei statice (&8.5.1) si
functiile membru pot fi referite de asemenea acolo unde numele clasei lor este in domeniu utilizind operatorul :: (&7.1). O clasa declarata intr-o clasa (&8.5.15) nu se considera un membru si numele ei l apartine la domeniul care o include. Un nume poate fi ascuns printr-o declaratie explicita a aceluiasi nume intr-un bloc sau clasa. Un nume intr-un bloc sau clasa poate fi ascuns numai printr-un nume declarat intr-un bloc sau clasa inclusa. Un nume nelocal ascuns poate insa sa fie utilizat cind domeniul lui se specifica folosind operatorul :: (&7.1). Un nume de clasa ascuns printr-un nume non-tip poate fi insa utilizat daca este prefixat prin class, struct sau union (&8.2). Un nume enum ascuns printr-un nume non-tip poate insa sa fie utilizat daca este prefixat de enum (&8.2). 4.2
Definitii
O declaratie (&8) este o definitie daca nu este o declaratie de functie (&10) si ea contine specificatorul extern si nu are initializator sau corpul functiei sau este declaratia unui nume de clasa (&8.8). 4.3
Linkare
Un nume din domeniul fisierului care nu este declarat expli- cit ca static este comun fiecarui fisier intr-un program multifi- sier; asa este numele unei functii. Astfel de nume se spune ca sint externe. Fiecare declaratie a unui nume extern din program se refera la acelasi obiect (&5), functie (&10), tip (&8.7), clasa (&8.5), enumerare (&8.10) sau valoare de enumerare (&8.10). Tipurile specificate in toate declaratiile unui nume extern trebuie sa fie identice. Pot exista mai multe definitii pentru un tip, o enumerare, o functie inline (&8.1) sau o constanta care nu este agregat cu conditia ca definitiile care apar in diferite fisiere sa fie identice, iar toti initializatorii sa fie expresii constante (&12). In toate celelalte cazuri, trebuie sa fie exact o definitie pentru un nume extern din program. O implementare poate cere ca o constanta neagregat utiliza- ta unde nu este definita, sa trebuiasca sa fie declarata extern explicit si sa aiba exact o definitie in program. Aceeasi restrictie poate fi impusa si asupra functiilor inline. 4.4
Clase de memorie
Exista doua clase de memorie: clase automatice si clase statice. Obiectele automatice sint locale. Ele apar la fiecare apel al unui bloc si se elimina la iesirea din el. Obiectele statice exista si isi mentin valorile pe timpul executiei intregului program.
Anumite obiecte nu sint asociate cu nume si viata lor se controleaza explicit utilizind operatorii new si delete; vezi &7.2 si &9.14. 4.5
Tipuri fundamentale
Obiectele declarate ca si caractere (char) sint destul de mari pentru a memora orice membru al setului de caractere implementat si daca un caracter real din acel set se memoreaza intr-o variabila caracter, valoarea ei este echivalenta cu codul intreg al acelui caracter. Sint disponibile trei dimensiuni de tip intreg, declarate short int, int si long int. Intregii long furnizeaza memorie nu mai putina decit cei short, dar implementarea poate face ca sau intregii short sau cei long sau ambii sa fie intregi fara alte atribute (int). Intregii int au dimensiunea naturala pe masina gazda sugerata de arhitectura ei. Fiecare enumerare (&8.10) este un set de constante denumite. Proprietatile lui enum sint identice cu cele ale lui int. Intregii fara semn asculta de legile aritmeticii modulo 2^n unde n este numarul de biti din reprezentare. Numerele flotante in simpla precizie (float) si in dubla precizie (double) pot fi sinonime in anumite implementari. Deoarece obiectele de tipurile anterioare pot fi interpretate in mod util ca numere, ele vor fi referite ca tipuri aritmetice. Tipurile char, int de toate dimensiunile si enum vor fi numite tip integral. Tipurile float si double vor fi numite tip floating. Tipul void specifica o multime vida de valori. Valoarea (inexistenta) a unui obiect void nu poate fi utilizata si nu se pot aplica conversii explicite sau implicite. Deoarece o expresie void noteaza o valoare inexistenta, o astfel de expresie poate fi utilizata numai ca o expresie instructiune (&9.1) sau ca operandul sting al unei expresii cu virgula (&7.15). O expresie poate fi convertita explicit spre tipul void (&7.2). 4.6
Tipuri derivate
Exista un numar conceptual infinit de tipuri derivate construite din tipurile fundamentale: tablouri de obiecte de un tip dat; functii care au argumente de tipuri date si returneaza obiecte de un tip dat; pointeri spre obiecte de un tip dat; referinte la obiecte de un tip dat; constante care sint valori de un tip dat; clase ce contin o secventa de obiecte de tipuri diferite, un set de functii pentru manipularea acestor obiecte si un set de restrictii asupra accesului la aceste obiecte si functii;
structuri care sint clase fara restrictii la acces; reuniuni care sint structuri capabile sa contina obiecte de tipuri diferite in momente diferite. In general aceste metode de a construi obiecte pot fi aplicate recursiv. Un obiect de tip void* (pointer spre void) poate fi utilizat pentru a pointa spre obiecte de tip necunoscut. 5 Obiecte si Lvalori Un obiect este o regiune de memorie; o lvaloare este o expresie care se refera la un obiect. Un exemplu evident de expresie lvaloare este numele unui obiect. Exista operatori care produc lvalori: de exemplu, daca E este o expresie de tip poin- ter, atunci *E este o expresie lvaloare care se refera la obiectul spre care pointeaza E. Numele lvaloare vine de la expresia de atribuire E1 = E2 in care operatorul sting trebuie sa fie o lvaloare. Discutia de mai jos despre operatori indica despre fiecare daca el asteapta un operand lvaloare si daca el produce o lvaloare. 6 Conversii Un numar de operatori pot, depinzind de operanzii lor, sa provoace conversia valorii unui operand de un tip la altul. Aceasta sectiune explica rezultatul asteptat de la o astfel de conversie. Paragraful &6.6 rezuma conversiile cerute de cei mai obisnuiti operatori; ea va fi suplimentata la nevoie printr-o discutie despre fiecare operator. Paragraful &8.5.6 descrie conversiile definite de utilizator. 6.1
Caractere si Intregi
Un caracter sau un intreg scurt poate fi utilizat oriunde se poate utiliza un intreg. Conversia unui intreg scurt spre unul mai lung implica totdeauna extensie de semn; intregii sint cantitati cu semn. Daca extensia de semn apare sau nu pentru caractere este dependent de masina; vezi &2.6. Tipul explicit unsigned char forteaza ca valorile sa fie de la zero la cea mai mare valoare permisa de masina. Pe masinile care trateaza caracterele ca fiind cu semn, caracterele ASCII sint toate pozitive. Cu toate acestea, o constanta caracter specificata cu backslash sufera o extensie de semn si poate apare negativa; de exemplu, '\377' are valoarea -1. Cind un intreg lung se converteste spre un intreg mai scurt sau spre char, se trunchiaza la stinga; bitii in plus sint pierduti. 6.2
Flotante in simpla si dubla precizie
Aritmetica in flotanta simpla precizie poate fi utilizata pentru expresii de tip float. Conversiile intre numere flotante in simpla precizie si dubla precizie sint din punct de vedere matematic corecte in masura in care permite hardware-ul. 6.3
Flotante si Intregi
Conversiile valorilor flotante spre tipul intreg tind sa fie dependente de masina; in particular directia trunchierii numere lor negative variaza de la masina la masina. Rezultatul este imprevizibil daca valoarea nu incape in spatiul prevazut. Conversiile valorilor intregi spre flotante se rezolva bine. Se pot pierde cifre daca destinatia nu are suficienti biti. 6.4.
Pointeri si Intregi
O expresie de tip intreg poate fi adunata sau scazuta dintr-un pointer; intr-un astfel de caz primul se converteste asa cum se specifica in discutia despre operatorul de adunare. Doi pointeri spre obiecte de acelasi tip pot fi scazuti; in acest caz rezultatul se converteste spre int sau long in functie de masina; vezi &7.4. 6.5
Intregi fara semn
Ori de cite ori se combina un intreg fara semn si un intreg de tip int, ultimul se converteste spre unsigned si rezultatul este unsigned. Valoarea este cel mai mic intreg fara semn congruent cu intregul cu semn (modulo 2^dimensiunea cuvintului). In reprezentarea prin complement fata de 2, aceasta conversie este conceptuala si in realitate nu exista o schimbare in structura bitilor. Cind un intreg fara semn se converteste spre long, valoarea rezultatului este numeric aceeasi cu cea a intregului fara semn. Astfel conversia are ca rezultat completarea cu zerouri nesemnificative la stinga. 6.6
Conversii aritmetice
Un numar mare de operatori conduc la conversii si produc rezultate de un tip similar cu tipurile descrise mai sus. Aceste conversii vor fi numite "conversii aritmetice uzuale". orice operanzi de tip char, unsigned char sau short se convertesc spre int.
daca unul din operanzi este double, atunci si celalalt se converteste spre double si acesta este tipul rezultatului. altfel daca unul din operanzi este unsigned long atunci si celalalt se converteste spre unsigned long si acesta este tipul rezultatului. altfel, daca unul dintre operanzi este long, celalalt este convertit spre long si acesta este tipul rezultatului. altfel, daca unul din operanzi este unsigned, celalalt se converteste spre unsigned si acesta este tipul rezultatu lui. altfel, ambii operanzi trebuie sa fie int si acesta este tipul rezultatului. 6.7
Conversii de pointeri
Conversiile urmatoare pot fi facute ori de cite ori se atribuie, se initializeaza sau se compara pointeri. constanta 0 poate fi convertita spre un pointer si se garanteaza ca aceasta valoare va produce un pointer dis tinct de orice pointer spre orice obiect. un pointer spre orice tip poate fi convertit spre un void*. un pointer spre o clasa poate fi convertit spre un pointer spre o clasa de baza publica a acelei clase; vezi &8.5.3. un nume al unui vector poate fi convertit spre un pointer spre primul lui element. un identificator care se declara ca "functie ce returneaza ..." cind se utilizeaza altundeva decit ca nume intr-un apel de functiei, se converteste in pointer spre "functia ce returneaza ...". 6.8
Conversii de referinte
Conversia urmatoare poate fi facuta ori de cite ori se initializeaza referintele. o referinta la o clasa poate fi convertita spre o referin ta spre o clasa de baza publica a acelei clase; vezi &8.6.3. 7 Expresii Precedenta operatorilor unei expresii este aceeasi cu ordinea subsectiunilor majore ale acestei subsectiuni, intii fiind precedenta cea mai inalta. Astfel, de exemplu, expresiile care se refera la operanzii lui + (&7.4) sint acele expresii care sint definite in &7.1-&7.4. Operatorii din fiecare subsectiune au aceeasi precedenta. Asociativitatea stinga sau dreapta este specificata in fiecare subsectiune pentru operatorii discutati in ea. Precedenta si asociativitatea tuturor operatorilor unei expresii este rezumata in gramatica din &14. Altfel ordinea evaluarii expresiilor este nedefinita. In particular compilatorul considera ca el este liber sa calculeze subexpresiile in ordinea in care el considera ca acest lucru este cel mai eficient, chiar daca subexpresiile implica efecte secundare.
Ordinea in care au loc efectele secundare nu este specificata. Expresiile care implica un operator comutativ si unul asociativ (*, +, &, |, ^) pot fi rearanjate arbitrar, chiar si in prezenta parantezelor; pentru a forta o ordine particulara a evaluarii trebuie sa se utilizeze un temporar explicit. Tratarea depasirilor si verificarea impartirii intr-o evaluare de expresie este dependenta de masina. Majoritatea imple mentarilor existente ale lui C++ ignora depasirile de intregi, tratarea impartirii la zero si toate exceptiile flotante difera de la masina la masina si de obicei se ajusteaza printr-o functie de biblioteca. In plus fata de intelesul standard descris in &7.2-&7.15 operatorii pot fi supraincarcati, adica li se dau sensuri cind se aplica la tipuri definite de utilizator; vezi &7.16. 7.1
Expresii primare
Expresiile primare implica . -> :: indexare si apel de functie grupindu-se de la stinga la dreapta. expression_list: expression expression_list, expression id: identifier operator_function_name typedef_name :: identifier typedef_name :: operator_function_name primary_expression: id :: identifier constant string this (expression) primary_expression[expression] primary_expression(expression_list opt) primary_expression.id primary_expression->id Un identificator este o expresie primara, cu conditia ca el sa aiba o declaratie potrivita (&8). Un operator_function_name este un identificator cu un inteles special; vezi &7.16 si &8.5.11.
Operatorul :: urmat de un identificator din domeniul fisierului este acelasi lucru cu identificatorul. El permite unui obiect sa fie referentiat chiar daca identificatorul lui a fost ascuns (&4.1). Un typedef_name (&8.8) urmat de :: si de un identificator este o expresie primara. Typedef_name trebuie sa noteze o clasa (&8.5) iar identificatorul trebuie sa noteze un membru al acelei clase. Tipul lui se specifica printr-o declaratie de identificator. Type_name poate fi ascuns printr-un nume non_type; in acest caz typedef_name poate fi inca gasit si utilizat. O constanta este o expresie primara. Tipul ei poate fi int, long, float sau double in functie de forma ei. Un sir este o expresie primara. Tipul lui este "tablou de caractere". El este de obicei convertit imediat spre un pointer spre primul lui caracter (&6.7). Cuvintul cheie this este o variabila locala din corpul unei functii membru (vezi &8.5); este un pointer spre obiectul pentru care functia a fost apelata. O expresie in paranteze este o expresie primara a carui tip si valoare sint identice cu a expresiei fara paranteze. Prezenta parantezelor nu afecteaza faptul ca expresia este o lvaloare. O expresie primara urmata de o expresie in paranteze patrate este o expresie primara. Sensul intuitiv este acela al unui indice. De obicei, expresia primara are tipul "pointer spre ...", expresia indice este int, iar tipul rezultatului este "...". Expresia E1[E2] este identica (prin definitie) cu *((E1) + (E2)). Toate cheile necesare intelegerii acestei notatii sint continute in aceasta sectiune impreuna cu discutiile din &7.1, &7.2 si &7.4 despre identificatori, * si respectiv +; &8.4.2 rezuma mai jos implicatiile. Apelul unei functii este o expresie primara urmata de paranteze care contin o lista de expresii separate prin virgula, care este posibil sa fie si vida, iar expresiile formeaza argumentele reale ale functiei. Expresia primara trebuie sa fie de tipul "functie care returneaza ... " sau "pointer spre o functie care returneaza ... " iar rezultatul apelului functiei este de tipul "...". Fiecare argument formal se initializeaza cu argumentul actual al lui (&8.6). Se fac conversii standard (&6.6-&6.8) si conversii definite de utilizator (&8.5.6). O functie poate schimba valorile argumentelor ei formale, dar aceste schimbari nu pot afecta valorile argumentelor actuale exceptind cazul in care argumentele formale sint de tip referinta (&8.4). O functie poate fi declarata ca sa accepte mai putine sau mai multe argumente decit sint specificate in declaratia de functie (&8.4). Orice argument real de tip float pentru care nu exista un argument formal se converteste inaintea apelului spre double; cel de tip char sau short se converteste spre int si ca de obicei, numele de tablouri se convertesc spre pointeri. Ordinea de evaluare a argumentelor este nedefinita prin limbaj; sa luam nota de faptul ca compilatoarele difera intre ele. Apelurile recursive sint permise la orice functie. O expresie primara urmata de un punct si de un identificator (sau un identificator calificat printr-un typedef_name utilizind operatorul ::) este o expresie. Prima
expresie trebuie sa fie un obiect al unei clase, iar identificatorul trebuie sa numeasca un membru al acelei clase. Valoarea este membrul numit al obiectului si el este o lvaloare daca prima expresie este o lvaloare. Sa observam ca "obiectele unei clase" pot fi structuri (&8.5.12) sau reuniuni (&8.5.13). O expresie primara urmata de o sageata (->) si de un identificator (sau un identificator calificat printr-un typedef_name utilizind operatorul ::) este o expresie. Prima expresie trebuie sa fie un pointer la un obiect al unei clase iar identificatorul trebuie sa numeasca un membru al acelei clase. Rezultatul este o lvaloare care referentiaza membrul numit al clasei spre care pointeaza expresia pointer. Astfel expresia E1->MOS este acelasi lucru cu (*E1).MOS. Clasele se discuta in &8.5. Daca o expresie are tipul "referinta la ..." (vezi &8.4 si &8.6.3) valoarea expresiei este obiectul notat prin referinta. O referinta poate fi gindita ca un nume al unui obiect (&8.6.3). 7.2
Operatori unari
Expresiile cu operatori unari se grupeaza de la dreapta la stinga. unary_expression: unary_operator expression expression++ expression-sizeof expression sizeof(type_name) (type_name) expression simple_type_name (expression_list) new type_name initializer_opt new (type_name) delete expression delete [expression] expression unary_operator: unul dintre * & + - ! ~ ++ -Operatorul unar * inseamna indirectare: expresia trebuie sa fie un pointer, iar rezultatul este o lvaloare care se refera la un obiect spre care pointeaza expresia. Daca tipul expresiei este "pointer spre ..." tipul rezultatului este "... ".
Rezultatul operatorului unar & este un pointer spre obiectul referit de operand. Operandul trebuie sa fie o lvaloare. Daca ti- pul expresiei este "...", atunci tipul rezultatului este "pointer spre ...". Rezultatul operatorului unar + este valoarea operandului sau valoarea rezultata in urma conversiilor aritmetice obisnuite. Operandul trebuie sa fie de tip aritmetic. Rezultatul operatorului unar - este negativarea operandului sau. Operandul trebuie sa fie de tip aritmetic. Se fac conversii aritmetice obisnuite. Negativarea unei cantitati fara semn se calculeaza scazind valoarea ei din 2^n unde n este numarul de biti dintr-un int. Rezultatul operatorului de negatie logica ! este 1 daca valoarea operandului sau este 0, si este 0 daca valoarea operandului sau este diferita de zero. Tipul operandului este int. Se aplica la orice tip aritmetic sau la pointeri. Operatorul ~ produce complementul fata de 1 al operandului sau. Se fac conversii aritmetice uzuale. Tipul operandului trebuie sa fie intreg. 7.2.1 Incrementare si Decrementare Operandul prefixului ++ este incrementat. Operandul trebuie sa fie o lvaloare. Expresia ++x este echivalenta cu x += 1. Vezi discutiile despre adunare (&7.4) si operatorii de asignare (&7.14) pentru informatii despre conversii. Operandul prefixat prin -- se decrementeaza in mod analog ca si in cazul operatorului prefix ++. Valoarea obtinuta prin aplicarea unui operator ++ postfix este valoarea operandului. Operandul trebuie sa fie o lvaloare. Dupa ce este luat in evidenta rezultatul; obiectul este incrementat in aceeasi maniera ca si operatorul prefix ++. Tipul rezultatului este acelasi ca si tipul operandului. Valoarea obtinuta prin aplicarea unui operator -postfix este valoarea operandului. Operandul trebuie sa fie o lvaloare. Dupa ce rezultatul este luat in evidenta, obiectul este decremen- tat in aceeasi maniera ca si pentru operatorul prefix --. Tipul rezultatului este acelasi cu al operandului. 7.2.2 Sizeof Operatorul sizeof produce dimensiunea in octeti a operandului sau. (Un octet este nedefinit prin limbaj cu exceptia terme- nilor valorii lui sizeof. Cu toate acestea, in toate implementarile existente un octet este spatiul cerut pentru a pastra un caracter.) Cind se aplica la un tablou, rezultatul este numarul total de octeti din tablou. Dimensiunea se determina din declaratiile obiectelor dintr-o expresie. Expresia este semantic o constanta fara semn si poate fi utilizata oriunde se cere o constanta. Operatorul sizeof se poate aplica de asemenea la un nume de tip in paranteze. In acest caz el produce dimensiunea in octeti a unui obiect de tip indicat.
7.2.3 Conversia explicita de tip Un simple_type_name inclus optional in paranteze (&8.2) urmat de o expresie in paranteze (sau o lista de expresii daca ti- pul este o clasa cu un constructor declarat in mod corespunzator &8.5.5) face ca valoarea expresiei sa fie convertita spre tipul denumit. Pentru a exprima conversia spre un tip care nu are un nume simplu, trebuie inclus in paranteze numele tipului (&8.7). Daca numele tipului este in paranteze, expresia nu este necesar sa fie in paranteze. Aceasta constructie se numeste cast. Un pointer poate fi convertit explicit spre orice tip de intregi care sint destul de mari pentru a le pastra. Ori de cite ori se cere un int sau long, acest lucru este dependent de masina. Functia de transformare este de asemenea dependenta de masina, dar se intentioneaza ca aceasta sa nu fie o surpriza pentru cei care cunosc structura de adresare a masinii. Detalii despre anumite masini particulare se dau in &2.6. Un obiect de tip intreg se poate converti in mod explicit spre un pointer. Transformarea totdeauna face ca un intreg convertit dintr-un pointer sa revina inapoi la acelasi pointer, dar printre altele ea este dependenta de masina. Un pointer spre un tip poate fi convertit explicit spre un pointer spre un alt tip. Pointerul rezultat poate provoca ex ceptii de adresare la utilizare daca pointerul care se converteste nu se refera la un obiect aliniat in memorie in mod cores- punzator. Se garanteaza ca un pointer spre un obiect de o dimensiune data poate fi convertit spre un pointer spre un obiect cu o dimensiune mai mica si din nou inapoi fara a face schimbari. Diferite masini pot diferi in numarul de biti in pointeri si in cerintele de aliniere pentru obiecte. Agregatele se aliniaza la limita cea mai stricta ceruta de oricare din componentele lor. Un obiect poate fi convertit spre o clasa de obiecte numai daca a fost declarat un constructor potrivit sau un operator de conversie (&8.5.6). Un obiect poate fi convertit explicit spre o referinta de tip X& daca un pointer spre acel obiect poate fi convertit explicit spre un X*. 7.2.4 Memoria libera Operatorul new creaza un obiect de tipul type_name (vezi &8.7) la care se aplica el. Durata de viata a unui obiect creat prin new nu este restrinsa la domeniul in care se creaza. Operatorul new returneaza un pointer la obiectul pe care il creaza. Cind acel obiect este un tablou se returneaza un pointer la primul sau element. De exemplu, atit new int, cit si new int[10] returneaza un int*. Se poate furniza un initializator pentru anumite obiecte de clasa (&8.6.2). Pentru a obtine memorie operatorul new (&7.2) va apela functia: void* operator new(long);
Argumentul specifica numarul de octeti cerut. Memoria va fi neinitializata. Daca operatorul new() nu poate gasi cantitatea de memorie ceruta, atunci el va returna valoarea zero. Operatorul delete va distruge un obiect creat prin operatorul new. Rezultatul este void. Operandul lui delete trebuie sa fie un pointer returnat de new. Efectul aplicarii lui delete la un pointer care nu este obtinut prin operatorul new este nedefinit. Cu toate acestea, stergind un pointer cu valoarea zero este inofensiv. Pentru a elibera memorie operatorul delete va apela functia: void operator delete(void*); In forma: delete [expression] expression cea de a doua expresie pointeaza spre un vector iar prima expresie da numarul de elemente al acelui vector. Specificarea numarului de elemente este redondant exceptind cazul cind se sterg vectori de anumite clase (vezi &8.5.8).
7.3
Operatori multiplicatori
Operatorii multiplicatori *, / si % se grupeaza de la stinga la dreapta. Se fac conversii aritmetice obisnuite. multiplicative_expression expression * expression expression / expression expression % expression Operatorul binar * indica inmultire. Operatorul * este asociativ si expresia cu diferite inmultiri la acelasi nivel poate fi rearanjata de compilator. Operatorul / indica impartire. Cind intregii pozitivi se impart trunchierea este zero; dar forma trunchierii este depen- denta de masina daca operandul este negativ. Pe masinile indicate in acest manual, restul are acelasi semn cu deimpartitul. Este totdeauna adevarat ca (a / b) * b + a % b este egal cu a (daca b nu este zero). Operatorul binar % produce restul impartirii primei expresii prin cea de a doua. Se fac conversii aritmetice uzuale. Operanzii trebuie sa nu fie flotanti. 7.4
Operatori aditivi
Operatorii aditivi + si - se grupeaza de la stinga la dreapta. Se fac conversii aritmetice obisnuite. Exista unele posibilitati de tip suplimentare pentru fiecare operator. aditive_expression:
expression + expression expression - expression Rezultatul operatorului + este suma operanzilor. Un pointer spre un obiect dintr-un tablou poate fi adunat cu o valoare de tip intreg. Ultimul este in toate cazurile convertit spre un deplasament inmultindu-l prin lungimea obiectului spre care pointeaza acel pointer. Rezultatul este un pointer de acelasi tip ca si pointerul original si care pointeaza spre un alt obiect din acelasi tablou, potrivit deplasamentului fata de obiectul original. Astfel daca P este un pointer spre un obiect dintr-un ta- blou, expresia P + 1 este un pointer spre obiectul urmator din tablou. Nu sint admise alte combinatii de tip pentru pointeri. Operatorul + este asociativ si expresiile cu diferite adunari la acelasi nivel pot fi rearanjate de compilator. Rezultatul operatorului – este diferenta dintre operanzi. Se fac conversii aritmetice obisnuite. In plus, o valoare de tip intreg poate fi scazuta dintr-un pointer si apoi se aplica aceleasi conversii ca si pentru adunare. Daca doi pointeri spre obiecte de acelasi tip se scad, rezultatul sete convertit (impartind la lungimea obiectului) la un intreg ce reprezinta numarul de obiecte care separa obiectele pointate. Depinzind de masina, intregul rezultat poate fi de tip int sau long (&2.6). Aceasta conversie va da in general un rezultat neasteptat daca pointerii nu pointeaza spre obiecte din acelasi tablou, intrucit pointerii, chiar spre obiecte de acelasi tip, nu difera in mod necesar printr-un multiplu de lungimea obiectului. 7.5
Operatori de deplasare
Operatorii de deplasare > se grupeaza de la stinga la dreapta. Ambii realizeaza conversii aritmetice obisnuite asupra operanzilor lor, fiecare din ei trebuind sa fie de tip intreg. Apoi operandul drept se converteste spre int. Tipul rezultatului este cel al operandului sting. Rezultatul este nedefinit daca operandul drept este negativ sau este mai mare sau egal decit lungimea obiectelor in biti. shift_expression: expression > expression Valoarea lui E1 expression expression = expression Operatorii < (mai mic decit), > (mai mare decit), = (mai mare sau egal cu) produc zero daca relatia specificata este falsa si unu daca este adevarata. Tipul rezultatului este int. Se fac conversii aritmetice obisnuite. Doi pointeri pot fi comparati; rezultatul depinde de locatiile relative din spatiul de adrese al obiectelor pointate. Comparatia de pointeri este portabila numai cind pointerii pointeaza spre obiecte din acelasi tablou. 7.7
Operatori de egalitate
equality_expression: expression == expression expression != expression Operatorii == (egal) si != (diferit) sint analogi cu operatorii de relatie exceptind precedenta mai mica a lor. (Astfel aa=i; } void private::member_set(int i){ a=i; }; private obj; friend_set(&obj, 10); obj.member_set(10); Cind o declaratie friend se refera la un nume sau la un operator supraincarcat numai functia specificata prin tipurile argument devine un prieten. Un membru al unei clase cl1 poate fi prietenul clasei cl2. De exemplu: class cl2{ friend char* cl1::foo(int); // ... }; Toate functiile unei clase cl1 pot fi facute prietene ale clasei cl2 printr-o singura declaratie: class cl2{ friend class cl1; //...... }; O functie friend definita (&10) intr-o declaratie de clasa este inline.
8.5.11Functii operator ---------------Cei mai multi operatori pot fi supraincarcati astfel incit sa aiba ca operanzi obiecte de clasa. operator_function_name: operator operator operator: unul din new delete + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= > >>= b) ? a : b; return (m>c) ? m : c; } Aici int este specificatorul de tip; max(int a,int b, intc) este fct_declarator; { ... } este corpul functiei. Intrucit in contextul unei expresii un nume de tablou (in particular ca argument efectiv) se ia drept pointer la primul element al tabloului, declaratia de argument formal "array of..." se ajusteaza pentru a fi citit ca "pointer la ...". Initializatorii pentru o clasa de baza si pentru membri pot fi specificati in definitia constructorului. Aceasta este cel mai util pentru obiectele de clasa, constante si referinte unde semanticile de initializare si asignare difera. Un initializator al bazei are forma: base_initializer: :member_initializer_list member_initializer_list: member_initializer member_initializer, member_initializer_list member_initializer: identifier_opt(argument_list_opt) Daca identifier este prezent intr-un member_initializer argumentul lista se utilizeaza pentru clasa de baza. De exemplu: struct base{ base(int); // ... }; struct derived : base{ derived(int); base b; const c; }; derived::derived(int a) : (a+1), b(a+2), c(a+3){ /* ... */ } derived d(10); Intii, se apeleaza constructorul clasei de baza base::base() pentru obiectul d cu argumentul 11; apoi constructorul pentru membrul b cu argumentul 12 si constructorul pentru membrul c cu argumentul 13; apoi se executa corpul derived::derived() (vezi &8.5.5). Ordinea in care se apeleaza constructorii pentru membri este nespecificata. Daca clasa de baza are un constructor care poate fi apelat fara argumente, nu se furnizeaza nici o lista de argumente. Daca membrul unei clase are un constructor care poate fi apelat fara argumente, atunci nu este necesar sa se furnizeze nici un argument pentru acel membru. 11 Linii de control ale compilatorului
Compilatorul contine un preprocesor capabil de macrosubstitutie, compilare conditionala si incluziune de fisiere denumite. Liniile care incep cu # comunica cu acest preprocesor. Aceste linii au sintaxa independenta de restul limbajului; ele pot apare oriunde si au efecte independente de domeniu si sint valabile pina la sfirsitul fisierului cu programul sursa. Sa observam ca definitiile const si inline sint o alta alternativa fata de multe utilizari ale lui #define. 11.1 Substitutia de siruri O linie de control a compilatorului de forma: #define identifier token_string face ca preprocesorul sa inlocuiasca intrarile ulterioare ale lui identifier cu sirul token_string dat. Punctul si virgula din token_string sau de la sfirsitul lui sint parte a sirului de substitutie. O linie de forma: #define identifier(identifier, ..., identifier) token_string unde nu exista spatiu intre identificator si '(', este macrodefinitie cu argumente. Intrarile ulterioare ale primului identificator urmat de '(' si de siruri delimitate prin virgula si terminate prin ')' se inlocuiesc prin token_string din definitie. Fiecare aparitie a unui identificator mentionat in lista argumentelor formale a definitiei se inlocuieste prin sirul corespunzator de la apel. Argumentele efective din apel sint sirurile separate prin virgule; virgulele din sirurile incluse intre ghilimele nu separa argumente. Numarul argumentelor formale si reale trebuie sa fie acelasi. Sirurile si constantele caracter din token_string sint analizate pentru descoperirea argumentelor formale. O definitie lunga poate fi continuata pe o alta linie utilizind \ la sfirsitul liniei de continuat. O linie de forma: #undef identifier face ca definitia preprocesor a lui identifier sa fie anulata. 11.2 Incluziune de fisiere O linie de control a compilatorului de forma: #include "filename" face ca linia respectiva sa fie inlocuita prin continutul fisierului filename. Fisierul denumit este cautat intii in directorul fisierului sursa, apoi intr-o secventa de locuri specificate standard. O linie de control de forma: #include cauta filename numai in locurile specificate standard si nu si in directorul fisierului sursa (cum se specifica locurile standard nu este parte a limbajului). Directivele #include pot fi imbricate.
11.3 Compilarea conditionata O linie de control a compilatorului de forma: #if expression verifica daca expresia este diferita de zero. Expresia trebuie sa fie o expresie constanta (&12). In plus fata de operatiile obisnuite din C++ se poate utiliza un identificator unar. Acesta cind se aplica la un identificator, atunci valoarea lui este diferita de zero daca identificatorul respectiv a fost definit utilizind #define si nu s-a utilizat ulterior pentru el #undef; altfel valoarea lui este zero. O linie de control de forma: #ifdef identifier verifica daca identifier este definit curent in preprocesor, adica daca el a fost obiectul unei linii de control #define. O linie de control de forma: #ifndef identifier verifica daca identifier este nedefinit curent in preprocesor. Toate cele trei forme sint urmate de un numar arbitrar de linii, care pot contine si o linie de control: #else si apoi de linia de control: #endif Daca conditia verificata este adevarata, atunci liniile dintre #else si #endif sint ignorate. Daca conditia verificata este falsa, atunci toate liniile dintre cea de test si #else sau, in lipsa lui #else, #endif sint ignorate. Aceste constructii pot fi imbricate. 11.4 Linie de control In beneficiul altor preprocesoare care genereaza programe C++, o linie de forma: #linie constant "filename" face ca, compilatorul sa considere ca numarul de linie al liniei sursa urmatoare se da printr-o constanta, iar fisierul de intrare curent este denumit prin identificator. Daca identificatorul lipseste, numele fisierului nu se schimba. Aceasta se face pentru a elimina erorile. 12 Expresii constante In diferite locuri C++ cere expresii care se evalueaza ca o constanta: cum ar fi limitele unui tablou (&8.4), expresiile case (&9.7) argumentele implicite ale functiilor (&8.4) si initializatorii (&8.6). In ultimul caz expresia poate implica numai
constante intregi, constante caracter, constante enumerative, valori const care nu sint agregate initializate cu expresii constante si expresii sizeof care pot fi legate prin operatorii binari: + - * / % & | ^ > == != < > = && || sau cei unari: +
- ~
!
sau prin operatorul ternar: ?: Parantezele pot fi utilizate pentru grupari, dar nu pentru apeluri de functii. In alte cazuri expresiile constante pot de asemenea sa contina operatorul unar & aplicat la obiecte statice sau externe, sau la tablouri statice sau externe indexate cu o expresie constanta. Unarul & poate fi aplicat implicit prin aparitia unui tablou fara indici sau a unei functii. Regula de baza este ca initializatorii trebuie evaluati sau ca o constanta sau ca adresa a unui obiect declarat in prealabil static sau extern + sau - o constanta. O posibilitate mai mica este atinsa pentru o expresie constanta dupa #if; nume declarate const, expresii sizeof si constante enumerative nu sint admise.
13 Consideratii de portabilitate Anumite parti ale lui C++ sint inerent dependente de masina. Urmarind lista necazurilor potentiale, bulinele nu inseamna ca vor apare toate "necazurile", dar se sublinieaza unele dintre principalele necazuri. Caracteristicile curate hardware cum este marimea unui cuvint, proprietatile aritmeticii flotante si impartirea intreaga in practica au dovedit ca acestea nu constituie prea mult o problema. Alte aspecte ale hardware-ului sint reflectate in diferite implementari. Unele dintre acestea, in particular extensia de semn (care converteste un caracter negativ intr-un intreg negativ) si ordinea in care octetii sint plasati in cuvint este o pacoste care trebuie privita cu multa grija. Majoritatea necazurilor celorlalte reprezinta doar probleme minore. Numarul variabilelor registru care pot fi in realitate plasate in registrii variaza de la masina la masina, asa cum este de fapt si cu setul tipurilor valide. Nu mai putin,
toate compilatoarele fac lucruri proprii masinii pentru care el a fost construit; declaratiile de variabile registru incorecte sau in exces sint ignorate. Ordinea evaluarii argumentelor functiilor nu este specificata de catre limbaj. Aceasta ordine este de la dreapta la stinga pentru unele masini si de la stinga la dreapta pentru altele. De cind constantele caracter sint obiecte reale ale tipului int, sint permise si constantele caracter multi-caracter. Implementarea specifica este foarte dependenta de masina deoarece ca- racterele sint asignate de la stinga la dreapta pentru unele masini si de la dreapta la stinga pentru altele. 14 Sumar de sintaxa Acest sumar al sintaxei C++ se intentioneaza sa fie un ajutor pentru intelegerea limbajului. Ceea ce se prezinta nu sint instructiuni exacte ale limbajului. 14.1 Expresii expression: term expression binary_operator expression expression ? expression : expression expression_list expression_list: expression expression_list, expression term: primary_expression unary_operator term term++ term-sizeof expression sizeof (type_name) (type_name) expression simple_type_name (expression_list) new type_name initializer_opt new (type_name) delete expression delete [expression] expression
special_operator: () [] free_store_operator: one of new delete abstract_declarator: empty *abstract_declarator abstract_declarator (argument_declaration_list) [constant_expression_opt] simple_type_name: typedef_name char short int long unsigned float double void typedef_name: identifier 14.2 Declaratii declaration: decl_specifiers_opt declarator_list_opt; name_declaration asm declaration name_declaration: aggr identifier; enum identifier; aggr: class struct union asm_declaration: asm (string); decl_specifiers: decl_specifier decl_specifiers_opt decl_specifier: sc_specifier type_specifier fct_specifier friend typedef type_specifier:
abstract_declarator
simple_type_name class_specifier enum_specifier elaborated_type_specifier const sc_specifier: auto extern register static fct_specifier: inline overload virtual elaborated_type_specifier: key typedef_name key identifier key: class struct union enum declarator_list: init_declarator init_declarator, declarator_list init_declarator: declarator initializer_opt declarator: dname (declarator) const_opt declarator & const_opt declarator declarator [constant_expression_opt] dname: simple_dname typedef_name::simple_dname simple_dname: identifier typedef_name ~typedef_name operator_function_name
(argument_declaration_list)
declarator
conversion_function_name operator_function_name: operator operator conversion_function_name: operator type argument_declaration_list: arg_declaration_list_opt ..._opt arg_declaration_list: arg_declaration_list, argument_declaration argument_declaration argument_declaration: decl_specifiers declarator decl_specifiers declarator = expression decl_specifiers abstract_declarator decl_specifiers abstract_declarator = expression class_specifiers: class_head { member_list_opt } class_head { member_list_opt public:member_list_opt } class_head: aggr identifier_opt aggr identifier:public_opt typedef_name member_list: member_declaration member_list_opt member_declaration: decl_specifiers_opt member_declarator initializer_opt function_definition;_opt member_declarator: declarator identifier_opt:constant_expression initializer: = expression = { initializer_list } = { initializer_list, } ( expression_list ) initializer_list: expression initializer_list, initializer_list { initializer_list } enum_specifier: enum identifier_opt { enum list } enum_list: enumerator enum_list, enumerator enumerator: identifier
identifier = constant_expression 14.3 Instructiuni compound_statement: { statement_list_opt } statement_list: statement statement statement_list statement: declaration compound_statement expression_opt; if(expression) statement if(expression) statement else statement while(expression) statement do statement while(expression); for(statement expression_opt;expression_opt) statement switch(expression) statement case constant_expression : statement default : statement break; continue; return expression_opt; goto identifier; identifier : statement;
14.4 Definitii externe program: external_definition external_definition program external_definition funtion_definition declaration function_definition decl_specifiers_opt fct_declarator base_initializer_opt fct_body fct_declarator: declarator(argument_declaration_list) fct_body: compound_statement base_initializer:
:member_initializer_list member_initializer_list: member_initializer member_initializer, member_initializer_list member_initializer: identifier_opt (argument_list_opt) 14.5 Preprocesor #define identifier token_string #define identifier(identifier,..., identifier) token_string #else #endif #if expression #ifdef identifier #ifndef identifier #include "filename" #include #line constant "filename" #undef identifier
15 Diferente fata de C 15.1 Extensii Tipurile argumentelor unei functii pot fi specificate (&7.1) si vor fi verificate (&7.1). Vor avea loc si conversiile de tip (&7.1). Aritmetica flotanta in simpla precizie poate fi folosita pentru expresii flotante (&6.2). Numele functiilor pot fi supraincarcate (&8.9). Operatorii pot fi supraincarcati (&7.16, &8.5.11). Functiile pot fi substituite inline (&8.1). Obiectele data pot fi constante (&8.4). Pot fi declarate obiecte ale tipului referinta (&8.4, &8.6.3). Alocarea si dealocarea sint furnizate de operatorii new si delete (&7.2). Clasele pot furniza incapsularea datelor (&8.5.9), garanteaza initializarea (&8.6.2), conversiile definite de utilizator (&8.5.6) si tipizarea dinamica prin folosirea functiilor virtuale (&8.5.4). Numele unei clase sau enumerari este un nume de tip (&8.5). Orice pointer poate fi asignat spre void* fara folosirea unei matrite (&7.14).
O declaratie in interiorul unui bloc este o instructiune Pot fi declarate reuniuni fara nume (&8.5.13).
(&9.14).
15.2 Sumar de incompatibilitati Multe constructii in C sint legale in C++, intelesul lor raminind neschimbat. Exceptiile sint urmatoarele: Programele C care folosesc unul din noile cuvinte cheie: class const delete friend inline new operator overload public signed this virtual volatile ca identificatori, nu sint corecte. In C++ declaratia functiei f() inseamna ca f nu primeste argumente, pe cind in C aceasta inseamna ca f poate lua argumente de orice tip. In C un nume extern poate fi definit de mai multe ori, pe cind in C++ trebuie sa fie definit exact o data. Numele de clase din C++ se afla in acelasi domeniu al numelor valabil si pentru celelalte nume, lucru ilustrat in urmatoarele constructii: int s; struct s { /*...*/ }; void f() { int s; struct s a; } void g() { ::s = 1; } 15.3 Anacronisme Extensiile prezentate aici pot fi furnizate pentru a face mai usoara utilizarea programelor C ca programe C++. Notati ca fiecare dintre aceste particularitati prezinta aspecte neastepta- te. O implementare care furnizeaza aceste extensii de asemenea poate furniza utilizatorului o cale de a se asigura ca aceste lucruri nu vor apare in fisierul sursa. Numele inca nedefinite pot fi utilizate intr-un apel ca si numele de functii. In acest caz numele trebuie implicit declarat ca o functie ce returneaza int cu tipul argumentului (...). Cuvintul cheie void poate fi folosit pentru a indica faptul ca functia nu primeste argumente;deci void este echivalent cu (). Programe utilizind sintaxa C pentru definirea functiilor. old_function_definition: decl_specifiers_opt old_function_declarator declaration_list fct_body old_function_declarator: declarator (parameter_list) parameter_list:
identifier identifier, identifier de exemplu, functia: max(a, b){ return (a
View more...
Comments