Limbajul de Programare C++ (Tutorial)

Embed Size (px)

Citation preview

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.

=================================================================

CAP.1 === "TUTORUL" LUI C++ 1

1.1. Introducere 1

1.1.1. Iesire 1

1.1.2. Compilare 1

1.1.3. Intrare 1

1.2. Comentariu 2

1.3. Tipuri si Declaratii 2

1.3.1. Tipuri fundamentale 2

1.3.2. Tipuri derivate 3

1.4. Expresii si Instructiuni 3

1.5. Functii 5

1.6. Structura programului 6

1.7. Clase 7

1.8. Operatorul overloading 8

1.9. Referinte 9

1.10. Constructori 10

1.11. Vectori 11

1.12. Expandare inline 13

1.13. Clase derivate 13

1.14. Mai mult despre operatori 15

1.15. Prieteni (Friends) 17

1.16. Vectori generici 18

1.17. Vectori polimorfici 18

1.18. Functii virtuale 20

CAP.2 === DECLARATII SI CONSTANTE 21

2.1. Declaratii 21

2.1.1. Domeniu 22

2.1.2. Obiecte si Lvalori 24

2.1.3. Durata de viata 24

2.2. Nume 25

2.3. Tipuri 25

2.3.1. Tipuri fundamentale 26

2.3.2. Conversia implicita de tip 27

2.3.3. Tipuri derivate 28

2.3.4. Void 29

2.3.5. Pointeri 30

2.3.6. Vectori 31

2.3.7. Pointeri si Vectori 32

2.3.8. Structuri 34

2.3.9. Echivalenta tipurilor 36

NUME PAG.

=================================================================

2.3.10. Referinte 36

2.3.11. Registrii 39

2.4. Constante 40

2.4.1. Constante intregi 40

2.4.2. Constante in flotanta 41

2.4.3. Constante caracter 41

2.4.4. Siruri 42

2.4.5. Zero 43

2.4.6. Const 43

2.4.7. Enumerari 45

2.5. Salvarea spatiului 46

2.5.1. Cimpuri 46

2.5.2. Reuniuni 47

2.6. Exercitii 49

CAP.3 === EXPRESII SI INSTRUCTIUNI 51

3.1. Un calculator de birou 51

3.1.1. Analizorul 52

3.1.2. Functia de intrare 56

3.1.3. Tabela de simboluri 58

3.1.4. Tratarea erorilor 60

3.1.5. Driverul 61

3.1.6. Argumentele liniei de comanda 62

3.2. Sumar de operatori 63

3.2.1. Paranteze rotunde 65

3.2.2. Ordinea de evaluare 66

3.2.3. Incrementare si Decrementare 67

3.2.4. Operatori logici pe biti 68

3.2.5. Conversia tipului 69

3.2.6. Memoria libera 70

3.3. Sumarul instructiunilor 73

3.3.1. Teste 74

3.3.2. Goto 76

3.4. Comentarii si Decalari 77

3.5. Exercitii 79

CAP.4 === FUNCTII SI FISIERE 83

4.1. Introducere 83

4.2. Linkare 84

4.3. Fisiere antet 86

4.3.1. Fisier antet unic 88

4.3.2. Fisiere antet multiple 90

4.3.3. Ascunderea datelor 92

4.4. Fisiere si Module 93

4.5. Cum se construieste o biblioteca 93

4.6. Functii 95

4.6.1. Declaratii de functii 95

4.6.2. Definitii de functii 95

4.6.3. Transferul argumentelor 96

4.6.4. Valoarea returnata 97

4.6.5. Argumente vector 98

4.6.6. Argumente implicite 99

4.6.7. Nume de functii supraincarcate 100

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

5.2.1. Functii membru 114

5.2.2. Clase 115

5.2.3. Autoreferinta 116

5.2.4. Initializare 118

5.2.5. Curatire (Stergere) 120

5.2.6. In linie 121

5.3. Interfete si Implementari 121

5.3.1. Implementari alternative 122

5.3.2. O clasa completa 125

5.4. Prieteni si Reuniuni 128

5.4.1. Prieteni 128

5.4.2. Calificarea numelor membre 131

5.4.3. Clase imbricate 131

5.4.4. Membri statici 132

5.4.5. Pointeri spre membri 133

5.4.6. Structuri si Reuniuni 134

5.5. Constructori si Destructori 137

5.5.1. Goluri 137

5.5.2. Memoria statica 138

5.5.3. Memoria libera 139

5.5.4. Obiectele clasei de membri 140

5.5.5. Vectori si Obiecte clasa 142

5.5.6. Obiecte mici 143

5.5.7. Goluri 144

5.5.8. Obiecte de dimensiune variabila 145

5.6. Exercitii 147

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

6.7. Indexare 160

6.8. Apelul unei functii 162

6.9. O clasa sir 163

6.10. Prieteni si Membri 166

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

7.2.8. Functii virtuale 181

7.3. Interfete alternative 183

7.3.1. O interfata 183

7.3.2. O implementare 184

7.3.3. Cum sa o folosim 186

7.3.4. Tratarea erorilor 187

