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




Relatii intre clase

c


Relatii intre clase

La elaborarea modelului obiectual al unei aplicatii se disting urmatoarele doua etape:



a)      identificarea claselor - corespunzatoare conceptelor aplicatiei (substantivele),

b)      stabilirea relatiilor dintre clase - corespunzatoare specificatiilor aplicatiei (verbele).

In cele ce urmeaza ne vom referi la urmatoarele tipuri de relatii intre clase:

Asociatie relatie de cooperare intre clase - corespunzatoare unui verb oarecare din specificatie, diferita de relatia parte-intreg (de exemplu relatia Student - Facultate). Relatia corespunzatoare dintre obiecte apartinand unor clase asociate se numeste legatura. O asociatie poate fi simpla sau multipla (daca un obiect asociant este pus in legatura, de exemplu prin pointeri, cu mai multe obiecte asociate, de acelasi tip). Aceasta relatie se reprezinta grafic (dupa metodologia OMT) in plan orizontal astfel:


Agregare - relatie de asociatie prin care obiectul agregat este inclus in obiectul agregant (verbul caracteristic este a avea), si evident ca poate fi simpla sau multipla:

Specializare (generalizare, mostenire) - relatie prin care sunt pastrate (mostenite) caracteristicile unei clase (de baza) si sunt adaugate diferentele specifice, formand o noua clasa (derivata). Mostenirea permite reutilizarea de cod definit in clasa de baza (superclasa) si in noua clasa (sublasa). Deci, o subclasa este o specializare a unei superclase (verbul caracteristic fiind a fi), iar o superclasa este o generalizare a unei subclase. Aceasta relatie este tranzitiva, iar structura formata de multimea clas 848g69i elor aflate in aceasta relatie (construita pe verticala) se numeste ierarhie de clase. Atat specializarea cat si mostenirea poate fi simpla sau multipla, reprezentarea facandu-se in plan vertical astfel:


Se pot obtine in felul acesta si ierarhii spatiale de clase, avand relatii atat pe orizontala cat si pe verticala.

Relatia de Asociatie

Prin aceasta relatie dintre clase se modeleaza o legatura intre obiectele instantiate (care depind unul de celalalt). Traversarea unei asociatii se face printr-un rol (nume dat extremitatatii unei asociatii). Implementarea unei asociatii se poate realiza astfel:

a)      printr-un pointer - clasa asocianta contine un atribut de tip pointer spre clasa asociata,

b)      printr-o clasa - cu atribute si comportare proprie, fiecare legatura fiind o instanta a acestei clase.

Asociatiile pot fi unidirectionale sau bidirectionale, iar relatiile de asociatie pot fi binare, ternare sau n-are. Pe de alta parte, asociatiile pot fi simple sau multiplicative (acestea din urma putand fi eventual si cu restrictii de ordonare sau de calificare).

Asociatiile multiplicative sunt caracterizate prin numarul de instante ale claselor care se afla in asociatie, iar pentru a reprezenta directia de asociatie se pot utiliza sageti.

O asociatie multiplicativa poate sa fie neordonata (instantele formeaza o multime), sau poate sa fie ordonata (instantele formeaza o lista ordonata).

O relatie multiplicativa cu restrictie de calificare pune in relatie doua clase printr-un calificant (atribut care reduce multiplicitatea asociatiei printr-un criteriu pe care trebuie sa-l indeplineasca obiectele asociate pentru a intra in relatie).

La implementarea relatiilor de asociatie putem aplica cele doua metode amintite anterior:

a)      prin pointeri spre clasa asociata incuibariti in clasa asocianta in functie de tipul relatiei de asociere astfel:

pentru relatia de asociatie simpla se adauga clasei asociante inca un atribut de tip pointer spre clasa asociata, impreuna cu relaxarea incapsularii pentru traversarea asociatiei alegand o metoda convenabila dintre urmatoarele variante:

modificarea protectiei datelor membru implicate in public,

utilizarea de metode sau clase friend,

extinderea interfetei prin metode de acces la componente.

pentru relatia de asociatie multipla se adauga clasei asociante mai multe atribute de tip pointer in functie de tipul asociatiei si ordinul de multiplicitate astfel:

