Sunteți pe pagina 1din 31

INTRODUCERE

PROGRAMAREA ORIENTATĂ PE OBIECTE

Programarea orientată pe obiecte (OOP) este o nouă cale de abordare a programării.


Modalităţile de programare s-au schimbat imens de la inventarea calculatorului, în primul rând
pentru a se acomoda creşterii complexităţii programelor. De exemplu, la început, când au fost
inventate calculatoarele, programarea se făcea introducându-se instrucţiuni în maşina de cod binar
cu ajutorul panoului frontal al calculatorului. Acest lucru a fost convenabil atât timp cât
programele aveau doar câteva sute de instrucţiuni. O dată cu mărirea programelor, au fost
inventate limbajele de asamblare, astfel încât programatorii se puteau descurca cu programe mai
mari, cu complexitate crescută, folosind reprezentarea simbolică a instrucţiunilor pentru maşină.
Deoarece programele continuau să crească, au fost introduse limbajele de nivel înalt care oferă
programatorului mai multe uneltef cu care să facă faţă complexităţii.
Anii ’60 au dat naştere programării structurate. Aceasta este metoda încurajată de limbaje
precum sunt C şi Pascal. Utilizarea limbajelor structurate face posibilă scrierea destul de uşoară a
unor programe relativ complexe. Totuşi, chiar folosind metodele programării structurate, un
proiect nu mai poate fi controlat odată ce atinge anumite mărimi. Programarea orientată pe obiecte
a preluat cele mai bune idei ale programării structurate şi le combină cu mai multe concepte noi,
mai puternice, care încurajează abordarea programării într-un mod nou. În general, când se
programează în modul orientat pe obiecte, o problemă este împărţită în subgrupe de secţiuni
înrudite, care ţin seama atât de codul cât şi de datele corespunzătoare din fiecare grup. Apoi, se
organizează aceste subgrupe într-o structură ierarhică. În sfârşit, subgrupele se transformă în
unităţi de sine stătătoare numite obiecte.
Modalitatile (tehnici, paradigme) de programare au evoluat de-a lungul anilor, reflectând
trecerea de la programe de dimensiuni reduse la programe si aplicatii de dimensiuni foarte mari,
pentru coordonarea carora sunt necesare tehnici evaluate.
Software-ul de dimensiuni mari, care nu poate fi realizat de o singura persoana, intra în
categoria sistemelor complexe, alaturi de alte sisteme complexe din cele mai variate domenii, cum
sunt organizarea materiei sau organizarile sociale.
Situatiile reale si experiente ale psihologilor au relevat limitele capacitatii umane în
perceptia sistemelor complexe, adica imposibilitatea unei persoane de percepe si controla un
numar mare de entitati de informatie simultan. De aceea, descompunerea si organizarea sistemelor
complexe, în scopul de putea fi percepute, proiectate sau conduse este esentiala. Ordinea în
sistemele complexe este introdusa în general printr-o organizare ierarhica, pe mai multe tipuri si
nivele de ierarhie.
În reprezentarea ierarhica a sistemelor complexe se evidentiaza doua tipuri de ierarhii:
- ierarhia structurala sau de compozitie si

- ierarhia de tip.

Ierarhia structurala este o ierarhie în care se poate afirma despre un obiect ca este o parte
a altui obiect, mai complex. Exemple de astfel de descompuneri se pot da oricâte, din orice
domeniu.
De exemplu, un calculator poate fi studiat prin descompunerea lui în subansamble
componente: placa de baza, placa video, monitor, etc; la rândul ei, placa de baza este compusa
din placheta de circuit imprimat, procesor, memorie, etc. Aceasta este o ierarhie de tipul “este o
parte din…”.
Pe de alta parte, fiecare obiect poate fi încadrat într-o categorie (clasa, tip) mai larga,
care contine mai multe obiecte care au proprietati comune. De exemplu, procesorul este de o
componenta electronica; monitorul este un dispozitiv de afisare, etc. Aceasta ierarhie se refera la
apartenenta obiectelor la o anumita clasa (sau tip - “este de tipul…”).
Este esential sa privim sistemele complexe din ambele perspective, studiindu-le atât din
perspectiva ierarhiei structurale, deci a obiectelor care le compun, cât si a ierarhiei de tip, deci a
claselor carora le apartin. La rândul lor, clasele din care fac parte obiectele pot fi organizate sau
studiate ca elemente componente ale unei ierarhii, prin care o clasa este considerata ca primitiva
(parinte) a unei alte clase.
Cele doua tipuri de ierarhii, ierarhia de clase si ierarhia de obiecte nu sunt independente,
si, împreuna, pot sa reprezinte un sistem complex.
La fel ca oricare sistem complex, software-ul poate fi controlat prin descompunerea lui.
Rolul descompunerii unui sistem în general (si al programelor în special) este de a permite
întelegerea si manevrarea acestuia: sistemul este descompus în parti din ce în ce mai mici,
fiecare dintre ele putând fi rafinata si dezvoltata independent.
Principiul “divide-et-impera”, care se aplica în multe situatii, este util si în programare.

Se pot identifica doua tipuri de descompunere a programelor:

- descompunerea algoritmica si

- descompunerea orientata pe obiecte.

Descompunerea algoritmica permite abordarea structurata a programarii. Programul este


