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”:
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:
Trimiteți un comentariu