daca este relativ mic, se vor adauga pointeri distincti,

iar in caz contrar se poate utiliza un sir de pointeri;

daca relatia este supusa unor restrictii de ordonare, se pot utiliza liste ordonate.

b)      prin clase distincte care realizeaza abstractizarea asociatiilor daca legaturile au proprietati si operatii proprii (nemaifiind necesara adaugarea de atribute claselor care se asociaza), aceasta metoda utilizandu-se in special in cazul asociatiilor bi­di­rec­tionale de tip m-n), sau o legatura poate conecta obiecte de clase diferite.

Exemplu:

Clase asociate

#include <conio.h>

#include <iostream.h>

#include 'VectCaut.h'

void main (void)

while (a);

cout << ' Dati m : '; cin >> n;

VectSort* Y=new VectSort(n); Y->Sort();

VectCaut* y=new VectCaut(Y); Y->Print();

do

while (a); getche();

// Clasa asocianta << VectCaut.h >>

#include 'VectSort.h'

class VectCaut ;

// Clasa asociata << VectSort.h >>

class VectSort ;

// Clasa asocianta << VectCaut.Cpp >>

# include 'VectCaut.h'

VectCaut::VectCaut (VectSort *p)

int VectCaut::CautSec(int a)

int VectCaut::CautBin(int a)

return 0;

// Clasa asociata << VectSort.Cpp >>

# include <iostream.h>

# include 'VectSort.h'

VectSort::VectSort (int k)

void VectSort::Sort( )

Sortat;

do k++; }

while (!Sortat);

void VectSort::Print ( )

int* VectSort::Adr ( )

int VectSort::Dim ( )

VectSort::~VectSort ( )

Relatia de Agregare

Relatia de agregare este cea mai puternica relatie de asociatie, in care o clasa este o componenta a altei clase, deci relatia este binara, unidirectionala, iar relatiile multiplicative sunt de tip 1-n. Prin aceasta relatie dintre clase, un obiect al clasei agregate este parte constituenta, atribut, al clasei agregante, deci verbul caracteristic este a avea (contine). Obiectele con­sti­tuente pot fi independente sau doar componente ale obiectului care le include.

Aceasta relatie (notata cu simbolul avand semnificatia contine) are urmatoarele doua proprietati de baza:

a)      tanzitivitate : Daca Cx Cy si Cy Cz, atunci Cx Cz

b)      antisimetrie : Daca Cx Cy atunci Cy Cx .

Relatia de agregare poate fi:

a)      fixa - numarul si tipul componentelor sunt fixe,

b)      variabila - permite un numar variabil de obiecte de acelasi tip,

c)      recursiva - accepta acelasi tip ca tip agregat si agregant.

Exemplu:

Relatia de agregare

#include <conio.h>

#include <iostream.h>

#include 'Vect_Agr.h'

void main (void)

while (a);

cout << ' Dati m : '; cin >> n;

VectCaut* Y=new VectCaut(n); Y->Sort(); Y->Print();

do

while (a); getche();

// Clasa Agreganta << Vect_Agr.h >>

#include 'VectSort.h'

class VectCaut ;

// Clasa Agreganta << Vect_Agr.Cpp >>

# include 'Vect_Agr.h'

VectCaut::VectCaut (int n) : V(n)

void VectCaut::Sort ()

void VectCaut::Print ()

int VectCaut::CautSec(int a)

int VectCaut::CautBin(int a)

return 0;

// Clasa Agregata << VectSort.h >>

class VectSort ;

// Clasa Agregata << VectSort.Cpp >>

# include <iostream.h>

# include 'VectSort.h'

// A fost deja descrisa la clase asociate.

In urmatorul exemplu se va folosi o clasa Iterator pentru lista simplu inlantuita care utilizeaza clasa Elem pentru un nod al listei si clasa Lista:

Iterator Lista

#include <conio.h>

#include <iostream.h>

# define Tel int

class Elem

friend class Lista;

friend class Iterator;

class Lista

void Ad (Tel);

friend class Iterator;

void Lista::Ad (Tel elem)

else Cap=new Elem(elem,0);

class Iterator

Tel operator () ( ) // elementul curent