împartit în module, în functie de actiunile pe care trebuie sa le efectueze, fiecare modul se
împarte în elemente functionale (blocuri, proceduri, functii), într-o structurare de sus în jos (top-
down), care urmareste diagrma de trecere a datelor în cursul executiei.
Descompunerea orientata pe obiecte este o alternativa de descompunere prin care
programul se descompune dupa obiectele care pot fi identificate, fiecare obiect având asociate o
multime de operatii care sunt apelate în cursul desfasurarii programului.
O problema nu poate fi abordata simultan prin ambele metode; se alege fie una, fie cealalta
metoda.
Care dintre ele este cea mai buna?
Nu exista un raspuns absolut si universal valabil, dar experienta a dovedit ca pentru
sisteme de dimensiuni mari, descompunerea orientata pe obiecte este mai eficienta, mai sigura si
mai flexibila.
Toate limbajele de programare orientate pe obiecte au trei caracteristici comune:
încapsularea, polimorfism şi moştenire.

CONCEPTELE DE BAZĂ ALE POO

Abstractizarea datelor

Atributele specificate în definiţia unei clase descriu valoric proprietăţile obiectelor


din clasă. Cele mai multe limbaje orientate pe obiecte fac următoarea distincţie între atribute:
- atribute ale clasei (au aceeaşi valoare pentru toate instanţele clasei);
- atribute ale instanţei (variază de la o instanţă la alta, fiecare instanţă având
propria copie a atributului).
În limbajul C++ atributele se numesc date membre. Toate datele membre sunt
atribute instanţă. Atributele de clasă se pot obţine în cazul datelor membre statice (aceeaşi adresă
de memorare pentru orice instanţă a clasei).
Metode (funcţii membre). La definirea unei clase se definesc şi metodele acesteia
(numite şi funcţii membre). Fiecare obiect are acces la un set de funcţii care descriu operaţiile care
pot fi executate asupra lui. Metodele pot fi folosite de instanţele clasei respective, dar şi de
instanţele altor clase (prin mecanismul moştenirii).
Clasa conţine atât structurile de date necesare descrierii unui obiect, cât şi metodele
care pot fi aplicate obiectului. Astfel, gradul de abstractizare este, mult mai ridicat, iar
programele devin mult mai uşor de înţeles.
La crearea unui obiect, alocarea memoriei se poate fi face static sau dinamic cu
ajutorul unor funcţii membre speciale, numite constructori. Eliberarea memoriei se realizează
cu ajutorul unor funcţii membre speciale, numite destructori, în momentul încheierii
existenţei obiectului respective.

Încapsularea
Încapsularea este un mecanism care leagă împreună cod şi date şi le păstrează pe ambele în
siguranţă faţă de intervenţii din afară şi de utilizări greşite. Mai mult, încapsularea este cea care
permite crearea unui obiect. Spus simplu, un obiect este o entitate logică ce încapsulează atât date
cât şi cod care manevrează aceste date. Într-un obiect o parte din cod şi/sau date pot fi particulare
acelui obiect şi inaccesibile în afara sa. În acest fel, un obiect dispune de un nivel semnificativ de
protecţie care împiedică modificarea accidentală sau utilizarea incorectă a părţilor
proprii obiectului de către secţiuni ale programului cu care nu are legătură.
În cele din urmă, un obiect este o variabilă de un tip definit de utilizator. Când se defineşte
un obiect, implicit se crează un nou tip de date.

Polimorfism

Limbajele de programare orientate pe obiecte admit polimorfismul, care este


caracterizat prin fraza „o interfaţă, metode multiple”. Polimorfismul este caracteristica ce permite
unei interfeţe să fie folosită cu o clasă generală de acţiuni. Acţiunea specifică selectată
este determinată de natura precisă a situaţiei.
De exemplu, se poate implementa un program care defineşte trei tipuri de memorie stivă.
Una este folosită pentru valori întregi, una pentru valori tip caracter şi una pentru valori în
virgulă mobilă. Datorită polimorfismului se pot crea trei perechi de funcţii numite push() şi pop()
– câte una pentru fiecare tip de date.
Conceptul general (interfaţa) este cel de a introduce şi de a scoate date dintr-o memorie
stivă. Funcţiile definesc calea specifică (metoda) care se foloseşte pentru fiecare tip de date. Când
se introduc date în memoria stivă, tipul de date va fi cel care va determina versiunea particulară
a lui push() care va fi apelată.
Primele limbaje de programare orientate pe obiecte au fost interpretoarele, astfel
încât polimorfismul a fost admis, desigur, în timpul rulării. Dar C++ este un limbaj de
compilare. Astfel, în C++, polimorfismul este admis atât în timpul rulării cât şi în timpul
compilării.
Moştenirea

Moştenirea este procesul prin care un obiect poate să preia prototipul altui obiect. Acest lucru
este important deoarece se admite conceptul de clasificare. Majoritatea cunoştinţelor despre lumea
înconjurătoare sunt accesibile deoarece sunt clasificate ierarhic. De exemplu, un câine ciobănesc
face parte din clasa câine, care la rândul său face parte din clasa mamifere care se află în marea
clasă animale. Fără utilizarea claselor, fiecare obiect ar trebui definit explicitându-se toate
caracteristicile sale. Însă, prin folosirea clasificărilor, un obiect are nevoie doar de definirea acelor
calităţi care îl fac unic în clasa sa. Mecanismul moştenirii face posibil ca un obiect să fie un
exemplar specific al unui caz mai general.
Fig.1. Clase

