Programarea in limbajul C++ Moştenirea şi compoziţia

1 Scopul lucrării:
·   studierea moştenirii, avantajele şi dezavantajele;
·   studierea compoziţiei;
·   studierea regulilor de definire a moştenirii şi compoziţiei;
·   studierea formelor de moştenire;
·   studierea iniţializatorilor;
·   principiul de substituţie;
·   moştenirea şi compoziţia – ce să alegem.

Sarcina lucrari:
De creat clasa camera, care conţine suprafaţă. Determinaţi constructorii şi metodele de acces. Creaţi clasa apartamente cu o odaie, care conţine o odaie şi o bucătarie (suprafaţa ei), etajul (camera este în clasa apartament cu o odaie). Determinaţi constructorii, metodele de acces. Determinaţi clasa derivată apartamente cu o odaie cu adresă (un câmp adăugător - adresa). Determinaţi constructorii, destructorii şi fluxul de ieşire.
2 Indicatii teoretice
Moştenirea reprezintă unul din cele trei mecanisme de bază a moştenirii orientate pe obiecte. Moştenirea poate fi studiată din două puncte de vedere: dezvoltatorului şi utilizatorului clasei.
Din punct de vedere a dezvoltatorului moştenirea înseamnă, că comportarea şi proprietăţile clasei derivate, sunt nişte dezvoltări a clasei de bază. Din punct de vedere a utilizatorului – moştenirea reprezintă existenţa unor particularităţi de schimbare independenta a claselor cu o interfaţă unică (Inginerii TI şi constructorii de automobile, în primul rând sunt inginerii).
Avantajele moştenirii:
-          micşorarea cantităţii codului şi folosirea lui repetată;
-          micşorarea cantităţii erorilor şi a preţului de cost;
-          o interfaţa unică şi substituţia;
-          mărirea vitezei de prelucrare;
Cheltuielile moştenirii: unicele cheltuieli la folosirea moştenirii poate fi numită micşorarea vitezei la compilarea codului.  Totuşi preocupările de eficacitate nu trebuie să intre in contrazicere cu  avantajele, aşa cum cheltuielile, cu adevărat, nu sunt esenţiale, aşa cum unele din ele pot fi ocolite prin utilizarea funcţiilor de substituire.

Definirea şi utilizarea moştenirii:
Moştenirea se desemnează prin indicarea clasei de bază după numele clasei derivate, după două puncte. Ca de exemplu:

class Animal{
    int NofLegs;
public:
    void Say(){ cout<<”!!!”; }
};
class Dog: public Animal{  // moştenirea
...
};
void main(){
 Dog d;
 d.Say();
}

Din exemplu se vede, că funcţia şi variabila, sunt definite în clasa Animal sunt importate şi pot fi utilizate de obiectul clasei Dog. Starea, ce complică percepţia acestui mecanism, consta din aceia că, clasa derivată poate sa-şi definească comportamentul, primit în clasa de bază. (Struţul şi pinguinul nu zboară, deşi sunt păsări, dar ornitoringul depune ouă, deşi este manifer). Ne vom întoarce la aceasta temă în următoarele lucrări de laborator.
Principiul de substituţiei
Adăugând la cele relatate mai sus, putem spune că, moştenirea presupune, că obiectul clasei derivate poate fi utilizat în locul obiectului de bază:

void main(){
 Animal *ptr = new Dog;
}
 Din exemplu se vede că sunt indice la clasa de bază – deci se aşteaptă utilizarea obiectului de bază,   dar, indicatorului i se atribuie obiectul derivatei.