void operator ++ ( ) // avanseaza in lista

int operator ! ( ) // exista element

void main (void)

getche();

Clase Incuibate(imbricate)

Exista posibilitatea definirii unei clase (incuibate) in interiorul altei clase (ca si atribut al cesteia). Aceasta posibilitate exista de fapt si la structuri (struct) si uniuni (union).

Declararea obiectelor din clasa incuibata se poate realiza utilizand operatorul de scop (::) asa cum se poate vedea in exemplul urmator:

Clase Imbricate

class Cerc ; /*

*/

};

void main ()

Utilizarea obiectelor din clasa incuibata se poate realiza utilizand operatorul de apartenenta (.) dupa cum se vede in urmatorul exemplul:

Clase Incuibate

#include <conio.h>

#include <iostream.h>

class Cerc

void Print ()

};

Punct Centru;

public: Cerc (Punct P, float raza)

void Print()

};

void main ()

Evident ca din clasa incuibata (Punct) nu avem acces la elementele clasei din care face parte (Cerc). Daca se doreste acest lucru, atunci se poate proceda ca si in urmatorul exemplu:

Clase Incuibate

#include <conio.h>

#include <iostream.h>

class Cerc

class Punct;

friend Punct;

class Punct

void Print (Cerc c)

};

// void Cerc::Punct::Print (Cerc c)

void main ()

Se poate observa in exemplul dat ca referirea atributului r al clasei Cerc nu este permisa din interiorul clasei incuibate (vezi functia Print descrisa in ambele variante), motiv pentru care clasa Punct a fost declarata prietena.

In urmatorul exemplu sunt imbricate clasele R R2 R3

Clase Incuibate

#include <conio.h>

#include <iostream.h>

class R

class R2; friend R2;

class R2

class R3; friend R3;

class R3

void Print (R,R2);

};

void Print (R);

}; };

void R::R2::Print (R a)

void R::R2::R3::Print (R a, R2 b)

void main ()

Relatia de derivare

Prin aceasta relatie putem modela similitudinile dintre clase doua sau mai multe clase. Pornind de la o clasa de baza (generala) se pot deriva noi clase (prin diferentele specifice). Obiectele clasei derivate mostenesc atributele si metodele clasei de baza la care se vor adauga noile elemente caracteristice (vor fi umflate), ceea ce permite reutilizarea resurselor deja pregatite in clasele de baza (pentru obiectele similare). Verbul caracteristic al acestei relatii de specializare este a fi ( . este un fel de . <a kind of>).

Mostenirea permite pastrarea ele­men­telor (date si functii ale) unei clase de baza (superclasa), cu definirea de noi elemente construind o noua clasa derivata (subclasa), formand in felul acesta ierarhii de clase. Mostenirea poate fi si multipla daca o clasa mosteneste mai multe clase. Deoarece aceasta relatie este tranzitiva se utilizeaza si termenii de stramos si descendent.


Clase derivate

Relatia de derivare se poate descrie prin constructii speciale fara a mai fi nevoie de o relaxare a incapsularii, asa cum a fost necesara la relatiile prezentate anterior. Daca intr-o aplicatie se poate utiliza relatia de derivare, este de preferat in locul asociatiei sau agregarii pentru ca avem instrumente specializate in limbajul de programare.

O clasa derivata se declara astfel:

class Clasa_Derivata Lista_clase_de_baza



Lista claselor de baza poate sa contina si modificatorii de protectie (Mod_Pr) public, protected sau private, deci o derivare poate sa fie publica, protejata sau privata, accesul rezultat fiind redat in urmatoarele tabele.


De exemplu, daca cele doua clase sunt descrise astfel:

class Cl_Baza

class Cl_Derivata : Mod_Pr Cl_Baza

atunci protectia membrilor din clasa derivata este redata in schema alaturata.

Ordinea de executare a constructorilor la instantierea obiectelor dintr-o clasa derivata:

prima data se executa constructorul clasei de baza, apoi constructorul clasei derivate (se construiste cadrul, apoi se adauga diferentele specifice).

Ordinea de executare a destructorilor la distrugerea obiectelor dintr-o clasa derivata:

prima data se executa destructorul clasei derivate, apoi destructorul clasei de baza

Constructorul clasei derivate transmite parametrii necesari constructorului clasei de baza prin apelul direct al acestuia astfel:

Clasa_Derivata Clasa_de_baza ( . ) ; // inline

sau

Clasa_Derivata :: Clasa_Derivata ( . ) Clasa_de_baza ( . ) ; //inline

Deoarece relatia de derivare este poate cea mai importanta relatie dintre clase, sunt oferite facilitati de implementare, care permit urmatoarele facilitati:

economia de cod - reutilizarea codului scris o singura data dupa care se mosteneste,

extensibilitate - re-specializare prin derivarea de noi ramuri dintr-o ierarhie,

polimorfism - intr-o ierarhie de clase se poate implementa o comportare polimorfica,

incapsulare-relaxare - relatia de derivare ofera posibilitatea inchiderii resurselor simultan cu deschiderea spre modificare si extensie.

Relatiile de derivare (de fapt si celelalte relatii dintre clase) sunt stabilite la compilare, deci nu se mai pot modifica pe parcursul executiei. Mai trebuie cunoscut faptul ca prin derivare nu se pot mosteni constructorii, destructorii, elementele prietene (functii, clase sau metode friend) si nici operatorii redefiniti.

Exemplu:

Relatia de derivare

#include <conio.h>

#include <string.h>

#include <iostream.h>

class N

~N

char* Modul ( )

};

void Print (N n)

class Z : public N

~Z

char Semnul( )

};

void Print (Z n)

void main (void)

Conversia unui obiect dintr-o clasa derivata intr-un obiect apartinand clasei de baza este permisa, invers insa nu (sursa trebuie sa acopere destinatia):

Contra_Exemplu:

Conversii la derivare

void main (void)

getche();

Pentru o functie care are ca parametru formal un obiect al clasei de baza este permis apelul avand ca parametru un obiect al clasei derivate, invers nu (o functie care are ca parametru formal un obiect al clasei derivate, nu poate fi apelata avand ca parametru actual un obiect al clasei de baza).

Exemplu:

Conversie la derivare

#include <conio.h>

#include <string.h>

#include <iostream.h>

class N

N (char* s)

N (N& n)

~N ( )

char* Modul ( )

void Print (N n)

class Z : public N

Z (char* s) : N(s+1)

~Z ( )

char Semnul( )

};

void Print (Z n)

void WriteAbs (N n)

void WriteAbs_(N*n)

void main (void)

In exemplul urmator se porneste de la clasa de baza VectBaza si se construieste clasa derivata Vect_Der :

Relatia de derivare

#include <conio.h>

#include <iostream.h>

#include 'Vect_Der.h'

void main (void)

while (a);

cout << ' Dati m : '; cin >> n;

Vect_Der* Y=new Vect_Der(n); Y->Sort(); Y->Print();

do

while (a); getche();

// Clasa de baza << VectBaza.h >>

class VectBaza ;

// Clasa de baza << VectBaza.Cpp >>

# include <iostream.h>

# include 'VectBaza.h'

VectBaza::VectBaza (int k)

void VectBaza::Sort( )

Sortat;

do k++; }

while (!Sortat);

void VectBaza::Print ( )

VectBaza::~VectBaza ( )

Clasa Derivata << Vect_Der.h >>

#include 'VectBaza.h'

class Vect_Der : public VectBaza ;

// Clasa Derivata << Vect_Der.Cpp >>

# include 'Vect_Der.h'

Vect_Der::Vect_Der (int n) : VectBaza(n)

int Vect_Der::CautSec(int a)

int Vect_Der::CautBin(int a)

return 0;

In exemplul care urmeaza, datele x,y (din clasa de baza Punct) au fost declarate protected deoarece clasa derivata (Cerc) le refera. La clasa derivata am utilizat modificatorul public pentru a putea utiliza si pentru Cerc operatia Contine (PIC).

// Program Fct_NeVirtuala;

#include <stdio.h>; #include <conio.h>; #include <iostream.h>; #include <math.h>;

float Sqr (float x)

class Punct ;

Punct::Punct (float x0, float y0)