Limbajul C++ combină avantajele oferite de limbajul C (eficienţă, flexibilitate şi


popularitate) cu avantajele oferite de tehnica POO (Programării Orientate pe Obiecte). Deşi adoptă
principiile POO, C++ nu impune aplicarea lor strictă (se pot scrie programe fără elemente POO).
Conceptul fundamental în C++ este clasa.
Clasele reprezintă o extensie a structurilor din C. Cu acestea, programatorul îşi poate crea tipuri
de date complexe, ce cuprind atât datele cât şi operaţiile ce acţionează asupra acestora.
Variabilele create din clase se numesc obiecte, iar programarea utilizând aceste concepte,
programare orientată pe obiecte (POO).
Cum este şi firesc, C++ posedă toate capacităţile limbajului C. În plus utilizând clasele, se
pot dezvolta programe de un înalt grad al complexităţii.
CAPITOLUL 1

ELEMENTELE DE BAZĂ AL LIMBAJULUI C++

Alfabetul și vocabularul limbajului de programare

Setul de caractere

Orice limbaj de programare are la bază un anumit alfabet. În majoritatea cazurilor setul de caractere
este format din:

• literele alfabetului englez (de la A la Z, de obicei și majusculele, și literele mici, în total 52


de caractere);
• cifrele arabe (de la 0 la 9, în total 10 caractere);
• unele caractere speciale (. , ; = < > # $ % + – * / ” ‘ ( ) etc.) , a căror semnificație poate sa
difere de la un limbaj la altul.

Secvențe Escape / Caractere speciale în C++

\b Backspace, \t Tab orizontal, \v Tab vertical, \n Linie nouă, \f Pagina nouă – formfeed
\r Început de rând, \” Ghilimele, \’ Apostrof, \\ Backslash, \? Semnul întrebării, \a Alarmă

Standarde de codificare a seturilor de caractere

• EBCDIC (Extended Binary Coded Decimal Interchenge Code), un cod pe 8 biți, introdus
de IBM;
• ASCII (American Standard Code for Information Interchange), introdus de ANSI
(American National Standard Institute), este un cod pe 7 biți și permite codificarea a 128
de caractere (95 de caractere afișabile și 33 de caractere neafișabile, numite caractere de
control). Ulterior, setul ASCII a fost extins la o codificare pe 8 biți, fiind disponibile astfel
256 de caractere.

Primele 128 sunt din setul ASCII standard, iar următoarele 128 sunt coduri de caractere afișabile
pentru caracterele unor alfabete naționale europene (francez, spaniol, român etc.), o parte din
literele alfabetului grecesc, unele simboluri matematice, caractere speciale pentru desenat tabele
etc.

Ordonarea caracterelor alfabetului se face pe baza codurilor numerice corespunzătoare caracterelor


respective.
Cuvinte cheie / cuvinte rezervate

Pe baza caracterelor ce alcătuiesc alfabetul limbajului se alcătuiesc cuvintele care formează


vocabularul sau lexicul limbajului și cu ajutorul cărora se construiesc expresiile și instrucțiunile
limbajului. Există doua categorii de cuvinte și anume:

1. cuvinte cheie – acestea au un înțeles explicit într-un context precizat (de ex., în unele
limbaje de programare cuvintele ce desemnează instrucțiuni pot fi folosite și ca nume de
variabile, neexistând restricții; asemenea situații nu sunt însă indicate deoarece pot ascunde
erori în logica programului și îl fac mai greu de înțeles);
2. cuvinte rezervate – acestea nu pot fi folosite decât în scopul pentru care au fost definite
(de ex., în limbajul C++). Avantajele utilizării acestei categorii de cuvinte sunt
următoarele:

• programul devine mai ușor de înțeles;


• se mărește viteza de compilare (analiza lexicală, sintactică și semantică este mai simplă la
căutarea în tabele de simboluri);
• erorile sunt mai ușor de depistat.
• pe de alta parte, în cadrul unui limbaj de programare se vor utiliza cuvinte ale limbajului
(rezervate) si cuvinte definite de utilizator pentru a referi diverse elemente (variabile,
fisiere, nume de proceduri, nume de functii, etc.).

Sintaxa unui limbaj de programare

Și în cazul limbajelor de programare succesiunile de cuvinte construite după anumite reguli,


formează propoziții, numite instrucțiuni. Sintaxa unui limbaj de programare reprezinta ansamblul
de reguli prin care se determină dacă o anumită instrucțiune este alcătuită corect sau nu. Sintaxa
unui limbaj de programare poate fi descrisă în diverse moduri, unul dintre acestea fiind notația
BNF (Backus-Naur Form).

Notatia BNF

Notatia BNF (Backus-Naur Form) a fost utilizata prima data la descrierea sintaxei limbajului
ALGOL (în cadrul raportului ALGOL60 aparut în 1963) si este numita dupa doi dintre autorii
acestui raport. În cadrul BNF sunt folosite metasimboluri, simboluri terminale si simboluri
neterminale.

Metasimboluri sunt simbolurile <, >, ½ si ::= si ele fac parte din mecanismul de descriere a
limbajului. Simbolul ½ semnifica o alternativa, simbolul ::= inseamna „se definește astfel”.
Simbolurile terminale sunt cuvinte care apar acolo unde se specifica în productii (de ex., for, while,
do, +, ; etc.).

Simbolurile neterminale sunt încadrate în < si > si sunt definite prin productii ale limbajului (de
ex., <variabila>, <identificator>, <instructiune if> etc.).

Exemplu: în limbajul C++ sintaxa unui identificator se descrie în BNF astfel:

<identificator>::=<litera>|<identificator><cifra>|<identificator><literă>|

unde

<litera>::=a|b|...|z|A|B|...|Z|_

<cifra>::=0|1|2|...|9
Simbolul _ este considerat <litera> în acest context.

Conform acestei reguli, identificatorul are 3 definiții alternative: un identificator este fie o <litera>,
fie un <identificator> urmat de o <cifra> sau o <litera> (definitie recursiva). Semnificatia acestei
definitii este urmatoarea: un identificator poate sa contina o singura litera, sau o litera urmata de
oricâte litere si/sau cifre. Conform acestei definitii, sunt corecte sintactic urmatorii identificatori:
a, t1, sec12a1.

Descrierea sintaxei instructiunii conditionale if-else din limbajul C++ în notatie BNF este:

<instructiune if>::= if (<conditie>)


<instructiune1>
else
<instructiune2>

Semantica unui limbaj de programare

Semantica unei instrucțiuni reprezintă înțelesul pe care îl are acea instrucțiune, adică ce va executa
calculatorul când o întâlnește.

Astfel, pentru instrucțiunea if-else de mai sus, se evalua condiția <conditie>, iar dacă aceasta este
adevărată (în momentul evaluării), atunci se va executa o singură dată
instrucțiunea <instructiune1>, respectiv, dacă este falsă, se va executa o singură dată
instrucțiunea <instructiune2>.

Primul program în C++, folosind Code::Blocks


Exemplu de program simplu în C++

/*
* primul program in C++
*/
#include <iostream>
int main ()
{
std::cout << "Primul test 1, 2, 3. ";
std::cout << "functioneaza.. \n";
return 0;
}

SAU

/*
* primul program in C++
*/
#include <iostream>
using namespace std;
int main ()
{
cout << "Primul test 1, 2, 3. ";
cout << "functioneaza.. \n";
char c;
cout << "Pentru a iesi, apasati orice tasta!!\n";
cin >> c;
return 0;
}
Rezultatul va fi:
Primul test 1, 2, 3. functioneaza..
} //aici se încheie programul