Formele moştenirii
În relaţiile moştenirii, C++ este un limbaj foarte bogat, aşa cum există cinci forme diferite de moştenire. În această lucrare de laborator noi vom studia trei dintre ele, acele care se numesc simple.
-          deschisă;
-          închisă;
-          protejată;
Diferite forme de moştenire sunt utilizate, pentru a modifica starea accesului pentru variabilele membre clasei. De exemplu, la utilizarea moştenirii închise, toate care sunt accesibile (deschise şi protejate) variabilele clasei de bază devin închise în derivare. Dar prin utilizarea derivării protejate – protejate. Variabilele închise a clasei de bază prin orice forma de derivare devin  inaccesibile. Mai mult ca atât, metodele de moştenire, se deosebesc prin aceia, că moştenirea deschisă creează un subtip de date, adică există principiul de substituţie, dar protejata şi deschisa nu.

Compoziţia
Compoziţia reprezintă încă un mecanism, legat de programarea orientată pe obiecte, care reprezintă relaţia dintre obiecte, atunci când moştenirea este relaţia dintre clase.
Moştenirea realizează relaţia a fi „is a ”. Dog este mamifer, iar mamiferul – animal.
Compoziţia realizează relaţia de a conţine „has a ”. Automobilul conţine motor şi roţi.

Definirea compoziţiei
Cu adevărat compoziţia este folosită foarte larg, aşa cum variabilele încorporate conţin un tip şi sunt utilizate la definirea clasei. Dar la folosirea variabilelor încorporate nu apar întrebări, ceia ce nu se poate spune despre clasele utilizatorilor. Definirea nu este grea, însă utilizarea constructorilor creează probleme.
class Car{
 Engine e;
};
Iniţializatorii
        Cum se ştie variabilele închise a clasei de bază devin inaccesibile, deci, ele nu pot fi iniţiate în constructor, mai mult ca atât, aceasta contrazice principiul repetării codului. Soluţia este una – chemarea constructorului clasei de bază. Aşa şi se întâmplă, numai că pentru constructorii impliciţi şi copiilor sunt generate de compilator. Restul trebuie să fie chemate manual. Aceiaşi problemă apare şi la utilizarea compoziţiei, poate fi utilizat numai constructorul implicit şi copiile. Pentru rezolvarea acestor probleme se utilizează iniţializatorii – care permit chemarea constructorilor şi efectuarea oricărei iniţializări.

class Engine{
 int power;
public:
 Engine(int p){power=p;}
};
class Transport{
...
public:
 Transport(char*);
};
class Car:public Transport{ // наследование
 Engine e;                  // композиция
public:
 Car():Transport(“automobile”),e(10){}
};

Pentru chemarea constructorului clasei de bază, după parantezele rotunde a constructorului derivat se scrie constructorul de bază, mai mult ca atât se poate de transmis parametrii derivatei de bază. La utilizarea compoziţiei starea este aceeaşi, numai că sunt scrise numele variabilelor dar nu a constructorului.
Ce să alegem ?
Aşa ca şi moştenirea şi compoziţia este un instrument de reutilizare a codului, deci apare întrebare: cînd să utilizam moştenirea şi cînd să utilizam compoziţia. Există o mulţime de recomandări în acest sens, dar, mai uşor este de memorat următoare regulă: trebuie sa-ţi pui următoarea întrebare: noua clasa este un subtip  (Dog is an Animal), dacă noi am obţinut un răspuns afirmativ atunci trebuie fi utilizată moştenirea, în caz contrar apare altă întrebare: nu este noua clasă un container (Car has a door) – în acest caz compoziţia.
Cu părere de rău, pentru câteva cazuri această strategie este inutilă. Ca de exemplu, clasa  mulţime poate fi creată pe baza clasei listă, ce metodă să folosim. Se poate moştenirea şi se poate compoziţia. În acest caz regulile sunt complicate. Trebuie să-ţi pui cîteva întrebări:
-          vor fi obiectele noii clase substituite în locul vechii clase?
-          trebuie de redefinit o funcţie virtuală ?
-          prelucrează noul tip aceleaşi mesaje ca şi vechiul ?
-          nu este clasa de bază abstractă ?
Dacă răspunsul este afirmativ, utilizaţi moştenirea.

3 Realizarea sarcinii:

Programul dat a fost compus din două fişiere cu numele şi „File1.cpp”(vezi anexa A) „File2.h”,(vezi fig.1)  în care se conţine funcţia „pause()” care este folosită pentru vizualizarea programului mai comod şi functia de afisare a unei linii, şi definirea unor culori.
 Conţinutul fisierului “File2.h”:
Fig. 1
3.1 Explicarea clasei „camera”:

   class camera{                                  // numele clasei „camera”
private:                                     //variabile private
   int suprafata;                          //variabile, functii publice
public:
   camera():suprafata(0){};                    //constructor implicit
   camera(int s):suprafata(s){};              //constructor explicit
   ~camera(){suprafata=0;};                  //destructor
    ret_s(){return suprafata;};               //functie de returnare a suprafetei
    ins_s(int n){suprafata=n;};               //functie de inscrierea suprafetei
    camera(camera &obj){suprafata=obj.suprafata;};               //constructor de copiere
               //functie prietena, supraincarcare operatorului de intrare (cin>>)
friend istream & operator>>(istream & in, camera & obj){ 
   in>>obj.suprafata;
   return in;    };
               //functie prietena, supraincarcare operatorului de iesire (cout<<)
friend ostream & operator<<(ostream & out, camera & obj){
   out<<obj.suprafata<<" m2";
   return out;                     };
camera & operator=(camera & obj){              //constructor de copiere
this->suprafata=obj.suprafata;
return *this; };
 };

3.2 Explicarea clasei „AP1C (APartamente cu 1 Camera):

   class AP1C:public virtual camera{
     public:
camera odaie;
   camera bucatarie;
   int etaj;
AP1C(){ odaie.ins_s(0); bucatarie.ins_s(0); etaj=0; };            //constructor implicit
 AP1C(int o, int b, int et){                                                                  //constructor explicit
 odaie.ins_s(o);
 bucatarie.ins_s(b);
 etaj=et;
  };
 ~AP1C(){odaie.ins_s(0); bucatarie.ins_s(0); etaj=0;};           //destructor

//*************************************SUPRAINCARCAREA OPERATORULUI CIN >>
 friend istream &operator>>(istream & in, AP1C & obj){
   char  bufer[50];
   cout<<"Introdu suprafata odaiei= ";             in>>obj.odaie;
   cout<<"Introdu suprafata bucatariei= ";       in>>obj.bucatarie;
   cout<<"Introdu Etajul= ";                             in>>obj.etaj;
               return in;};

//***********************************SUPRAINCARCAREA OPERATORULUI COUT <<
friend ostream &operator<<(ostream &out, AP1C & obj){
   out<<"Suprafata odaiei= "<<obj.odaie<<endl;
   out<<"Suprafata bucatariei= "<<obj.bucatarie<<endl;
   out<<"Etajul: "<<obj.etaj<<endl;
   return out; };
};
3.3  Explicarea clasei „AP1CA (APartamente cu 1 Camera cu Adresa):
class AP1CA:public AP1C{
char *stada;
    public:
    AP1CA():AP1C(){stada=NULL; };
    AP1CA(char *str,int o, int b, int et){
               this->stada=new char[strlen(str)+1];
               strcpy(this->stada,str);
               AP1C(o,b,et); };
                AP1CA(AP1CA & obj){
               this->stada=new char[strlen(obj.stada)+1];
               strcpy(this->stada,obj.stada);
               odaie.ins_s(obj.odaie.ret_s());
               bucatarie.ins_s(obj.bucatarie.ret_s());
               etaj = obj.etaj; };
   ~AP1CA(){odaie.ins_s(0); bucatarie.ins_s(0); etaj=0; delete []stada; stada=NULL;};
friend istream & operator>>(istream &in, AP1CA &obj){
    char buf[50]; int s;
    cout<<"Introdu strada: "; in>>buf;
    obj.stada = new char[strlen(buf)+1];
    strcpy(obj.stada,buf);
    cout<<"Etajul: ";  in>>obj.etaj;
    cout<<"Suprafata odaiei= "; in>>s; obj.odaie.ins_s(s);
    cout<<"Suprafata bucatariei= "; in>>s; obj.bucatarie.ins_s(s);
    return in;    };

friend ostream & operator<<(ostream &out, AP1CA &obj){
    out<<"Adresa: "<<obj.stada<<endl;
    out<<"Etajul: "<<obj.etaj<<endl;
    out<<"Suprafata odaiei= "<<obj.odaie<<endl;
    out<<"Suprafata bucatariei= "<<obj.bucatarie<<endl;
    return out;  };
};