float Punct::Dist (Punct P)

int Punct::Contine(Punct P)

class Cerc : public Punct

float Dist (Punct P)

};

void main (void)

Rezultate:

Cercul C nu contine punctul P.

Se observa in exemplul de mai sus ca rezultatul nu este cel dorit. Acest neajuns il vom rezolva mai tarziu declarand Distanta ca functie virtuala (pentru legare dinamica

Fata de mostenirea simpla, in care dintr-o singura clasa de baza se deriveaza una sau mai multe clase derivate (specializate), mostenirea multipla presupune existenta mai multor clase de baza din care un sau mai multe clase mostenesc diverse caracteristici.

Declararea unei clase derivate din mai multe clase de baza se face astfel:

class Clasa_de baza ;

class Clasa_de baza ;

class Clasa__derivata : Mod_Pr Clasa_de baza Mod_Pr Clasa_de baza

unde Mod_Pr I

Datorita mostenirii multiple o clasa de baza poate fi prezenta in mai multe exemplare intr-o clasa derivata, asa cum se poate vedea in exemplul alaturat, unde datele membru ale clasei Animal vor fi mostenite in doua exemplare de catre clasa Caine (unul prin clasa Domestic, altul prin clasa Mamifer) si pot fi referite prin operatorul de rezolutie ( :: ) aplicat clasei prin care se face mostenirea (Nume).

Aceasta mostenire repetitiva a unei clase de baza este corecta si se poate utiliza astfel:

class Cl_Baza ;

class Cl_Der1 : public Cl_Baza ;

class Cl_Der2 : public Cl_Baza ;

class Clasa_Derivata : public Cl_Der1, Cl_Der2

Daca dorim realizarea unei singure copii a atributelor mostenite, vom folosi mostenirea multipla virtuala:

class Cl_Baza ;

class Cl_Der1 : virtual public Cl_Baza ;

class Cl_Der2 : virtual public Cl_Baza ;

class Clasa_Derivata : public Cl_Der1, Cl_Der2

;

Asa cum se poate vedea in exemplul urmator, vom avea un nume de mamifer si un nume domestic.

// Program Clase NeVirtuale;

#include <iostream.h>

#include <conio.h>

#include <string.h>

class Animal

};

class Mamifer : public Animal

};

class Domestic: public Animal

};

class Caine : public Mamifer, public Domestic

void Tip()

};

void main (void)

// Rezultate:

Nume Mamifer : Cane

Nume Domestic: Nero

Greutate : 13

Pret : 1300

Lant : 8

Daca dorim ca datele membru sa fie prezente intr-un singur exemplar in clasele derivate, atunci vom utiliza clase virtuale. O clasa de baza devine virtuala prin mostenire daca se declara aceasta prin cuvantul virtual plasat inaintea clasei (devenind astfel clasa virtuala fata de clasa derivata

Programul anterior modificat astfel incat numele sa fie memorat intr-un singur exemplar este urmatorul:

// Program Clase Virtuale;

#include <iostream.h>

#include <conio.h>

#include <string.h>

class Animal

};

class Mamifer : virtual public Animal

};

class Domestic: virtual public Animal

};

class Caine : public Mamifer, public Domestic

void Tip()

};

void main (void)

// Rezultate:

Nume Animal : Lup

Greutate : 13

Pret : 1300

Lant : 8

Pentru o ierarhie ca cea din figura alaturata, in care avem clase virtuale ( ) si nevirtuale ( ), se executa mai intai constructorii claselor de baza virtuale apoi cei ai claselor nevirtuale, iar constructorul clasei de baza se va executa pentru o singura data toate exemplarele virtuale si cate o data pentru fiecare exemplar nevirtual.

Exemplul:

// Program Ierarhie Clase Virtuale/Nevirtuale;

#include <iostream.h>

#include <conio.h>

class A

class B: virtual public A

class C: virtual public A

class D: public A

class E

class F

class G: public B, public C, public D, public E, virtual public F

void main (void)

// Rezultate:

A : Ob.

F : Ob.

B : Ob.

C : Ob.

A : Ob.

D : Ob.

E : Ob.

G : Ob.





Document Info


Accesari: 5407
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. 2025 )