Documente online.
Zona de administrare documente. Fisierele tale
Am uitat parola x Creaza cont nou
 HomeExploreaza
upload
Upload




CONCEPTE DE BAZĂ ÎN PROGRAMAREA OBIECTUALĂ UTILIZÂND C++

Informatica


CONCEPTE DE BAZĂ ÎN PROGRAMAREA OBIECTUALĂ UTILIZ ND C++



1.1. Clase, constructori si destructori

O clasa este un tip care poate contine ca membri variabile si functii care sa manipuleze aceste variabile. Functiile membre ale unei clase se mai numesc metode, iar variabilele membre se mai numesc atribute, sau simplu, date. Exista si functii numite "prietene", care nu sunt membri ai clasei, dar au acces la membrii clasei (acestea pot fi membre ale altei clase sau nemembre în nici o clasa). De asemenea, exista clase prietene.

O clasa poate avea o parte privata, care poate fi accesata doar de membrii si de prietenii clasei, o parte publica, care poate fi accesata de oriunde, si o parte protejata. Astfel, clasa realizeaza o încapsulare si ascunderea informatiei. Folosind clase, se separa detaliile de implementare de interfata.

O variabila de tipul unei clase se numeste obiect sau instantiere sau instanta a clasei respective. Un obiect încapsuleaza atât o stare, cît si o functionalitate.

Sintaxele pentru declararea unei clase si a unor obiecte de tipul unei clase sunt urmatoare 838i817i le:

class [nume [: clase_de_baza ]]

[obiecte];

[ class ] nume obiecte;

Cuvântul rezervat class declara un tip clasa sau se foloseste pentru a defini obiecte de tip clasa. Elementele din definitia unei clase sunt:

nume este numele clasei. El devine cuvânt rezervat în interiorul clasei.

clase_de_baza specifica clasele din care este derivata clasa. Numele fiecarei clase de baza poate fi precedat de un specificator de acces (public, private, protected) si de cuvântul-cheie virtual (vezi mostenirea - capitolul 1.3).

membri declara membri sau prieteni ai clasei. Membrii pot fi: date, functii, clase încuibate, enumerari, câmpuri de biti, tipuri. Prietenii pot fi functii sau clase. Nu sunt permise initializari explicite de date. Clasa poate contine un pointer sau o referinta spre un obiect de tipul ei, dar nu poate contine obiecte statice de tipul ei.

obiecte declara obiecte de tipul clasei.

//general

class CDreptunghi

friend void PatratMic(CDreptunghi&);

//functie prietena

}d; //d este o instanta a clasei CDreptunghi

inline void CDreptunghi::Set

(int latVal, int lungVal)

void CDreptunghi::Set(CDreptunghi &drept)

void PatratMic(CDreptunghi& drept)

int main()

Metodele definite în interiorul declaratiei clasei sunt implicit inline. Pentru cele definite în afara declaratiei clasei se poate specifica explicit sa fie inline, prefixându-le cu cuvântul-cheie inline, asa cum arata definitia metodei Set(int, int).

Directiva de compilare Inline determina generarea codului functiei în locul apelului ei. Activarea ei în Microsoft Visual C++ se face din Project Setings->Tab C/C++->combo Inline function expansion setat pe Only __inline sau Any Suitable. Functiile inline scurte duc la cresterea eficientei la executie, pe când cele lungi duc la cresterea dimensiunii codului.

Indiferent de modul de definire a functiei, este obligatoriu ca la fiecare apel de functie membra a unei clase sa fie precizat obiectul care o apeleaza, sub forma:

nume_obiect.nume_metoda 

sau

pointer_obiect->nume_metoda

Operatorul de rezolutie trebuie folosit la definirea membrilor în afara declaratiei clasei. El mai poate fi folosit pentru a ne referi la membrii clasei.

class C

O metoda urmata de sufixul const poate citi membrii clasei, dar nu îi poate modifica. Ca exemplu, este gresit sa setam latimea dreptunghiului în metoda Arie():

lat = 3; //gresit în metoda Arie() const

Ca orice functie în C++, functiile membre pot fi supraîncarcate. Functiile supraîncarcate au acelasi nume. Ele trebuie sa contina un numar diferit de argumente sau cel putin unul din argumente sa fie de un alt tip (adica numarul si/sau tipul argumentelor sa fie diferit). Tipul valorii returnate de o functie nu este factor distinctiv în cazul functiilor supraîncarcate.