3.4 Functia main:
Codul sursa:

void main(){
start: AP1CA *tab;                                          //start - eticheta
del;                                                                   //curata ecranu
int n;
white;                                                               //culoarea alba
cout<<"1 - Introdu un numar N de apartamente"<<endl;
cout<<"2 - Afiseaza apartamentile inscrise"<<endl;
cout<<"Esc - Iesire"<<endl;
sus:
switch (getch()) {                    
case '1':{            del;
                          cout<<"N= ";
                          cin>>n;
                          tab = new AP1CA[n];//alocare de memorie p/u „n” apartamente cu 1 camara cu Adr
                          if (tab==NULL) {                  //verificare daca sa alocat cu succes
                                      cout<<"Memorie insuficienta !"<<endl;
                                      pause();  exit(1);                     }
                          else if (tab!=NULL){
                  del; yellow; linie();
                  for (int i = 0; i < n; i++) {
                  cyan;
                  cout<<"Apartamenul Nr. "<<i+1<<endl;
                  white;
                  cin>>tab[i];                                     //introducerea apartamentilor
                  yellow;
                  linie();                      }
                  pause(); }     break;
                  };
case '2':{ del;
                  for (int i=0; i<n; i++){                    //afisarea apartamentilor
                  yellow; linie();
                  cyan; cout<<"Apartamenul Nr. "<<i+1<<endl;
                  white;   cout<<tab[i]<<endl;
                  yellow;
                  linie(); }       pause();           break;};
case 27:{   pause(); exit(1);};
default : goto sus;
}

goto start;   }
Fig. 2
3.5       Afisarea apartamentilor cu 1 camera (Fig. 3):
Fig. 3
Concluzi:
    In urma efectuarii lucrarii date am determinat ca mediul de prgramare C++   este cu mult flexibil ca C, care ne permite sa manipulam cu informatia intr-un mod rapid si eficient fara a induce erori grosolane, si am aflat ca utilizarea claselor este cu mult mai comod si mai rapid in eleborarea unui program.
Am aflat ca moştenirea reprezintă existenţa unor particularităţi de schimbare independenta a claselor cu o interfaţă unică. Compoziţia reprezintă încă un mecanism, legat de programarea orientată pe obiecte, care reprezintă relaţia dintre obiecte, atunci când moştenirea este relaţia dintre clase.
Moştenirea realizează relaţia a fi „is a ”. Cîine este mamifer, iar mamiferul – animal.
Compoziţia realizează relaţia de a conţine „has a ”. Automobilul conţine motor şi roţi.


Bibliografie
1 TOTUL DESPRE C SI C++ (MANUALUL FUNDAMENTAL DE PROGRAMARE IN C SI C++)[RO][Kris Jamsa][Lars Kland]  
2 PROGRAMARE IN C_C++ CULEGERE DE PROBLEME Valiriu Iorga
3 Initiere in C++, Programarea orientata pe obiecte (Editie Prevazuta) Cluj-Napoca 1993