Directive preprocesare

Directiva preprocesare #include

Sintaxa:

#include <biblioteci> (Input/output, math, strings, …)


Exemple:

#include <iostream>
#include <math.h>
#include <stdlib.h>
#include “biblioteca_mea.h”
#include “t1.h”

Directiva preprocesare #define

Sintaxa:

#define simbol

#define simbol valoare

Exemple:

#define infinit 1000


#define pi 3.1415926
#define then
#define si &&
#define daca if
#define altfel else
#define max(x,y) x > y ? x : y #define min(x,y) x < y ? x : y
#include <stdio.h>
void main()
{
float a,b,c;
printf("Dati lungimile laturilor:\n");
scanf("%f %f %f",&a,&b,&c);
daca ((a>=0) si (b>=0) si (c>=0) si (a<b+c) si (b<a+c) si (c<a+b))
printf("%4.2f, %4.2f si %4.2f formeaza triunghi.", a,b,c);
altfel
printf("Nu formeaza triunghi.");
}
Date

Variabile și constante. Expresii

În cadrul programului, datele pot fi declarate ca fiind constante sau variabile. O constantă
este o dată a cărei valoare nu se poate modifica pe parcursul execuţiei programului, deci rămâne
constantă.
O variabilă este o dată a cărei valoare se poate modifica pe parcursul execuţiei programului,
deci ea poate varia, dar acest lucru nu este obligatoriu. Astfel, se poate declara o dată ca fiind
variabilă în cadrul unui program, apoi ea să primească o anumită valoare, iar această valoare să
rămână asociată respectivei variabile până la terminarea programului.
Evident, atunci când se va declara o dată constantă, se va preciza şi valoarea ei, iar când se va
declara o dată variabilă, se subînţelege că ulterior, pentru a putea fi folosită, această variabilă va
primi o anumită valoare.
Majoritatea limbajelor de programare asignează o valoare iniţială variabilelor, o dată cu
declararea lor. Astfel, şirurile de caractere sunt iniţializate la şirul vid, iar numerele sunt
considerate cu valoarea zero.
Fireşte, atât constantele cât şi variabilele au o anumită structură, mai simplă sau mai complicată,
şi o anumită natură, dată de mulţimea valorilor posibile pentru o dată. Cu ele se pot face anumite
operaţii, în funcţie de natura şi structura lor. Astfel, vom spune că o dată are un anumit tip.

Expresii

Majoritatea limbajelor de programare definesc expresiile după un sistem de reguli sintactice,


care, în general sunt următoarele:
1. orice constantă este expresie;
2. orice variabilă este expresie;
3. dacă E este expresie, atunci şi (E), -E, +E, F(E) sunt expresii, unde F este numele unei
funcţii aplicabile expresiei E;
4. dacă E1 şi E2 sunt expresii, atunci şi E1+E2, E1-E2, E1*E2, E1/E2 sunt expresii.

Pe baza regulilor de mai sus putem construi expresii foarte complexe, pornind de la
constante şi variabile. Astfel, să considerăm entitatea (3+A)*(5/(-B+C)) şi să verificăm dacă ea
este expresie sau nu. Să presupunem că A, B şi C sunt variabile numerice întregi. Cum 3 este
constantă, conform regulii 1, ea este şi expresie. A, fiind variabilă este, conform regulii 2 expresie.
Acum, conform regulii 4, 3+A este expresie, iar (3+A) este tot expresie, conform regulii 3. După
simbolul înmulţirii (reprezentat adesea prin *), avem: 5 este expresie, fiind constantă, B, C, apoi -
B şi -B+C sunt expresii. În fine, conform regulii 3, (-B+C) este tot expresie, apoi şi (5/(-B+C))
este expresie, în conformitate cu regula 4, şi, tot după această regulă, şi (3+A)*(5/(-B+C)) este
expresie.
Datele sunt caracterizate de

• Tip
• Nume
• Valoare
• Domeniu de vizibilitate
• Timp de viaţă
• Operatori
• Apeluri de funcții

Variabile în C++

Declararea variabilelor

tip variabila;

tip var1, var2, …, varn;

tip variabila = expresie_constanta;

Variabile globale și variabile locale

Variabile globale: declararea lor se face la începutul programului, în afara oricărei funcţii.

Variabile locale: declararea se face în corpul funcţiei, la început.

Exemplificare

char c;
signed char sc;

int a, b;
a = b = 5;

int i;
int suma = 0;
long j;

float x1,,x2, x3;


float pi = 3.14;
double y;
int patrat(int y)
{
int x; x=y*y;
return x;
}

Variabila x este caracterizata de

• Tip = int
• Nume = x
• Valoare = 4
• Domeniu de vizibilitate: funcția patrat
• Timp de viaţă = pe durata unui apel al funcției

Atribuirea (Asignarea) variabilelor

variabila = expresie;

SAU

Lvalues (left-side) = Rvalues (right-side)

• Lvalues sunt variabile


• Rvalues sunt expresii

Exemplu

În atribuirea

distance = rate * time;

avem: Lvalue: „distance” și Rvalue: „rate * time”

Contraexemple pt Lvalue: 5+5, “str”, const int i

În atribuiri apar alte două probleme, despre care vom vorbi mai târziu:

• Compatibilitate
• Conversii
Tipuri de variabile

Variabilele pot fi : locale si globale.

Tipuri de date

Prin tip de date vom înţelege o mulţime de valori, împreună cu operaţiile ce se pot executa cu ele.
Fiecărei variabile, la declarare, i se va asocia un anumit tip. Tipul unei constante poate fi determinat
implicit din valoarea constantei, sau poate fi precizat explicit ca în cazul variabilelor. Astfel, dacă
constanta K are valoarea numerică 7, putem trage concluzia că ea este de tip întreg, sau de tip real,
nu şi logic sau şir de caractere.
Totuşi, există şi limbaje în care se fac anumite convenţii, de pildă că orice număr diferit de zero
este considerat ca fiind cu valoarea de adevăr adevărat, iar numărul zero are valoarea de adevăr
fals.
Unele limbaje de programare permit declararea unor variabile fără a se preciza tipul lor,
considerându-se astfel ca având un anumit tip general. Astfel, atunci când va fi folosită, variabila
respectivă va fi considerată ca având cel mai adecvat tip cu putinţă, în situaţia concretă respectivă.
De pildă, dacă este declarată o variabilă X, iar la un moment dat i se atribuie valoarea 3,. atunci ea
poate fi considerată ca având un tip numeric. Dacă ulterior, variabila X va primi valoarea „abc”,
adică un şir de caractere, se poate considera că X este de tip şir de caractere.
Pe baza constantelor şi variabilelor se formează expresii. Bineînţeles, în formarea expresiilor se
vor folosi acei operatori, precum şi acele funcţii, permise de tipurile valorilor asupra cărora se
operează. Expresiile mici pot conduce la elaborarea de expresii mai mari, din ce în ce mai
complexe

Domeniul tipului (colecţia de obiecte) – mulțime de valori pentru care s-a adoptat un anumit mod
de reprezentare în memorie

Operaţiile tipului = operațiile ce se pot executa cu valorile de acel tip de date

Categorii de tipuri de date:

• Tipuri de date standard


• Tipuri de date structurate de nivel jos – operaţiile se desfășoară la nivel de componentă
• Tipuri de date de nivel înalt – operaţiile sunt implementate de algoritmi utilizator

Tipuri de date standard în C++

• Tipuri caracter: tipurile char, signed char, unsigned char


• Tipuri întregi: tipurile caracter, întregi cu semn, întregi fără semn, tipurile enumerare
• Tipuri reale: tipurile întregi şi tipurile flotante reale
• Tipuri aritmetice: tipurile întregi şi cele flotante
• Tipuri de bază: caracter, întregi cu şi fără semn, flotante
• Tipul void: desemnează o mulţime vidă

Echivalențe între tipurile de date

signed short int ≡ short


unsigned short int ≡ unsigned short
signed int ≡ int
unsigned int ≡ unsigned
signed long int ≡ long
unsigned long int ≡ unsigned long

Tipuri de date derivate

Acestea se construiesc din obiecte, funcţii şi tipuri incomplete:


• tipul tablou de T (elementele de tip T)
• tipul structură
• tipul uniune
• tipul funcţie, derivat din tipul returnat T şi numărul şi tipurile parametrilor (funcţie ce
returnează T)
• Tipul pointer, derivat dintr-un tip referenţiat (tip funcţie, tip obiect, tip incomplet).
Valorile tipului pointer sunt referinţe la o entitate de tipul referenţiat (pointer la T)
• Tipuri scalare: tipurile aritmetice şi tipul pointer
• Tipuri agregat: tablouri şi structuri
• Un tablou de dimensiune necunoscută, o structură sau uniune cu conţinut necunoscut sunt
tipuri incomplete

Tipuri întregi
Constante întregi
• Octale: au prefixul 0 (zero), de exemplu: 032 = 26 și 077 = 63
• Hexazecimale: au prefixul 0x sau 0X, de exemplu: 0x32 = 50 și 0x3F = 63
• Întregi „long”: au sufixul l sau L, de exemplu: 2147483647L și 0xaf9Fl = 44959
• Întregi „unsigned” au sufixul u sau U, de exemplu: 345u și 0xffffu = 65535
• Caractere între apostrof: ‘A’, ‘+’, ‘n’
• Caractere în zecimal: 65, 42
• Caractere în octal: ’\101’, ‘\52’
• Caractere în hexazecimal: ‘\x41’, ‘\x2A’
• Caractere speciale – secvențe escape
Operații și funcții

Operaţii pentru tipurile întregi: + – * / % == != < <= > >= ++ —

Funcţii:

• cele de la tipul flotant


• cele din bibliotecă: tolower, toupper, isalpha, isalnum, iscntrl, isdigit, isxdigit, islower,
isupper, isgraph, isprint, ispunct, isspace

Operatori

Operatorii ++ și —

Se aplică doar unei expresii ce desemnează un obiect din memorie (L-value).

Tipul flotant (real)

float

• Numere reale în simplă precizie


• sizeof(float) = 4

double

• Numere reale în dublă precizie


• sizeof(double) = 8

long double
• Numere reale în „extra” dublă precizie
• sizeof(long double) = 12

Limitele se găsesc în <float.h>


Operaţii: + – * / == != < <= > >=

Constante reale

• Constantele reale sunt implicit double


• Pentru a fi float trebuie sa aiba sufixul f sau F
• Pentru long double trebuie sa aibă sufixul l sau L
Date booleene (logice)
Tipul bool

• Domeniul de valori: {false, true}


• false = 0
• true = 1, dar şi orice întreg nenul
• Operaţii: ! && || == !=
• Declaraţii posibile:
• bool x = 7; // x devine “true”
int y = true; // y devine 1

Expresii logice
expresie_relationala ::= expr < expr | expr > expr | expr <= expr | expr >= expr | expr == expr |
expr != expr expresie_logica ::= ! expr | expr || expr | expr && expr

Negația logică

! 0 = 1, ! orice_nr_diferit_de_0 = 0

Conjuncția logică. Valoarea expresiilor logice &&

O condiţie de forma a ≤ x ≤ b se scrie în limbajul C++ astfel:


(x >= a) && (x <= b) (a <= x) && (x <= b)
O condiţie de forma a > x sau x > b se scrie în limbajul C++ astfel:
(x < a) || (x > b) !(x >= a && x <= b)

Legile lui De Morgan

• ! (A && B) este echivalent cu !A || ! B


• ! (A || B) este echivalentă cu ! A && ! B

Tipul void

• Conversia în tip void a unei expresii semnifică faptul că valoarea sa este ignorată
• Utilizat pentru tipul pointer; nu se face controlul tipului la un pointer de tip void
• Utilizat pentru funcţii fără valoare returnată sau pentru funcţii fără parametri
• Este un tip incomplet ce nu poate fi completat
• Conversia în tip void a unei expresii semnifică faptul că valoarea sa este ignorată
• Utilizat pentru tipul pointer; nu se face controlul tipului la un pointer de tip void
• Utilizat pentru funcţii fără valoare returnată sau pentru funcţii fără parametri
• Este un tip incomplet ce nu poate fi completat

xStructuri. Utilizare typedef

Typedef este un mecanism prin care se asociază un tip unui identificator:

typedef char litera_mare;


typedef short varsta;
typedef int vector[20];
typedef char string[30];
typedef float matrice[10][10];
typedef struct { double re, im; } complex;

Identificatorul respectiv se poate utiliza pentru a declara variabile:

litera_mare u, v=‘a’;
varsta v1, v2;
vector x; string s;
matrice a;
complex z;

sau funcții

complex suma(complex z1, complex z2) {


complex z;
z.re=z1.re+z2.re; z.im=z1.im+z2.im;
return z;
}

Operatorul condiţional ? :

Sintaxa

exp1 ? exp2 : exp3

Semantica

• Se evaluează exp1
• Dacă exp1 are valoare true (nenulă), atunci valoarea expresiei este valoarea lui exp2;
exp3 nu se evaluează
• Dacă exp1 are valoare false (nulă), atunci valoarea expresiei este valoarea lui exp3; exp2
nu se evaluează
Operatorul ?: este drept asociativ

Exemple

x >= 0 ? x : y
x>y?x:y
x>y?x>z?x:z:y>z?y:z
joc=(raspuns==’1’)?JocSimplu();JocDublu();
#include <iostream>
using namespace std;
void main(){
int a=1, b=2, c=3;
int x, y, z;
x = a?b:c?a:b;
y = (a?b:c)?a:b; /* asociere stanga */
z = a?b:(c?a:b); /* asociere dreapta */
cout<< "x=" << x << "\ny=" << y << "/nz="<< z;
}
/* x=2 y=1 z=2 */

Operatorul virgulă ,

Sintaxa

expresia_virgula ::= expresie, expresie

Semantica

• Se evaluează prima expresie apoi cea de-a doua.


• Valoarea şi tipul întregii expresii este valoarea şi tipul operandului drept.
• Operatorul virgulă are cea mai mică precedenţă.

Exemplu

a = 1, b = 2;
i = 1, j = 2, ++k + 1;
k != 1, ++x * 2.0 + 1;
for(suma = 0, i = 1; i <= n; suma += i, ++i);
Operatorul sizeof()

sizeof() este un operator unar ce permite determinarea numărului de octeţi pe care se reprezintă
un obiect (un tip sau o expresie).

Exemple:

sizeof(int), sizeof(double);
sizeof(b*b-4*a*c), sizeof(i);
sizeof(char)<=sizeof(short)<=sizeof(int)<=sizeof(long)
sizeof(signed)=sizeof(unsigned) = sizeof(int)
sizeof(float)<=sizeof(double)<=sizeof(long double)

Utilizare