O clasa poate avea si membri care sunt comuni tuturor instantelor si care exista si daca nu avem nici o instanta a clasei. Ei se pot accesa si în afara contextului unui obiect. Acestia sunt membri statici. Datele statice trebuie initializate la început, chiar daca sunt private. Metodele statice nu pot accesa decât date statice.

//membri statici

class C

static void ResetSuma() // in afara contextului unui obiect

}a, b; //a si b sunt instante ale clase C

int C::suma = 0;

//initializarea membrului static (chiar daca este private)

int main()

Obiectele unei clase sunt initializate de anumite functii membre ale clasei, numite constructori (pot fi: mai multi, unul sau nici unul). Constructorii au numele la fel ca al clasei. De asemenea, se poate defini pentru o clasa o metoda care sa se ocupe de distrugerea instantelor sale. O astfel metoda se numeste destructor. Destructorul are numele ~numele_clasei. O clasa poate avea doar un singur destructor.

Motivul principal pentru care este bine sa avem constructori este ca acestia furnizeaza un mod foarte convenabil de alocare/dezalocare a memoriei dinamice. Daca programatorul nu furnizeaza constructori sau destructor pentru o clasa, compilatorul presupune ca acestia exista sub cea mai simpla forma posibila (dar nu genereaza constructorul implicit în cazul în care exista vreun constructor definit).

//generarea constructorului implicit

class C

este echivalent cu:

class C;

Constructorul implicit nu este generat:

class C

int main()

Daca avem tablou de obiecte, trebuie sa existe neaparat un constructor fara parametri:

//tablou de obiecte

class C

int main()

Ei se definesc ca functiile membre obisnuite; fata de acestea însa, constructorii/destructorul sunt implicit apelati atunci când se creeaza/distrug obiecte ale clasei respective.

Destructorii reprezinta un mecanism complementar constructorilor si ei sunt apelati în ordine inversa celei de apelare a constructorilor.

//ordinea apelului destructorilor

#include <stdio.h>

class C

~C()

int main()

Rezultatul executiei acestui program este:

S-a apelat constructorul pentru obiectul 1.

S-a apelat constructorul pentru obiectul 2.

S-a apelat destructorul pentru obiectul 2.

S-a apelat destructorul pentru obiectul 1.

Caracteristici ale constructorilor si destructorilor (C si D)

C si D nu returneaza nici un fel de valoare, nici macar de tipul void, chiar daca pot contine instructiuni return;

când  C si D nu sunt definiti, sunt generati de compilator ca metode publice;

C pot avea multiple definitii (supraîncarcarea constructorilor vezi polimorfismul - capitolul 1.3), D poate avea doar una singura;

C pot avea parametri, D nu poate avea nici un parametru;

C si D nu se mostenesc de catre descendenti ca si alte metode (vezi mostenirea - capitolul 1.3);

C nu pot fi metode virtuale; D pot fi metode virtuale, dar toate metodele destructori ale obiectelor derivate trebuie sa fie tot virtuale (vezi polimorfismul - capitolul 1.3).

Exemplul urmator ilustreaza utilitatea constructorilor si a destructorilor la alocarea/eliberarea dinamica a memoriei.

//alocare/eliberare cu C si D

#include <string.h>

class CSir //constructor implicit

CSir(char* sir)

~CSir()

int main()

Ca si celelalte metode, constructorii si destructorii trebuie sa fie accesibili pentru pozitia în care se creeaza/distrug obiecte de tipul clasei respective.

//accesul la C si D

class C

~C()

int main()

Obiectele pot fi create static sau dinamic.

//obiecte statice si dinamice

class C{

public:

C()

~C()

int main()

Constructorii impliciti sunt generati automat de catre compilator, daca nu au fost scrisi de programator.

Un obiect dintr-o clasa poate fi folosit pentru a se crea si initializa un altul (folosind un constructor de copiere) sau pentru a se modifica un obiect deja existent (atribuire prin copiere).

//C de copiere si atribuire prin copiere

class CPunct

int main(), punct2 =

CPunct punct3 = punct1;

// constructor de copiere; punct3 =

punct2 = punct1; //atribuire prin copiere; punct2 =

return 0;

Acolo unde nu sunt definiti explicit un constructor de copiere si un operator de atribuire, se folosesc unii impliciti. Cei impliciti este recomandat sa fie folositi acolo unde destructorul clasei nu realizeaza eliberarea memoriei dinamice, întrucât pot fi mai eficienti decât operatiile de copiere definite de programator.

// C de copiere si operator de atribuire prin copiere la alocarea dinamica

//gresit

class CPunct

~CPunct()

int main()

În acest exemplu, constructorul de copiere egaleaza data coordonate a lui punct3 cu cea a lui punct1, si, întrucât  coordonate este de tip pointer, aceasta înseamna ca coordonate ale celor doua puncte indica spre aceeasi zona de memorie. De asemenea, copierea coordonatelor lui punct1 peste cele ale lui punct2 face ca si coordonate pentru punct2 sa indice aceeasi zona.

Asadar, toate cele trei puncte au coordonatele indicând spre aceeasi zona, deci vom avea un singur set de coordonate pentru toate cele trei puncte - ceea ce nu este de dorit (fiecare punct ar trebui sa aiba setul propriu de coordonate). Pe lânga aceasta, la distrugerea acestor obiecte, aceeasi zona este eliberata de trei ori, rezultând o eroare. Pentru a evita aceasta, pentru o clasa al carei destructor elibereaza spatiul alocat dinamic de constructor, programatorul trebuie sa defineasca un constructor de copiere si un operator de atribuire prin copiere. Pentru o clasa C, acestia pot fi (const nu este obligatoriu):

C::C(const C &); //constructor de copiere

C& C::operator=(const C &)

//operator de atribuire prin copiere

unde operator este un cuvânt rezervat care permite supraîncarcarea operatorilor (vezi capitolul 1.4).

Pentru clasa CPunct, din exemplul 11, ar trebui sa avem:

// C de copiere si operator de atribuire prin copiere la alocarea dinamica

//corect

class CPunct

CPunct(const CPunct &);

// declaratia constructorului de copiere

CPunct& operator=(const CPunct &);

// declaratia operatorului de atribuire

~CPunct()

CPunct::CPunct(const CPunct &p)

}

CPunct& CPunct::operator=(const CPunct& p)

int main()

Astfel, la distrugerea obiectelor, pentru fiecare se va elibera zona proprie alocata.

this este un pointer constant catre obiectul pentru care este invocata metoda, iar *this reprezinta chiar obiectul. Folosind this, ne putem referi la membrii obiectului (nu si la functiile prietene). Operatorul de atribuire definit întoarce o referinta spre obiect, deci nu are loc nici o alocare, ci doar atribuiri.

Asa cum am mai spus, pe lânga functiile obisnuite (exemplul 1), prietene ale unei clase pot fi alte clase sau functii membre ale altei clase.

//tipuri de prieteni

class A;

class C;

class B;

class A;

void B::metodaB(A& obiectA)

void C::metodaCPrietena(A& obiectA)

void C::metodaC(A& obiectA)

void fPrietena(A& obiectA)

int main()

Relatia de prietenie nu este tranzitiva (daca clasa C este prietena a clasei B, iar B este prietena a clasei A nu rezulta ca C este prietena a clasei A).

//ne-tranzitivitatea prieteniei

class B;

class A;

class C;

class B

friend C;

//C este prietena clasei B, deci are acces la toti membrii clasei B

class C

int main()

O clasa poate avea ca membri obiecte de tipul unei alte clase. În exemplul urmator, obiectele din clasa CLinie contin câte doua obiecte de tipul clasei CPunct. Acestea se creeaza atunci când se creeaza obiecte CLinie. Un constructor pentru obiectele CPunct poate fi apelat explicit, iar daca nu este apelat, atunci în mod implicit este apelat constructorul implicit al clasei CPunct.

//obiecte membre

class CPunct  //constructorul implicit

CPunct(int xVal, int yVal, int zVal)

void Reset()