Anexa A
Fişierul „File1.cpp”
#include <iostream.h>
#include <conio.h>
#include <windows.h>
#include "File2.h"
class camera{
private:
    int suprafata;
public:
    camera():suprafata(0){};
    camera(int s):suprafata(s){};
    ~camera(){suprafata=0;};
     ret_s(){return suprafata;};
     ins_s(int n){suprafata=n;};
     camera(camera &obj){suprafata=obj.suprafata;};
friend istream & operator>>(istream & in, camera & obj){
    in>>obj.suprafata;
    return in;    };
friend ostream & operator<<(ostream & out, camera & obj){
    out<<obj.suprafata<<" m2";
    return out;                     };
camera & operator=(camera & obj){
this->suprafata=obj.suprafata;
return *this; };
 };

//**clasa NR 2*******APartamente cu 1 Camera**********
class AP1C:public virtual camera{
private:
    camera odaie;
    camera bucatarie;
    int etaj;
    char *adresa;
public:
 AP1C(){ odaie.ins_s(0); bucatarie.ins_s(0); etaj=0; adresa="----"; };
 AP1C(int o, int b, int et, char *str){
 odaie.ins_s(o);
 bucatarie.ins_s(b);
 etaj=et;
 adresa = new char[strlen(str)+1];
 strcpy(adresa,str);
 };
 AP1C(char * adr){ adresa = new char[strlen(adr)+1]; strcpy(adresa,adr); };
 ~AP1C(){odaie.ins_s(0); bucatarie.ins_s(0); etaj=0; delete []adresa; adresa=NULL;};

//*******SUPRAINCARCAREA OPERATORULUI CIN >>
 friend istream &operator>>(istream & in, AP1C & obj){
   char  bufer[50];
   cout<<"Introdu suprafata odaiei= ";              in>>obj.odaie;
    cout<<"Introdu suprafata bucatariei= ";       in>>obj.bucatarie;
    cout<<"Introdu Etajul= ";                             in>>obj.etaj;
    cout<<"Introdu Adresa= ";
   in>>bufer;
   obj.adresa = new char[strlen(bufer)+1];
   strcpy(obj.adresa,bufer);
    return in;};

//*******SUPRAINCARCAREA OPERATORULUI COUT <<
friend ostream &operator<<(ostream &out, AP1C & obj){
    out<<"Suprafata odaiei= "<<obj.odaie<<endl;
    out<<"Suprafata bucatariei= "<<obj.bucatarie<<endl;
    out<<"Etajul: "<<obj.etaj<<endl;
    out<<"Adresa: "<<obj.adresa;
    return out; };
};
//*************************************
void main(){
start:
AP1C *tab;
del;int n;
white;
cout<<"1 - Introdu un numar N de apartamente"<<endl;
cout<<"2 - Afiseaza apartamentile inscrise"<<endl;
cout<<"Esc - Iesire"<<endl;
sus:switch (getch()) {
case '1':{  del;
                           cout<<"N= ";
                           cin>>n;
                           tab = new AP1C[n];
                           if (tab==NULL) {
                            cout<<"Memorie insuficienta !"<<endl;
                                       pause();  exit(1);                     }
                           else if (tab!=NULL){
                  del; yellow; linie();
                  for (int i = 0; i < n; i++) {
                  cyan;
                  cout<<"Apartamenul Nr. "<<i+1<<endl;
                  white;
                  cin>>tab[i];
                  yellow;
                  linie();                      }
                  pause(); }     break;
                  };
case '2':{ del;
                  for (int i=0; i<n; i++){
                  yellow; linie();
                  cyan; cout<<"Apartamenul Nr. "<<i+1<<endl;
                  white;   cout<<tab[i]<<endl;
                  yellow;
                  linie(); }       pause();           break;};

case 27:{   pause(); exit(1);};
default : goto sus;
}
goto start;  }






Fişierul „File2.h”
# define   white SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 11)  //alb
# define   yellow SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10) //galben
# define   cyan SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 8)    //cyan
# define  del  clrscr();         //curata ecranul
//******************MENU PAUZA
linie(){
for (int i = 0; i < 51; i++) cout<<"-";
cout<<endl;
};
void pause(){
yellow;
cout<<endl<<endl<<"Apasati orice tasta...";
getch();
white;
};

Niciun comentariu: