Skip to content

Latest commit

 

History

History
155 lines (138 loc) · 9.33 KB

POO_22_C_2022-05-19.md

File metadata and controls

155 lines (138 loc) · 9.33 KB

Mostenire multipla

C++ este unul dintre putinele limbaje de programare care accepta mostenire multipla, adica o clasa mosteneste mai multe clase. Clasele mostenite se enumera separate prin virgula dupa caracterul :, specificand in fata fiecarei clase modul in care acea clasa este mostenita: public, protected, private si optional specificatorul virtual.

Imagine: mostenire multipla

class C: public A, public B
{
	...
	C(...):A(...),B(...)
	{...}
};

Inainte de crearea obiectul instanta C sunt create subobiectele instanta A si apoi celei instanta B. Mostenirea multipla vine si cu probleme suplimentare. Problema cea mai cunoscuta este cea a "Diamantului" care apare atunci cand o clasa mosteneste mai multe clase si cel putin doua din cele mostenite au stramos comuni. La instantiere, facilitatile stramosului ajung in obiectul creat pe doua cai. De fapt, obiectul creat va avea doua subobiecte instanta stramosului.

Imagine: mostenire multipla - problema Diamantului

class S
{
public:
	void f(){cout << "f" << endl;}
}

class A: virtual public S
{};

class B: virtual public S
{};

class C: public A, public B
{};

void main()
{
	C c;
}

La instantierea clasei C o data cu obiectul c apar doua obiecte instanta A, respectiv B si pentru fiecare dintre aceste ultime doua obiecte cate un subobiect S, adica in total 5 obiecte in memorie. Problema apare atunci cand din obiectul instanta C incercam sa apelam/utilizam o facilitate mostenita din clasa S, fie ea camp sau functie, adica, in exemplul nostru, problema apare la apelul c.f();. Din cauza ca in memorie exista doua subobiecte instanta S, compilatorul nu poate decide din care aceste subobiecte va apela functia f(), rezultand eroare la compilare. Solutia consta in a mosteni clasa S virtual. Se spune astfel ca S este o clasa virtuala in ierarhie. In urma mostenirii virtuale a clasei S, la instantierea clasei C se va creea un singur subobiect S si in consectinta apelul c.f(); nu mai genereaza eroare la compilare.

Clase imbricate

Exista posibilitatea declararii unei clase in interiorul altei clase.

class A
{
	...
	class B
	{...};
	...
};

In exemplul de mai sus, spunem ca B este imbricata in clasa A. Clasa B nu are acces la membrii protejati sau privati din clasa A si nici invers. O clasa o descriem imbricata in alta clasa in general atunci cand numai in implementarea clasei mari este necesara existenta unor obiecte instanta clasei imbricate. Putem insa instantia clasa imbricata din exterior folosind operatorul de rezolutie:

A::B b;
class C
{
	...
	class B
	{...};
	...
};

Cele doua clase, desi au acelasi nume, sunt diferite (B din A si B dn C).

C::B

Clase template

Pe langa functii template, C++ ofera ca suport de programare generica si clase template pentru care unul sau mai multe tipuri de date sunt generice (nespecificate atunci cand descriem clasa). Inaintea unei clase template trebuie sa apara acea specificatie pe care am intalnit-o la functiile template si anume, cuvantul rezervat template, urmat de o lista de date generice, specificata intre < si >. In fata fiecarui tip generic, apare tipul rezervat class.

template <class T1, class T2,...>
class A
{...};

Pentru a nu avea probleme la link-editare in Visual C++ trebuie sa implementam toate metodele in momentul descrierii clasei, ci nu separat in fisier .cpp. Daca in cazul functiilor template nu era nevoie la apel sa indicam tipurile de date ce substituie tipurile generice, identificarea lor facandu-se pe baza tipurilor de date ale parametrilor, in cazul claselor template trebuie sa specificam de fiecare data, cand ne referim la ele, intre < si > tipurile de date ce inlocuiesc tipurile generice. De exemplu, pentru clasa A, vom scrie:

A<int,float,...>

(A de int float ...)

template <class T>
class Punct3D
{
	T x, y, z;
public:
	Punct3D(T X, T Y, T Z)
	{x = X; y = Y; z = Z;}
	T abs(){return x*x + y*y + z*z;}
};

void main()
{
	Punct3D<int> p1(1,2,3);
	cout << p1.abs() << endl;
	Punct3D<float> p2(1,0.5,2);
	cout << p2.abs() << endl;
}

Toate functiile membre unei clase template devin la randul lor functii template.

Ierarhia ios