7.3.5. Clase generice 189

7.3.6. Interfete restrictive 190

7.4. Adaugarea la o clasa 191

7.5. Liste eterogene 193

7.6. Un program complet 193

7.6.1. Controlul ecranului 193

7.6.2. Biblioteca de figuri 196

7.6.3. Programul de aplicatie 198

7.7. Memoria libera 200

7.8. Exercitii 202

CAP.8 === STREAMS 205

8.1. Introducere 205

8.2. Iesire 206

8.2.1. Iesirea tipurilor predefinite 206

8.2.2. Iesirea tipurilor definite de

utilizator 207

8.2.3. Citeva detalii de implementare 208

8.2.4. Iesire formatata 209

8.2.5. O functie de iesire virtuala 212

8.3. Fisiere si Streamuri 213

8.3.1. Initializarea streamurilor de

iesire 213

8.3.2. Inchiderea streamurilor de iesire 214

8.3.3. Deschiderea fisierelor 214

8.3.4. Copierea streamurilor 215

8.4. Intrari 215

8.4.1. Introducerea tipurilor predefi-

nite 216

8.4.2. Starile streamului 217

8.4.3. Introducerea tipurilor definite

de utilizator 218

8.4.4. Initializarea streamurilor de

intrare 219

NUME PAG.

=================================================================

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

2.6. Caracteristici hardware 230

3. Notatia sintactica 230

4. Nume si Tipuri 231

4.1. Domenii 231

4.2. Definitii 232

4.3. Linkare 232

4.4. Clase de memorie 232

4.5. Tipuri fundamentale 232

4.6. Tipuri derivate 233

5. Obiecte si Lvalori 233

6. Conversii 234

6.1. Caractere si Intregi 234

6.2. Flotante in simpla si dubla pre-

cizie 234

6.3. Flotante si Intregi 234

6.4. Pointeri si Intregi 235

6.5. Intregi fara semn 235

6.6. Conversii aritmetice 235

6.7. Conversii de pointeri 236

6.8. Conversie de referinta 236

7. Expresii 236

7.1. Expresii primare 237

7.2. Operatori unari 239

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

7.3. Operatori multiplicatori 242

7.4. Operatori aditivi 242

7.5. Operatori de deplasare 243

7.6. Operatori relationali 243

7.7. Operatori de egalitate 244

7.8. Operatorul SI pe biti 244

7.9. Operatorul SAU-EXCLUSIV pe biti 244

NUME PAG.

=================================================================

7.10. Operatorul SAU-INCLUSIV pe biti 244

7.11. Operatorul logic SI 244

7.12. Operatorul logic SAU 245

7.13. Operator conditional 245

7.14. Operatori de asignare 245

7.15. Operatorul virgula 246

7.16. Operatori de supraincarcare 246

7.16.1. Operatori unari 247

7.16.2. Operatori binari 247

7.16.3. Operatori speciali 247

8. Declaratii 247

8.1. Specificatori de clasa de memorie 248

8.2. Specificatori de tip 249

8.3. Declaratori 250

8.4. Intelesul ( sensul ) declaratorilor 251

8.4.1. Exemple 253

8.4.2. Tablouri, Pointeri si Indici 254

8.5. Declaratii de clasa 255

8.5.1. Membri statici 256

8.5.2. Functii membru 257

8.5.3. Clase derivate 258

8.5.4. Functii virtuale 259

8.5.5. Constructori 259

8.5.6. Conversii 260

8.5.7. Destructori 261

8.5.8. Memoria libera 261

8.5.9. Vizibilitatea numelor membri 262

8.5.10. Prieteni 263

8.5.11. Functii operator 264

8.5.12. Structuri 264

8.5.13. Reuniuni 264

8.5.14. Cimpuri de biti 265

8.5.15. Clase imbricate 265

8.6. Initializare 266

8.6.1. Liste initializatoare 266

8.6.2. Obiecte de clasa 267

8.6.3. Referinte 268

8.6.4. Tablouri de caractere 269

8.7. Nume de tip 269

8.8. Typedef 270

8.9. Nume de functii supraincarcate 271

8.10. Declaratii de enumerare 272

8.11. Declaratia ASM 273

9. Instructiuni 273

9.1. Instructiunea expresie 273

9.2. Instructiunea compusa (blocul) 273

9.3. Instructiunea conditionala 274

9.4. Instructiunea WHILE 274

9.5. Instructiunea DO 274

9.6. Instructiunea FOR 274

9.7. Instructiunea SWITCH 275

9.8. Instructiunea BREAK 276

9.9. Instructiunea CONTINUE 276

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

10. Definitii de functii 278

11. Linii de control ale compilatorului 279

11.1. Substitutia de siruri 280

11.2. Incluziune de fisiere 280

11.3. Compilarea conditionata 281

11.4. Linie de control 281

12. Expresii constante 282

13. Consideratii de portabilitate 282

14. Sumar de sintaxa 283

14.1. Expresii 283

14.2. Declaratii 284

14.3. Instructiuni 286

14.4. Definitii externe 286

14.5. Preprocesor 287