class CLinie{ //clasa CLinie

public:

CPunct p1, p2; //obiecte din clasa CPunct

CLinie() //constructor implicit

CLinie(int xVal1, int yVal1, int zVal1,

int xVal2, int yVal2, int zVal2)

//constructor cu parametri

:p1(xVal1, yVal1, zVal1),

p2(xVal2, yVal2, zVal2)

//apelul constructorilor pentru cele 2 obiecte CPunct

int main()

De asemenea, o clasa poate contine ca membri pointeri catre obiecte din alta clasa. Pentru acesti membri, la crearea unui obiect din clasa care-i contine (în exemplul urmator, CLinie), nu se apeleaza implicit constructorii impliciti ai clasei obiectelor referite.

//membri: pointeri catre obiecte

class CPunct  //constructorul implicit

CPunct(int xVal, int yVal, int zVal)

void Reset()

class CLinie

CLinie(int xVal1, int yVal1, int zVal1,

int xVal2, int yVal2, int zVal2)

~CLinie()

int main()

Se poate lucra si cu pointeri catre membri ai claselor. Un pointer catre un membru al unei clase nu este asociat unui obiect particular, ci clasei respective, el continând deplasamentul membrului în cadrul oricarui obiect de tipul clasei. Declararea unui pointer la membru se face astfel:

pentru metode:

tip_returnat(clasa::*nume_ptr_metoda)(parametri);

pentru date:

tip clasa::*nume_ptr_data;

Pentru preluarea adresei unui membru într-un pointer se foloseste sintaxa:

pointer_membru = &clasa::membru

Pentru accesarea unui obiect se pot folosi notatiile:

pentru accesarea dintr-un obiect static:

obiect.*pointer_membru

pentru accesarea dintr-un obiect dinamic:

pointer_obiect->*pointer_membru

În exemplul urmator este ilustrata folosirea pointerilor catre membri atât ca membri ai unei clase, cât si ca variabile independente.

//pointeri catre membri

class A

class B;

void B::Metoda(A a, A* pa)

int main()

Probleme propuse

1. Sa se scrie o aplicatie care creeaza un tablou de obiecte din clasa persoana. Pentru fiecare persoana se cunosc:

numele si prenumele

adresa

codul numeric personal

seria si numarul de buletin

alte observatii

Programul va realiza toate operatiile pentru gestionarea tabloului de persoane, si anume: adaugarea unui element, stergerea unui element, cautarea unui element, afisarea continutului întregului tablou.

2. Sa se scrie un program pentru gestionarea deranjamentelor într-o retea de telefonie. Deranjamentele pot fi de doua feluri:

deranjamente ale posturilor telefonice ale abonatilor, caracterizate prin:

q       numele (si prenumele) abonatului

q       numarul de telefon

q       descrierea textuala a deranjamentului

q       data si ora semnalarii

q       data si ora rezolvarii

deranjamente ale echipamentelor din cadrul cutiilor existente pe teren, caracterizate prin:

q       codul de identificare a centralei careia îi apartine cutia (alfanumeric: de exemplu: CENTA02),

q       codul de identificare al echipamentului (alfanumeric: de exemplu: YZK235),

q       numarul de telefon,

q       descrierea deranjamentului 

q       data si ora semnalarii

q       data si ora rezolvarii

Sa se implementeze câte o clasa pentru fiecare tip de deranjament. Ca si atribute, pe lânga cele care descriu deranjamentul, se cere ca fiecare deranjament sa aiba un identificator unic printre instantele din clasa sa. În acest sens, fiecare clasa sa fie prevazuta cu un membru static, care sa se incrementeze la fiecare obiect creat si sa reprezinte identificatorul acelui obiect. De asemenea, fiecare clasa sa aiba un contor al instantelor. Pentru fiecare clasa, pe lânga atribute (private), sa se implementeze urmatoarele metode publice:

constructori (fara parametri, cu parametri, constructor de copiere),

operator de atribuire, metoda de initializare,

metode set/get (seteaza/returneaza),

metoda de afisare

metoda de adaugare la arhiva a unui deranjament (o operatie de adaugare la un fisier),

destructor.

Aplicatia va crea mai multe obiecte de tipurile de mai sus, si va seta atributele lor în diferite moduri (folosind constructorii, metoda de initializare, operatorul de atribuire); de asemenea, se vor afisa obiectele create si arhiva într-un fisier.


Document Info


Accesari: 3584
Apreciat: hand-up

Comenteaza documentul:

Nu esti inregistrat
Trebuie sa fii utilizator inregistrat pentru a putea comenta


Creaza cont nou

A fost util?

Daca documentul a fost util si crezi ca merita
sa adaugi un link catre el la tine in site


in pagina web a site-ului tau.




eCoduri.com - coduri postale, contabile, CAEN sau bancare

Politica de confidentialitate | Termenii si conditii de utilizare




Copyright © Contact (SCRIGROUP Int. 2024 )