#include <iostream>
using namespace std;
void main(){
int x = 1; double y = 9; long z = 0;
cout << "Operatorul sizeof()\n\n\n";
cout << "sizeof(char) = " << sizeof(char) << endl;
cout << "sizeof(int) = " << sizeof(int) << endl;
cout << "sizeof(short) = " << sizeof(short) << endl;
cout << "sizeof(long) = " << sizeof(long) << endl;
cout << "sizeof(float) = " <<sizeof(float) << endl;
cout << "sizeof(double) = " << sizeof(double) << endl;
cout << "sizeof(long double) = " << sizeof(long double) << endl;
cout << "sizeof(x +y + z) = " << sizeof(x+y+z) << endl;
}

Reguli pentru conversia implicită

În absenţa unui unsigned , obiectele se convertesc la tipul cel mai “înalt” în ordinea
(descrescătoare):

long double, double, float, long int, int

Regulile pentru operanzii unsigned depind de implementare.


Conversia la unsigned se face doar în caz de necesitate (de ex. valoarea din unsigned nu “încape”
în celălalt operand).
Regula “integer promotion” : operaţiile se fac cel puţin în int, deci char şi short sunt “promovaţi”
la int.
La o asignare (v = exp) tipul membrului drept se converteşte la tipul membrului stâng (care este şi
tipul rezultatului).

Se pot intimpla situatiile :

• Pierderea preciziei (double ->float ->long int)


• Pierderea unor biţi semnificativi (long ->int)
• Nedeterminări

Exemplu conversii implicite

#include <iostream>
using namespace std;
int main(void){
char c1 = -126, c2; /* c1 = 10000010 */
unsigned char c3, c4 = 255; /* c4 = 111111111 */
short s1, s2 = -32767; /* s2=10000000 00000001 */
short s3 = -1, s4; /* s3 = 11111111 11111111 */
s1 = c1;
cout << "c1=" << (int)c1 << " s1=" << s1 << endl;
c2 = s2;
cout << "c2=" << (int)c2 << " s2=" << s2 << endl;
c3 = s3;
cout << "c3=" << (int)c3 << " s3=" << s3 << endl;
s4 = c4;
cout << "c4=" << (int)c4 << " s4=" << s4 << endl;
return 0;
}

Forţarea tipului – cast

• Conversia explicită la tipul numetip se face prin:

(numetip) expresie

Exemple:

(long)(‘A’ + 1.0)
(int)(b*b-4*a*c)
(double)(x+y)/z
(float)x*y/z
x / (float)2

Exemplu cast

#include <iostream>
using namespace std;
int main(void){
int i, j; double x, y, z, t;
i = 5/2; x = 5/2;
y = (double)(5/2); j = (double)5/2;
z = (double)5/2; t = 5./2;
cout << i << ", " << x << ", ";
cout << y << ", " << j << ", ";
cout << z << ", " << t << ", " << endl;
return 0;
}
/* 2, 2, 2, 2, 2.5, 2.5 */

Fişiere în bibliotecă relative la tipuri

<limits.h>

• pentru tipurile întregi


• Întregul min/max: INT_MIN, INT_MAX
• Numărul de biţi pe caracter CHAR_BIT
• Etc.

<float.h>

• pentru tipurile flotante:


• Exponentul maxim
• Precizia zecimală, etc.

<stdlib.h>

• conţine funcţii de conversie:


• Şir de caractere în int: atoi(const char*)
• Şir de caractere în float: atof(const char*)
• Test de evaluare a cunoștințelor
Intrări / ieșiri

Forma generală
cin >> var; /* citeşte var de la cin */

• Se pot prelua tipurile aritmetice, șiruri de caractere

cout << expr; /* scrie expr la cout */

• Se pot transfera tipurile aritmetice, șiruri de caractere, pointeri de orice tip în afară de
char

• Sunt posibile operaţii multiple, de tipul:

cin >> var1 >> var2 ... >> varN;


cout << var1 << var2 ... << varN;

Instrucțiuni

Instrucţiunea expresie

Sintaxa:

Semantica:

• Se evaluează expresia.
• Dacă este o expresie de forma unei instrucțiuni de atribuire, variabila=expresie, atunci
variabila primește valoarea expresiei din dreapta, vechea valoare a expresiei pierzându-
se.
• Dacă este o expresie de forma variabila op = expresie, aceasta este echivalentă cu
variabila=variabila op expresie, unde op este un operator din mulțimea {+, -, *, /, % }
• Dacă este o expresie de forma variabila++ sau ++variabila, aceasta este echivalentă cu
variabila=variabila+1.
• Dacă este o expresie de forma variabila– sau –variabila, aceasta este echivalentă cu
variabila=variabila-1.
Exemple:

a = b;
a + b + c;
;
cout << a;
sizeof(int);

Instrucţiunea compusă (bloc)

Sintaxa:

• Grupează instrucţiuni/declarații într-o unitate executabilă.


• O instrucţiune compusă este ea însăşi o instrucţiune: oriunde poate să apară o
instrucţiune, este corect să apară şi o instrucţiune compusă.

Semantica:

• Se execută o singură dată fiecare dintre instrucțiuni/declarații, de sus în jos și de la stânga


la dreapta.
• Nu se revine în vreun fel la una dintre instrucțiunile/declarațiile anterioare.

Exemple:

{
int a=3, b=10, c=7;
a += b += c;
cout << a << ", " << b << ", " << c; // ?, ?, ?
}

if (x > y){
int temp;
temp = x; x = y; y = temp;
cout << x << y;
}

{
int a, b, c;
{
b = 2; c = 3; a = b += c;
}
cout << "a= " << a <<endl;
} // ?