15. Diferente fata de C 287

15.1. Extensii 287

15.2. Sumar de incompatibilitati 288

15.3. Anacronisme 288

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.2Definitii

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.3Linkare

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.4Clase 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.5Tipuri 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.6Tipuri 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.1Caractere 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.2Flotante 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.3Flotante 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.5Intregi 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.6Conversii 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.7Conversii 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.8Conversii 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.1Expresii 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.2Operatori 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.1Incrementare 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.2Sizeof

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.3Conversia 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.4Memoria 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.3Operatori 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.4Operatori 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.5Operatori 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.7Operatori 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 operatoroperator: 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_initializermember_initializer, member_initializer_listmember_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 compilatoruluiCompilatorul 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.1Substitutia de siruriO linie de control a compilatorului de forma:#define identifier token_stringface 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_stringunde 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 identifierface ca definitia preprocesor a lui identifier sa fie anulata.11.2Incluziune de fisiereO 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.3Compilarea conditionataO linie de control a compilatorului de forma:#if expressionverifica 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 identifierverifica 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 identifierverifica 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:#endifDaca 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.4Linie de controlIn 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 constanteIn 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 portabilitateAnumite 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 alehardware-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 sintaxaAcest 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 Expresiiexpression:termexpression binary_operator expressionexpression ? expression : expressionexpression_listexpression_list:expressionexpression_list, expressionterm:primary_expressionunary_operator termterm++term--sizeof expressionsizeof (type_name)(type_name) expressionsimple_type_name (expression_list)new type_name initializer_optnew (type_name)delete expressiondelete [expression] expressionspecial_operator: () []free_store_operator: one ofnew delete abstract_declarator:empty*abstract_declaratorabstract_declarator (argument_declaration_list) abstract_declarator [constant_expression_opt]simple_type_name:typedef_namecharshortintlongunsignedfloatdoublevoidtypedef_name:identifier14.2Declaratiideclaration:decl_specifiers_opt declarator_list_opt;name_declarationasm declarationname_declaration:aggr identifier; enum identifier;aggr:classstructunionasm_declaration:asm (string); decl_specifiers:decl_specifier decl_specifiers_opt decl_specifier:sc_specifiertype_specifierfct_specifierfriendtypedeftype_specifier:simple_type_nameclass_specifierenum_specifierelaborated_type_specifierconstsc_specifier:autoexternregisterstaticfct_specifier:inlineoverloadvirtualelaborated_type_specifier: key typedef_namekey identifierkey:classstructunionenumdeclarator_list:init_declaratorinit_declarator, declarator_listinit_declarator:declarator initializer_opt declarator:dname(declarator)const_opt declarator& const_opt declarator declarator (argument_declaration_list) declarator [constant_expression_opt]dname:simple_dnametypedef_name::simple_dnamesimple_dname:identifiertypedef_name~typedef_nameoperator_function_nameconversion_function_nameoperator_function_name:operator operator conversion_function_name:operator type argument_declaration_list:arg_declaration_list_opt ..._opt arg_declaration_list:arg_declaration_list, argument_declarationargument_declarationargument_declaration:decl_specifiers declaratordecl_specifiers declarator = expressiondecl_specifiers abstract_declaratordecl_specifiers abstract_declarator = expressionclass_specifiers:class_head { member_list_opt }class_head { member_list_opt public:member_list_opt }class_head:aggr identifier_optaggr identifier:public_opt typedef_namemember_list:member_declaration member_list_opt member_declaration:decl_specifiers_opt member_declarator initializer_optfunction_definition;_optmember_declarator:declarator identifier_opt:constant_expressioninitializer:= expression= { initializer_list }= { initializer_list, }( expression_list )initializer_list:expressioninitializer_list, initializer_list{ initializer_list }enum_specifier:enum identifier_opt { enum list } enum_list:enumeratorenum_list, enumeratorenumerator:identifieridentifier = constant_expression14.3Instructiunicompound_statement:{ statement_list_opt } statement_list:statementstatement statement_liststatement:declarationcompound_statementexpression_opt;if(expression) statementif(expression) statement else statement while(expression) statement do statement while(expression);for(statement expression_opt;expression_opt) statementswitch(expression) statementcase constant_expression : statementdefault : statementbreak;continue;return expression_opt;goto identifier;identifier : statement;14.4Definitii externeprogram:external_definitionexternal_definition programexternal_definitionfuntion_definition declarationfunction_definitiondecl_specifiers_opt fct_declarator base_initializer_optfct_body fct_declarator:declarator(argument_declaration_list) fct_body:compound_statement base_initializer::member_initializer_list member_initializer_list:member_initializermember_initializer, member_initializer_listmember_initializer:identifier_opt (argument_list_opt)14.5Preprocesor#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 identifier15 Diferente fata de C15.1ExtensiiTipurile 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 (&9.14).Pot fi declarate reuniuni fara nume (&8.5.13).15.2Sumar de incompatibilitatiMulte 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 volatileca 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.3AnacronismeExtensiile 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:identifieridentifier, identifierde exemplu, functia:max(a, b){ return (a