ios - input output stream standard Ierarhia este pornita de clasa ios. Clasa ios porneste ierarhia, contine o serie de facilitati comune intregii ierarhii, in schimb nu se instantiaza direct. Clase aflate pe pozitii mai jos se instantiaza efectiv pentru a prelucra fluxul. Ierarhia ios foloseste instante de obiecte ale ierarhiei streambuf atunci cand fluxurile sunt prelucrate. Un obiect instanta din ierarhia streambuf gestioneaza buffer-ul atasat fluxului. Din cauza ca atunci cand prelucram un flux prin intermediului unui obiect instanta clasei ios si implementarea claselor a fost facut incat un obiect streambuf este gestionat automat, nu este necesar sa cunoastem membrii claselor streambuf, fiind suficient a cunoaste membrii claselor ios. Din clasa streambuf sunt derivate clasele filebuf (fiind specializata pe buffere atasate fisierelor) si strstreambuf (fiind specializata pe buffere pentru stringuri). Clasa ios are doi constructori: ios() si ios(streambuf* buf). Clasa ios contine urmatoarele campuri:

  • adjustfield: este un camp constant static transmis de obicei in al doilea parametru al functiei setf; aceasta constanta este folosita pentru curatatea bitilor de formatare legati de aliniere (left sau right).
  • basefield: este un camp static constanta de tip long si este folosit pentru caratarea bitilor de formatare pentru bazele de numeratie.
  • floatfield: constanta statica de tip long pentru curatarea bitilor de formatare cu virgula mobila (reale).
  • bp: memoreaza adresa buffer-ului atasat fluxului, adica obiectul instanta streambuf.
  • state: este o valoare de tip int ce memoreaza starea fluxului; bitii acestui camp daca sunt 1 inseamna ca au aparut erori in prelucrarea fluxului si dau informatii cu privire la tipul erorii.
  • x_fill: o valoare de tip int care este folosit pentru caracterul pentru umplerea spatiilor libere
  • x_flags: o valoare de tip long ce retine bitii de formatare la scriere (aliniere, baze de numeratie, etc.)
  • x_precision: o valoare de tip long care retine precizia de afisare in virgula mobila a numerelor reale, adica numarul de cifre exacte folosite la afisare.
  • x_width: valoare int ce retine numarul de caractere pe care se face afisarea.

Campurile care nu sunt constante de mai sus nu sunt publice. Aceste campuri se modifica folosind functii ale clasei ios sau ale claselor derivate din ios. Functiile membre clasei ios:

  • int bad(): returneaza o valoare nenula atunci cand in prelucrarea fluxului au aparut erori; sunt interogati bitii ios::badbit si ios::hardfail.
  • int fail(): returneaza o valoare nenula daca au aparut erori in prelucrarea fluxului, interogandu-se in plus fata de int bad() si bitul ios::failbit.
  • int good(): returneaza 1 daca nu au aparut erori in prelucrarea fluxului.
  • void clear(int st=0): aduce fluxul din nou in stare buna; campul state al parametrului, implicit 0, evident cand nu exista erori.
  • char fill(): returneaza caracterul folosit pentru caracterul care umple spatiile libere, adica returneaza valoarea lui x_fill.
  • char fill(char c): seteaza noul caracter al lui x_fill cu valoarea lui c si returneaza vechiul caracter al x_fill.
  • long iosflags(): returneaza valoare campului x_flags.
  • long iosflags(long f): seteaza noua valoare a lui x_flags cu valoarea lui f si returneaza vechea valoare a lui x_flags.
  • void init(streambuf* buf): specificam adresa unui buffer ce se ataseaza fluxului curent.
  • int precision(): returneaza precizia de afisare a numerelor reale.
  • int precision(int p): seteaza precizia x_precision la valoarea lui p si se returneaza vechea valoare a lui x_precision.
  • stringbuf* rdbuf(): returneaza adresa catre buffer-ul fluxului.
  • int rdstate(): returneaza valoarea lui state.
  • int setstate(int s): campul state devine s.
  • long setf(long flags: bitii 1 ai variabilei x_flags fac sa devina biti 1 pe pozitiile corespunzatoare in campul x_flags si se returneaza vechea valoare a campului x_flags.
  • long setf(long flags,long field): reseteaza bitii (ii face 0) din x_flags pe pozitiile indicate de bitii cu valoare 1 ai parametrului field si seteaza bitii din x_flags la valoarea 1 pe pozitiile in care bitii sunt 1 in parametrul flags, returnand valoarea campului x_flags inainte de modificare.
  • long unsetf(long l): bitii 1 ai variabilei l anuleaza setari din campul x_flags.
  • void sync_width_stdin(): fluxul ios este sincronizat cu fluxul standard de intrare din C; sincronizarea incetineste executia.
  • ostream* tie(): este returnata adresa fluxului legat de fluxul curent; de exemplu, fluxul cin este legat de cout.
  • ostream* tie(ostream* f): fluxul curent este legat de adresa data ca parametru, returnandu-se vechea legatura.
  • int width(): returneaza valoarea campului x_width.
  • int width(int w): este setata lungimea la afisarea formatata, returnandu-se vechea lungime.