|
Politica de confidentialitate |
|
• domnisoara hus • legume • istoria unui galban • metanol • recapitulare • profitul • caract • comentariu liric • radiolocatia • praslea cel voinic si merele da aur | |
Totul despre C++ | ||||||
|
||||||
1 Introducere
Limbajul de programare C++ este limbajul C extins cu clase, functii inline,
operator de supraincarcare, nume de functie supraincarcat, tipurile constant,
referinta, operatorii de gesti- une a memoriei libere, verificarea argumentelor
functiei si o sintaxa noua de definire a functiilor. Limbajul C este descris
in "The C Programming Language" de Brian W. Kernighan si Dennis M.
Richie, Prentice Hall, 1978. Acest manual a fost derivat din sistemul UNIX V
"The C Programming Language - Reference Manual" cu permisiunea lui
AT&T Ball Laboratories. Diferentele dintre C++ si C sint rezumate in &15.
Manualul descrie limbajul C++ din iunie 1985. o8x16xh 2 Conventii lexicale Exista sase clase de lexicuri: identificatori, cuvinte cheie, constante, siruri,
operatori si alti separatori. Blancuri- le, tabulatori, rindul nou si comentariile
(cu un singur cuvint "spatii albe") asa cum se descrie mai jos se
ignora exceptind faptul ca ele servesc la a separa lexicuri. Anumite spatii
albe se cer pentru a separa printre altele identificatori, cuvinte cheie si
constante adiacente. Caracterele /* incep un comentariu care se termina cu caracterele */. Comentariile nu se vor imbrica. Caracterele // incep un comentariu care se termina in linia in care a fost inceput. 2.2 Identificatori (Nume)Un identificator este un sir de litere si cifre de lungime arbitrara; primul caracter trebuie sa fie o litera; caracterul subliniere _ conteaza ca litera. Literele mari sint diferite de cele mici. 2.3 Cuvinte cheie Identificatorii urmatori sint rezervati pentru a fi utilizati ca si cuvinte
cheie si nu pot fi utilizati in alte scopuri: asm auto break case char class const continue default delete do double else enum extern float for friend goto if inline int long new operator overload public register return short sizeof static struct switch this typedef union unsigned virtual void 2.4 Constante Exista diferite tipuri de constante, asa cum se indica mai jos. Caracteristicile hardware care afecteaza dimensiunile sint rezumate in &2.6. 2.4.1 Constante intregiO constanta intreaga care consta dintr-un sir de cifre se considera in octal daca ea incepe cu 0 (cifra zero) si zecimal in caz contrar. Cifrele 8 si 9 nu fac parte din sistemul de numeratie octal. Un sir de cifre precedate de 0x sau 0X se considera ca fiind un intreg hexazecimal. Cifrele hexazecimale contin si literele a..f respectiv A..F care reprezinta valorile 10..15. O constanta zecimala a carei valoare depaseste intregul cu semn cel mai mare se considera de tip long; o constanta octala sau hexazecimala care depaseste intregul fara semn cel mai mare se conside- ra de tip long; altfel constantele intregi se considera de tip int. 2.4.2 Constante long expliciteO constanta intreaga zecimala, octala sau hexazecimala urmata imediat de litera l sau L este o constanta de tip long. O constanta caracter este un caracter inclus intre caractere apostrof ('x'). Valoarea unei constante caracter este valoarea numerica a caracterului din setul de caractere al calculatorului. Constantele caracter se considera de tip int. Anumite caractere negrafice, apostroful si backslashul pot fi reprezentate potrivit tabelei urmatoare de secvente escape: new_line NL (LF) \n horizontal tab HT \t vertical tab VT \v backspace BS \b carriage return CR \r form feed FF \f backslash \ \\ simple quote ' \' bit pattern 0ddd \ddd bit pattern 0xddd \xddd Secventa escape \ddd consta dintr-un backslash urmat de una, doua sau trei cifre octale care specifica valoarea caracterului dorit. Un caz special al acestei constructii este \0 (care nu este urmat de o cifra), care indica caracterul NULL. Secventa escape \xddd consta din backslash urmat de una, doua sau trei cifre hexazecimale care specifica valoarea caracterului dorit. Daca caracterul care urmeaza dupa backslash nu este unul din cei specificati mai sus, atunci caracterul backslash se ignora. 2.4.4 Constante flotanteO constanta flotanta consta dintr-o parte intreaga, un punct zecimal, o parte fractionara, un e sau un E si un exponent intreg cu un semn optional. Partile intregi si fractionare constau fiecare dintr-o secventa de cifre. Partea intreaga sau partea fractionara (dar nu simultan) pot lipsi; punctul zecimal sau e (E) si exponentul (dar nu simultan) pot lipsi. O constanta flotanta are tipul double. 2.4.5 Constante enumerativeNumele declarate ca enumeratori (vezi &8.10) sint constante de tip int. 2.4.6 Constante declarateUn obiect (&5) de orice tip poate fi specificat sa aiba o valoare constanta in domeniul numelui lui (&4.1). Pentru pointeri declaratorul &const (&8.3) se utilizeaza pentru a atinge acest fapt; pentru obiecte nepointer se utilizeaza specificatorul const (&8.2). 2.5 SiruriUn sir este o succesiune de caractere delimitate prin ghilimele (" ... "). Un sir are tipul "tablou de caractere" si clasa de memorie static (vezi &4 mai jos) si se initializeaza cu caracterele date. Toate sirurile, chiar daca sint scrise identic sint distincte. Compilatorul plaseaza un octet null (\0) la sfirsitul fiecarui sir asa ca programele care parcurg sirul pot gasi sfirsitul lui. Intr-un sir, ghilimelele " trebuie precedate de \; in plus secventele escape asa cum s-au descris pentru constantele caracter, se pot folosi intr-un sir. In sfirsit, new_line poate apare numai imediat dupa \. 2.6 Caracteristici hardware Tabela de mai jos rezuma anumite proprietati care variaza de la masina la masina. | DEC | Naturale | IBM 370 | AT&T3B | In notatia sintactica utilizata in acest manual categoriile sintactice se indica
prin italice, iar cuvintele literale si caracterele din constante in forma reala.
Variantele se listeaza pe linii separate. Un simbol terminal optional sau neoptional
se indica prin indicele "opt" asa ca: 4 Nume si Tipuri Un nume denota un obiect, o functie, un tip, o valoare sau o eticheta. Un nume se introduce intr-un program printr-o declaratie (&8). Un nume poate fi utilizat numai intr-o regiune a textului programului numit domeniul lui. Un obiect este o regiune de memorie care determina existenta lui. Intelesul valorilor gasite intr-un obiect se determina prin tipul numelui utilizat pentru a-l accesa. 4.1 Domenii Exista trei feluri de domenii: local, fisier si clasa. Local: In general, un
nume declarat intr-un bloc(&9.2) este local la acel bloc si poate fi folosit
in el numai dupa punctul de declaratie si in blocurile incluse in el. Cu toate acestea, etichetele (&9.12)
pot fi utilizate oriunde in functia in care ele sint declarate. Numele argumentelor
formale pentru o functie se trateaza ca si cind ar fi fost declarate in blocul
cel mai extern al acelei functii. Fisier: Un nume declarat in afara oricarui
bloc (&9.2) sau clasa (&8.5) poate fi utilizat in fisierul in care a
fost declarat dupa punctul in care a fost declarat. Clasa: Numele unui membru
al clasei este local la clasa lui si poate fi utilizat numai intr-o functie membru al acelei clase (&8.5.2),
dupa un operator aplicat la un obiect din clasa lui (&7.1) sau dupa operatorul
-> 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. 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). 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. 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. 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. 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. 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. 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 semnOri 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. 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 referinteConversia 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 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 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. Expresiile cu operatori unari se grupeaza de la dreapta la stinga. unary_expression: unary_operator expression expression++ expression- sizeof expression sizeof(type_name) unary_operator: unul dintre * & + - ! I ++ -- 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 "... ". 7.2.1 Incrementare si Decrementare 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. 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. 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 inta10i 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); In forma: delete aexpressioni 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. 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. 7.5 Operatori de deplasare Operatorii de deplasare << si >> 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. Valoarea lui E1 << E2 este E1 (interpretat ca o configuratie de biti) deplasat la stinga cu E2 biti; bitii liberi se completeaza cu zero. Deplasarea la dreapta este garantata a fi o deplasare logica (se completeaza cu 0) daca E1 este fara semn; altfel ea este aritmetica (se copiaza bitul de semn). 7.6 Operatori relationali Operatorii de relatie se grupeaza de la stinga la dreapta, dar acest fapt nu este foarte util; a < b < c nu inseamna ceea ce s-ar parea. relational_expression: expression < expression expression > expression expression <= expression expression >= expression Operatorii < (mai mic decit), > (mai mare decit), <= (mai mic sau
egal cu) si >= (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. equality_expression: expression == expression expression != expression Operatorii == (egal) si != (diferit) sint analogi cu operatorii de relatie exceptind precedenta mai mica a lor. (Astfel a<b == c<d este 1 daca a<b si c<d au aceeasi valoare de adevar). Un pointer poate fi comparat cu zero. 7.8 Operatorul SI pe biti and_expression: expression & expression 7.9 Operatorul SAU EXCLUSIV pe biti exclusive_or_expression: expression ^ expression 7.10 Operatorul SAU INCLUSIV pe biti inclusive_or_expression: expression | expression 7.11 Operatorul logic SI logical_and_expression: expression && expression 7.12 Operatorul logic SAU logical_or_expression: expression || expression 7.13 Operator conditional conditional_expression: expression ? expression : expression 7.14 Operatori de asignare Exista mai multi operatori de asignare si toti se grupeaza de la dreapta la stinga. Toti cer o lvaloare ca operand sting si tipul unei expresii de asignare este acela al operandului sting; aceasta lvaloare trebuie sa nu se refere la o constanta (nume de tablou, nume de functie sau const). Valoarea este valoarea memorata in operandul sting dupa ce asignarea a avut loc. assigment_expresion; expression assigment_operator expression assigment_operator: unul dintre = += -= *= /= %= >>= <<= &= ^= |= In atribuire simpla cu =, valoarea expresiei o inlocuieste pe cea a obiectului
referit prin operandul din partea stinga. Daca ambii operanzi au tipul aritmetic,
operandul drept se converteste spre tipul operandului sting preparat pentru
asignare. Daca argumentul sting are tipul pointer operandul drept trebuie sa
fie de acelasi tip sau de un tip care poate fi convertit spre el (vezi &6.7).
Ambii operanzi pot fi obiecte de aceeasi clasa. Obiectele de anumite clase nu
pot fi atribuite (vezi &8.5.3). 7.15 Operatorul virgula comma_expression: expression, expression 7.16 Operatori de supraincarcare Majoritatea operatorilor pot fi supraincarcati, adica declarati sa accepte
obiectele unei clase ca operanzi (vezi &8.5.11). Nu este posibil sa se schimbe
precedenta operatorilor si nici sa se schimbe sensul operatorilor aplicati la
obiecte non_clasa. In telesul predefinit al operatorilor = si & (unar) aplicati
la obiectele unei clase se poate schimba. Un operator unar, daca este prefix sau postfix, poate fi definit printr-o functie membru (vezi &8.5.4) fara apartenente sau o functie prieten (vezi &8.5.10) care are un argument dar nu ambele. Astfel, pentru operatorul unar @, atit x@, cit si @x pot fi interpretati fie ca x.operator@(), fie ca operator@(x). Cind operatorii ++ si -- sint supraincarcati, nu este posibil sa se faca distinctie intre aplicatia prefix si cea postfix. 7.16.2 Operatori binari Un operator binar poate fi definit sau printr-o functie membru care are un argument sau printr-o functie prieten care are doi parametri, dar nu ambele. Astfel, pentru un operator binar @, x@y poate fi interpretat sau x.operator@(y) sau operator@(x, y). 7.16.3 Operatori speciali Apelul de functie primary_expression (expression_list_opt) si indexarea primary_expressionaexpressioni se considera operatori binari. Numele functiilor care se definesc sint operator()
si operatorai. Astfel, un apel x(arg) este interpretat ca x.operator()(arg)
pentru un obiect de clasa x. O expresie de forma xayi se interpreteaza ca x.operatorai(y).
Declaratiile se utilizeaza pentru a specifica interpretarea data fiecarui identificator;
ele nu neaparat rezerva memorie asociata cu identificatorul. Declaratiile au
forma: declaration: decl_specifiers_opt declarator_list_opt; name_declaration asm_declaration 8.1 Specificatori de clasa de memorie Specificatorii de clasa de memorie sint: sc_specifier: auto static extern register Declaratiile care utilizeaza specificatorii auto, static si register servesc
de asemenea ca definitii prin faptul ca ele implica rezervarea unei cantitati
de memorie de o marime potrivita. Daca o declaratie extern nu este o definitie
(&4.2) trebuie sa existe undeva o definitie pentru identificatorii dati.
O declaratie register este cel mai bine sa fie gindita ca o declaratie auto
impreuna cu sugestia ca, compilatorul stie faptul ca variabilele respective
vor fi utilizate din greu. Aceasta informatie poate fi ignorata. Specificatorul overload permite ca un nume sa fie utilizat pentru a nota diferite
functii: vezi &8.9. Specificatorul inline este numai o informatie pentru
compi- lator; el nu afecteaza intelesul programului si poate fi ignorat. Se
indica faptul ca substitutia inline a corpului functiei este de preferat implementarii
obisnuite al apelului de functie. O functie (vezi &8.5.2 si &8.5.10)
definita intr-o declaratie a unei clase este implicit o functie inline. Specificatorul
virtual poate fi utilizat numai in decla- ratiile membrilor unei clase; vezi
&8.5.4. Specificatorul typedef se foloseste pentru a introduce un nume pentru un tip; vezi &8.8. 8.2 Specificatori de tip Specificatorii de tip sint: type_specifier: simple_type_name class_specifier enum_specifier elaborated_type_specifier const Cuvintul const poate fi adaugat la orice specificator de tip legal. Altfel,
intr-o declaratie se poate da cel mult un specifi- cator de tip. Un obiect de
tip const nu este o lvaloare. Daca specificatorul de tip lipseste dintr-o declaratie,
el se ia int. simple_type_name: typedef_name char short int long unsigned float double void Un specificator de tip elaborat poate fi utilizat pentru a face referire la
numele unei clase sau la numele unei enumerari unde numele poate fi ascuns printr-un
nume local. De exemplu: class x A /*...*/ S; void f(int) Daca numele de clasa sau de enumerare nu a fost in prealabil declarat, specificatorul de tip elaborat actioneaza ca o decla- ratie de nume; vezi &8.8. 8.3 Declaratorideclarator_list: init_declarator init_declarator, declarator_list init_declarator: declarator initializer_opt Fiecare declarator se considera a fi o asertiune care, cind apare intr-o expresie o constructie asemanatoare cu declaratorul, produce un obiect de tipul si clasa de memorie indicata. Fiecare declarator contine exact un dname; el specifica identificatorul care este declarat. Exceptind declaratiile unor functii speciale (vezi &8.5.2), un dname va fi un identificator simplu. Daca apare ca un declarator un identificator "neimpodobit", atunci el are tipul indicat de specificatorul care se afla in capul declaratiei. Un declarator in paranteze este identic cu un declarator "neimpodobit", dar legaturile declaratorilor complecsi pot fi alterate prin paranteze; vezi exemplele de mai jos. Sa ne imaginam o declaratie: T D1 unde T este un specificator de tip (int, etc.) si D1 este un declarator. Sa presupunem ca aceasta declaratie face ca identifi- catorul sa aiba tipul " ... T", unde "..." este vid daca D1 este chiar un identificator (cum ar fi tipul lui x in "int x" exact int). Daca D1 are forma: *D tipul identificatorului pe care il contine este "... pointer la T". Daca D1 are forma: *const D tipul identificatorului pe care il contine este "... pointer constant la T" adica, acelasi tip ca si *D, dar identificatorul continut nu este o lvaloare. Daca D1 are forma: &D sau &const D tipul identificatorului pe care il contine este "... referinta la T". Intrucit o referinta nu poate fi prin definitie o lvaloare, utilizarea lui lvalue este redondanta. Nu este posibil sa avem o referinta spre void (void&). Daca D1 are forma: D(argument_declaration_list) atunci identificatorul pe care il contine are tipul "... functie care are argumente de tip argument_declaration_list si returneaza T". argument_declaration_list: arg_declaration_list_opt ... _opt argument_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 Daca argument_declaration_list se termina cu trei puncte, atunci numarul argumentelor se stie numai ca este egal sau mai mare decit numarul de argumente specificat; daca este vid, fun- ctia nu are argumente.Toate declaratiile pentru o functie trebuie sa corespunda exact atit in privinta tipului valorii returnate, cit si in numarul si tipul argumentelor. Argumentul argument_declaration_list se utilizeaza pentru a verifica si converti argumentele actuale in apeluri si pentru a verifica asignarile pointerilor spre functii. Daca este specificata o expresie intr-o declaratie de argument, atunci aceasta expresie se utilizeaza ca argument implicit. Argumentele implicite vor fi utilizate in apeluri acolo unde ultimele argumente sint omise. Un argument implicit nu poate fi redefinit printr-o declaratie ulterioara. Cu toate acestea, o declaratie poate adauga argumente implicite care nu s-au dat in declaratiile precedente. Un identificator poate fi furnizat optional ca un argument nume; daca este prezent intr-o declaratie de functie, el nu poate fi utilizat intrucit el iese imediat afara din domeniul sau; daca este prezent intr-o definitie de functie (&10) el numeste un argument formal. Daca D1 are forma: Daconstant_expressioni sau Dai atunci identificatorul pe care il contine are tipul "... tablou de T". In primul caz expresia constanta este o expresie a carei valoare se determina la compilare si a carei tip este int (expresiile constante se definesc in &12). Cind diferite specificari de tablouri sint adiacente, se creaza un tablou multidimensional; expresiile constante care specifica limitele tablourilor se pot omite numai pentru primul membru al secventei. Aceasta omisiune este utila cind tabloul este extern si definitia reala, care aloca memorie, se da in alta parte. Prima expresie constanta poate fi omisa de asemenea cind declaratorul este urmat de initializare. In acest caz dimensiunea se calculeaza din numarul elementelor initiale furnizate. Un tablou poate fi construit din unul din tipurile de baza, dintr-un pointer, dintr-o structura sau reuniune sau dintr-un alt tablou (pentru a genera un tablou multi_dimensional). Nu toate posibilitatile admise prin sintaxa de mai sus sint permise. Restrictiile sint: functiile nu pot returna tablouri sau functii, desi ele pot returna pointeri spre astfel de lucruri; nu exista tablouri de functii, desi pot fi tablouri de pointeri spre functii. 8.4.1 Exemple Declaratia: int i, *pi, f(), *fpi(), (*pif)(); declara un intreg i, un pointer pi spre un intreg, o functie f care returneaza
un intreg, o functie fpi care returneaza un pointer spre un intreg si un pointer
pif spre o functie care returneaza un intreg. Este util mai ales sa se compare
ultimii doi. Sensul lui *fpi() este *(fpi()) si aceeasi constructie intr-o expresie
cere apelul functiei fpi si apoi utilizind indirectarea prin pointer rezulta
producerea unui intreg. La declaratorul (*pif)(), parantezele sint necesare
pentru a indica faptul ca indirectarea printr-un pointer la o functie produce
o functie, care apoi este apelata. Functiile f si fpi se declara fara argumente,
iar pif pointeaza spre o functie care nu are argumente. Exemple de operatii legale: b=a; Declaratia: fseek(FILE*, long, int); declara o functie care poate fi apelata cu zero, unu sau doi parametri de tip int. Ea poate fi apelata in oricare din modurile: point(1, 2); point(1); point(); Declaratia: printf(char* ...); declara o functie care poate fi apelata cu un numar variabil de argumente si tipuri. De exemplu: printf("hello world"); printf("a=%d b=%d", a, b); Cu toate acestea, trebuie ca totdeauna char* sa fie primul sau parametru. Declaratia: float faa17i, *afpa17i; declara un tablou de numere flotante si un tablou de pointeri spre numere flotante. Ori de cite ori intr-o expresie apare un identificator de tip tablou, el este
convertit intr-un pointer spre primul element al tabloului. Din cauza acestei
conversii, tablourile nu sint lvalori. Exceptind cazul in care operatorul de
indexare ai a fost declarat pentru o clasa (&7.16.3), el se interpreteaza
in asa fel incit E1aE2i este identic cu *((E1)+(E2)). Din cauza regulilor de
conversie care se aplica la + daca E1 este un tablou si E2 un intreg, E1aE2i
se refera la al E2-lea membru al lui E1. De aceea, in ciuda aparentei asimetrice,
indexarea este o operatie comutativa. O regula consistenta se aplica in cazul
tablourilor multidi- mensionale. Daca E este un tablou ndimensional de ordinul
ixjx...xk, atunci E care apare intr-o expresie este convertit spre un pointer
spre un tablou (n-1)dimensional de ordinul jx...xk. Daca operatorul * se aplica
explicit sau implicit ca rezultat al indexarii, rezultatul este tabloul (n-1)dimensional,
care este convertit imediat intr-un pointer. 8.5 Declaratii de clasa O clasa este un tip. Numele ei devine un typedef_name (vezi &8.8) care poate fi utilizat chiar in specificarea clasei. Obiectele unei clase constau dintr-o secventa de membri. class_specifier: class_headAmember_list_optS class_headAmember_list_opt public: member_list_optS class_head: aqqr identifier_opt aqqr identifier: public_opt typedef_name aqqr: class struct union Obiectele de clasa pot fi asignate, pasate ca argumente la functii si returnate
de functii (exceptind obiectele unor clase derivate; vezi &8.5.3). Un membru care este data a unei clase poate fi static; functiile care sint membri nu pot fi. Membri pot sa nu fie auto, register sau extern. Exista numai o singura copie a unui membru static comuna pentru toate obiectele unei clase dintr-un program. Un membru static mem al unei clase cl poate fi referit prin cl::mem, adica fara a se face referire la un obiect. El exista chiar daca nu s-a creat nici un obiect al clasei cl. Nu se poate specifica nici un initializator pentru un membru static si nu poate fi o clasa cu un constructor. 8.5.2 Functii membru O functie declarata ca membru (fara specificatorul friend (&8.5.10)) se
numeste functie membru si se apeleaza utilizind sintaxa membrului unei clase
(&7.1). De exemplu: struct tnodA char tworda20i; int count; tnode* left; tnode* right; void set(char*, tnode*
l, tnode* r); Definitia unei functii membru se considera ca este in dome- niul clasei sale.
Aceasta inseamna ca poate utiliza direct numele clasei sale. Daca definitia
unei functii membru este lexic in afara declaratiei de clasa, numele functiei
membru trebuie sa fie calificat prin numele clasei folosind operatorul ::. Definitiile
functiilor se discuta in &10. De exemplu: void tnode::set(char* w, tnode* l, tnode* r) Notatia tnode::set() specifica faptul ca set( |
||||||
|
||||||
|
||||||
Copyright© 2005 - 2024 | Trimite document | Harta site | Adauga in favorite |
|