Instrucţiunile condiţionale if şi if-else

Sintaxa:

instr_if ::= if (<expresie_booleană>)


{<instructiunea1>;}

instr_if-else ::= if (<expresie_booleană>)


{<instructiunea1>;}
else
{<instructiunea2>;}

expresie_booleană este construită cu:

• Expresii aritmetice
• Comparatori: ==, !=, <, <=, >, >=
• Conectori logici: &&, ||, !

Semantica:

• Se evaluează (o singură dată) expresie_booleană.


• Dacă aceasta este adevărată, atunci se execută instrucțiunea1.
• Dacă nu este adevărată, atunci, dacă este prezentă ramura cu else, se execută
instrucțiunea2.

Problema “dangling else”

Regula:

Regula este: else este ataşat celui mai apropiat if.

int a=1, b=2; // b=3


if (a == 1)
if (b == 2) // b=2
cout << "*****\n";
else
cout << "ooooo\n";
• Nu lăsaţi forma codului să vă ducă în eroare!
• Atenție la diferența dintre operatorii de egalitate și cel de asignare

if ( conditie-1 ) {
instructiuni-1;
}
else if ( conditie-2 ) {
instructiuni-2;
...
}
else if ( conditie-n ) {
instructiuni-n;
}
else {
instructiuni-pt-restul-posibilitatilor;
}

Exemplu:

int main(void){
float operand1, operand2, rezultat;
char operator;
cout << "Expresia:(numar operator numar – FARA SPATII)\n";
cin >> operand1 >> operator >> operand2;
if(operator == '+')
rezultat = operand1+operand2;
else if(operator == '-')
rezultat = operand1-operand2;
else if(operator == '*')
rezultat = operand1*operand2;
else if(operator == '/')
rezultat = operand1/operand2;
else{
cout << "Eroare in scrierea expresiei!";
return 1;
}
cout << "Rezultatul este: " << rezultat << "\n";
return 0;
}
Instrucţiunea switch

Sintaxa:

switch (expresie)
{
case constanta1:
grup de instructiuni 1;
[break;] (break este opțional)
case constanta2:
grup de instructiuni 2;
[break;]
.
.
.
[default:
grup implicit de instructiuni] (default este opțional)
}

Semantica:

• Se evaluează expresia.
• Dacă ea are valoarea constanta1, atunci se execută grupul de instrucțiuni 1, eventual
grupul de instrucțiuni2 etc., până la întâlnirea primului break.
• Dacă ea are valoarea constanta2, atunci se execută grupul de instrucțiuni2 etc., până la
întâlnirea primului break.
• …
• În cazul în care expresia nu este egală cu niciuna din variantele constanta1, constanta2
etc, iar grupul implicit de instrucțiuni este prezent, se execută acesta

Instrucțiunea While

Sintaxa:
Semantica:

• Se evaluează expresia (condiția).


• Dacă ea este nulă / nu este adevărată, se trece la instrucțiunea_următoare.
• Dacă este adevărată, se execută instrucțiunea, apoi se reia ciclul, testându-se din nou
valoarea de adevăr (!=0) a expresiei ș.a.m.d.
• Așadar, cât timp expresia este adevărată, se execută instrucțiunea.

Instrucțiunea do-while

Sintaxa:

Semantica:

• Se execută instructiune.
• Se evaluează conditie: dacă valoarea sa este nenulă controlul este transferat înapoi, la
începutul instrucţiunii do..while; dacă valoarea este nulă se execută
instructiunea_urmatoare.

Instrucţiunea for

Sintaxa:

Una, doua sau toate trei dintre expresii pot lipsi, dar cei doi separatori (;) sunt obligatorii.
Semantica

• Dacă instructiune nu conţine continue şi expr-cond este prezentă, atunci for este echivalent cu:
expr-init;

while(expr-cond){
instructiune;
expr-in/decrementare;
}
instructiunea_urmatoare

• Dacă există continue atunci aceasta transferă controlul la expr-in/decrementare.


• Se evaluează expr-init – în general aceasta se utilizează pentru iniţializarea iteraţiei.
• Se evaluează expr-cond – în general aceasta este o expresie logică ce se utilizează pentru
controlul iteraţiei. Dacă valoarea sa este nenulă(true), se execută corpul buclei do
(instrucţiune), se evalueaza expr-in/decrementare si controlul este trecut la începutul
buclei do, fără a se mai evalua expr-init.
• În general expr-in/decrementare face trecerea la iteraţia următoare: modifică o variabilă
ce intră în componenţa lui expr-cond.
• Procesul continuă până când valoarea expr-cond este nulă (false). Controlul este
transferat următoarei instrucţiuni (cea de după for).

Instrucţiuni de întrerupere a secvenţei

• break;
o se referă la bucla sau instrucţiunea switch cea mai apropiată.
o produce ieşirea din buclă sau din switch şi trece controlul la instrucţiunea
următoare
• continue;
o se referă la bucla (for, while, do..while) cea mai apropiată.
o întrerupe execuţia iteraţiei curente şi trece controlul la iteraţia următoare.
• goto;
o Permite saltul la o anumită secțiune din program, identificată prin punctul de
începere.
• return expr; sau return;
Instrucţiuni de iteraţie – recomandare

• Pentru expresia de control a iteraţiei se recomandă operatorii relaţionali în locul celor de


(ne)egalitate:

int main(){
int contor = 0;
double suma = 0.0, x;
for(x = 0.0; x != 9.9; x += 0.1){
suma += x;
++contor;
}
cout << "suma = " << suma << ", contor= " << contor << "\n";
return 0;
}

S-ar putea să vă placă și