![]() |
Índex |
Miguel A. Almarza
Departament d'Informàtica IES Mare de Deu de la Merce |
La classe Punt | |
#include <iostream.h> #include <conio.h> class Punt { int x; int y; char Caracter; public: Punt(); Punt(int n1,int n2); Punt(int n1,int n2,char Car); void PosaCaracter(char c); void PosaCoordenades(int n1, int n2); void Dibuixat(); int TornaX(); int TornaY(); char TornaCaracter(); void ImprimeixDades(); }; | Aquesta és la declaració de la classe Punt. Aquesta declaració de la classe ha de tenir també escrites després totes les funcions. No les incloem aquí ja que estan escrites en capítols anteriors. |
La classe PuntColor | |
class PuntColor : public Punt { int ColorPrimerPla; int ColorFons; public: void PosaColors(int C1, int C2); void Dibuixat(); void ImprimeixDadesColor(); }; La declaració de la classe PuntColor és class PuntColor : public Puntque indica que hereta la classe Punt. Això fa que els objectes de la nova classe disposin de les dades i funcions membre de la classe Punt. Veiem que a la classe PuntColor hi ha les noves dades ColorPrimerPla i ColorFons. També veiem que hi ha les noves funció membre PosaColors() i ImprimeixDadesColor(). Fem notar que també apareix la funció Dibuixat() que ja apareixia a la classe pare Punt. Hem de reescriure-la ja que en aquesta funció hem de incloure el color. Es a dir que es pot donar dins la classe filla el mateix nom a una funció que sigui més especialitzada que la de la classe pare. Apareix una altra vegada la idea de polimorfisme amb aquest fet. | |
void PuntColor::PosaColors(int C1, int C2) { ColorPrimerPla=C1; ColorFons =C2; } void PuntColor::ImprimeixDadesColor() { cout << "\n"; ImprimeixDades(); cout << "Color de primer pla: " << ColorPrimerPla; cout << ", Color de fons: " << ColorFons << "\n"; } void PuntColor::Dibuixat() { gotoxy(TornaX(),TornaY()); textbackground(ColorFons); textcolor(ColorPrimerPla); cprintf("%c",TornaCaracter()); } | Implementació de les noves funció membre de la classe PuntColor. Veiem que la funció ImprimeixDadesColor() té accés a la funció ImprimeixDades() de la classe pare. Les funcions de les classes filles tenen accés a les funcions públiques de la classe pare. Fem notar que la funció Dibuixat() de la classe filla és molt diferent de la funció Dibuixat() de la classe pare, però que té el mateix nom. |
main () { clrscr(); PuntColor A; A.PosaCoordenades(3,3); A.PosaCaracter('W'); A.PosaColors(RED,WHITE); A.Dibuixat(); A.ImprimeixDadesColor(); } | A la funció main declarem l'objecte A di tipus PunColor. Veiem que aquest objecte té accés a tots els elements (dades i funcions membre) de la classe pare Punt. |
#include <iostream.h> #include <conio.h> class Rectangle { int x1,y1; int x2,y2; public: int Tipus; void PosaA(int x, int y){x1=x;y1=y;} void PosaB(int x, int y){x2=x;y2=y;} int TornaX1(){return x1;} int TornaY1(){return y1;} int TornaX2(){return x2;} int TornaY2(){return y2;} void Dibuixat(); }; class RectangleInteligent : public Rectangle { public: float Superficie(); }; |
Escrivim la classe Rectangle que te com a dades privades x1,y1 i x2,y2. Te una sola dada pública que és el tipus i totes les
funcions membre són públiques. Fem que la classe RectangleInteligent sigui filla de la classe rectangle amb accés public de la classe filla respecte a la classe pare. Feta d'aquesta manera l'herència tenim que:
|
float RectangleInteligent::Superficie() { int Base, Altura; Base = TornaX2()-TornaX1()+1; //Base = x2-x1+1; Errada Altura = TornaY2()-TornaY1() +1; return (float) Base * Altura; } |
La funció membre RectangleInteligent té accés a les funcions publiques de la classe pare com TornaX1() o TornaY1() però no té accés a les dades privades de la classe pare com x1 o y1. |
void Rectangle::Dibuixat() { int i; gotoxy(x1,y1); cout << "┌"; for(i=x1+1;i<x2;i++) cout << "─"; gotoxy(x2,y1); cout << "┐"; for(i=y1+1;i<y2;i++) { gotoxy(x1,i); cout << "│"; gotoxy(x2,i); cout << "│"; } gotoxy(x1,y2); cout << "└"; for(i=x1+1;i<x2;i++) cout << "─"; gotoxy(x2,y2); cout << "┘"; } |
|
main() { clrscr(); RectangleInteligent C1; C1.PosaA(2,2); C1.PosaB(20,20); C1.Dibuixat(); cout << "\n" << C1.Superficie() << "\n"; C1.Tipus = 23; cout << C1.Tipus; //C1.x1=3; Errada } | Els objectes de la classe RectangleInteligent tenen accés a tots els
elements públics de la classe Pare com la dada Tipus o la funció membre PosaA.
Els objectes de la classe RectangleInteligent no tenen accés a cap element privat de la classe Pare Rectangle. |
#include <iostream.h> class Pare { private: int a; public: int b; void PosaA(int n){a=n;} }; class Fill : private Pare { int c; public: void PosaDades(int n1,int n2, int n3); }; | Declarem la classe Pare amb tres elements, la dada privada
a, la dada pública b i la funció pública PosaA. Declarem la classe Fill amb herència de tipus private respecte a la classe Pare. Així tenim que tots els elements de la classe Pare són elements privats de la classe filla. és a dir que a, b i PosaA són elements privats de la classe Fill. |
void Fill::PosaDades(int n1,int n2, int n3) { PosaA(n1); b=n2; c=n3; //a=n1; Errada } | Les funcions de la classe filla tenen accés als elements
públics de la classe Pare quan l'accés de la classe filla és private.
Però no tenen accés als elements privats de la classe Pare. Així la funció PosaDades de la classe Fill té accés a la funció PosaA i a la dada a de la classe Pare. La funció PosaDades no té accés a la dada b de la classe Pare. |
main() { Fill Obj; // Obj.PosaA(23); Errada // Obj.b=23; Errada PosaDades(1,2,3); } | Ara declarem l'objecte obj de la classe Fill que té accés
privat a la classe Pare. Aquest objecte no té accés a cap dada de la classe Pare. |
#include <iostream.h> class Pare { private: int a; protected: int b; public: int c; void PosaDades(int n1,int n2,int n3) { a=n1;b=n2;c=n3; } int TornaA(){return a;} int TornaB(){return b;} int TornaC(){return c;} }; main() { Pare Objecte1; Objecte1.PosaDades(34,23,12); Objecte1.a = 888; //No vàlid ja que a ès private Objecte1.b = 888; //No vàlid ja que b és protected Objecte1.c = 888; //Vàlid ja que c ès públic } | Els objectes d'una classe no tenen accés als elements declarats com a protected.
Així l'objecte Objecte1 no té accés a la dada b. |
class Fill : public Pare { int d; public: void PosaD(int n){d=n;} int TornaD(){return d;} }; main() { Fill Objecte2; //Valid: public + public = public Objecte2.PosaDades(34,23,12); //No vàlid: private + public = private Objecte2.a = 888; //No vàlid: protected + public = protected Objecte2.b = 888; //Vàlid: public + public = public Objecte2.c = 888; } | Els objectes de la classe heretera tipus public tenen accés als elements protected de la classe pare.
Així l'objecte Objecte2 té accés a la dada b. |
class Fill : public Pare { int d; public: void PosaD(int n){d=n;} int TornaD(){return d;} void CanviaDadesPare() { a=10; //No vàlid. private de la classe Pare b=10; //Vàlid. protected de la classe Pare c=10; //Vàlid. public de la classe Pare } }; | Les funcions membre de la classe filla tenen accés als elements protected de la classe pare
Així la funció membre CanviaDadesPare de la classe Fill té accés a la dada b de la classe Pare. |
Public | Private | Protected | ||
Accés de la classe filla a la classe pare. | ||||
Public | Public | Private | Protected | |
Private | Private | Private | Private | |
Protected | Protected | Private | Protected | |
#include <iostream.h> class Pare { int a; public: Pare(int a=0) { this->a = a; cout << "Executat el constructor de la classe Pare\n"; } ~Pare() { cout << "Executat el destructor de la classe Pare\n"; } }; class Fill : public Pare { int b; public: Fill(int b=0) { this->b = b; cout << "Executat el constructor de la classe Fill\n"; } ~Fill() { cout << "Executat el destructor de la classe Fill\n"; } }; main() { Fill Objecte1; } |
|
![]() |
#include <iostream.h> class Pare { int x,y; public: Pare(int x, int y) { this->x=x; this->y=y; } void PImprimeix() { cout << "x=" << x << ", y=" << y << "\n"; } }; class Fill : public Pare { int z; public: Fill(int x, int y, int z) : Pare(x, y) { this->z = z; } void FImprimeix() { PImprimeix(); cout << "z= " << z << "\n"; } }; main() { Fill Objecte1(2,5,9); Objecte1.FImprimeix(); } |
![]() #include <iostream.h> class PuntRecta { double x; public: PuntRecta(double x=0) {this->x=x;} void AssignaPuntRecta(double x) {this->x=x;} double TornaX() {return x;} }; class PuntPla : public PuntRecta { double y; public: PuntPla(double x=0, double y=0) : PuntRecta(x) { this->y=y; } void AssignaPla(double x, double y) { AssignaPuntRecta(x); this->y=y; } double TornaY() {return y;} }; class PuntEspai : public PuntPla { double z; public: PuntEspai(double x=0, double y=0, double z =0) : PuntPla(x, y) { this->z=z; } void AssignaEspai(double x, double y, double z) { AssignaPla(x, y); this->z=z; } double TornaZ() {return z;} }; main() { PuntEspai A(4,6,8); cout << "(" << A.TornaX() << "," << A.TornaY() << "," << A.TornaZ() << ")"; } |
![]() #include <iostream.h> class Xoco { float Pes; public: Xoco(float Pes=0){this->Pes = Pes;} float TornaPes(){return Pes;} }; class Llet { float Volum; public: Llet(float Volum=0){this->Volum = Volum;} float TornaVolum(){return Volum;} }; class XocoLlet : public Xoco, public Llet { public: XocoLlet(float Pes=0, float Volum=0) : Xoco(Pes), Llet(Volum){}; }; main() { XocoLlet Got1(200,250); cout << "Got1. Xoco pes: "<< Got1.TornaPes() << ", Llet volum; " << Got1.TornaVolum(); } |
![]() Si ens fixem en la figura veiem que la classe Derivada3 hereta dues vegades a la classe Base, una pel camí de la classe Derivada1 i altra pel camí de la classe Derivada2. Així quan declarem un objecte de la classe Derivada3 tindrem espai reservat per a les dades de la classe Base dos cops en el nostre objecte de la classe Derivada3. De fet el llenguatge C++ fa aquesta duplicació i quan intentem accedir a aquestes dades dona error d'ambigüitat ja que les té duplicades i no sap quines ha d'utilitzar. Per evitar això hem de fer que l'herència de les classes Derivada1 i Derivada2 sigui virtual respecte a la classe Base segons la notació class Derivada2 : virtual public Base Així evitarem que es dupliquin les dades dins la classe Derivada3. A l'exemple següent fem la classe Producte que té les classes derivades Xoco i Llet declarades com virtuals. D'aquestes dues classes derivem la classe XocoLlet que per tant també es deriva de la classe Producte. Cal indicar que ara en la crida al constructor de la classe XocoLlet incloem la crida als constructors de les tres classes de la que es derivada aquesta de XocoLlet incloent el de la classe Producte encara que XocoLlet no es deriva directament de Producte. |
![]() #include <iostream.h> #include <string.h> class Producte { char Tipus[45]; public: Producte(char * T){strcpy(Tipus,T);} char * TornaTipus(){return Tipus;} }; class Xoco : virtual public Producte { float Pes; public: Xoco(float Pes=0) : Producte("Comestible") {this->Pes = Pes;} float TornaPes(){return Pes;} }; class Llet : virtual public Producte { float Volum; public: Llet(float Volum=0) : Producte("Comestible") {this->Volum = Volum;} float TornaVolum(){return Volum;} }; class XocoLlet : public Xoco, public Llet { public: XocoLlet(float Pes=0, float Volum=0) : Xoco(Pes), Llet(Volum), Producte("Comestible") {}; }; main() { XocoLlet Got1(200,250); cout << Got1.TornaTipus(); } |
#include <iostream.h> class Base { int a; public: void PosaA(int n) {a=n;} int TornaA(){return a;} }; class Derivada : public Base { int b; public: void PosaB(int n) {b=n;} int TornaB(){return b;} }; main() { Derivada ObjecteDerivada; ObjecteDerivada.PosaA(10); ObjecteDerivada.PosaB(34); //Assignació de ll'adreça d'un objecte //derivat a un punter a la classe base Base * pObjecteBase; pObjecteBase = &ObjecteDerivada; pObjecteBase->PosaA(75); cout << "a=" << pObjecteBase->TornaA() << "\n"; pObjecteBase->PosaB(95); //Errada } |
#include <iostream.h> class Base { double x; public: Base(double x) {this->x=x;} void Imprimeix() { cout << "x= " << x << endl; } double TornaX(){return x;} }; class Derivada : public Base { double y; public: Derivada(double x, double y) : Base(x) {this->y=y;}; void Imprimeix() { cout << "x=" << TornaX() << ", y=" << y << endl; } }; main() { Base P(6); Derivada Q(2,6); P.Imprimeix(); Q.Imprimeix(); } | La funció void Imprimeix() està definida en la classe Base i en la classe Derivada. Així tenim que amb les intruccions Q.Imprimeix(); la funció que s'executa depen del tipus d'objecte que la crida, es a dir depen del tipus de P i del tipus de Q. Hem de fer notar que el compilador sap, en el moment de compilar quina funció Imprimeix() ha d'utilitzar ja que és l'objecte P o l'Objecte Q els que estan escrits a aquestes instruccions. |
#include <iostream.h> class Original { public: double x; Original(double x) {this->x=x;} virtual void Mostra() { cout << "Fent ús de Mostra() de la classe original "; cout << x << endl; } }; class Derivada1 : public Original { public: Derivada1(double x) : Original(x){}; void Mostra() { cout << "Fent ús de Mostra() de la classe Drivada1 "; cout << 2*x << endl; } }; class Derivada2 : public Original { public: Derivada2(double x) : Original(x){}; void Mostra() { cout << "Fent ús de Mostra() de la classe Drivada2 "; cout << x*x << endl; } }; main() { int Opcio; Original *pOb; Original Ob(10); Derivada1 Ob1(10); Derivada2 Ob2(10); cout << "Tria (1 Original//2 Derivada1//3 Derivada2): "; cin >> Opcio; if (Opcio==1) pOb = &Ob; if (Opcio==2) pOb = &Ob1; if (Opcio==3) pOb = &Ob2; pOb->Mostra(); } | En la classe original origina veiem que la funció Mostra es declara
com a virtual i que també l'hem definida.
En les dues classes derivades també està declarada i definida. El prototip de les tres funcions és el mateix. En la funció main veiem que declarem tres objectes de cada classe i u punter a objecte de la classe base Original. Després de construir els tres objectes demanem a l'usuari quin vol mostrar i és en aquest moment quan assignem a al punter pOb un dels objectes. Així que la instrucció pOb->Mostra() executa una funció segons el que triï l'usuari. (Moment d'execució, lligadura dinàmica) Això és polimorfisme en temps d'execució. |
#include <iostream.h> class BaseAltura { double Base; double Altura; public: void PosaDimensions(double Base, double Altura) { this->Base=Base; this->Altura=Altura; } void DonamDimensions(double &b, double &h) { b=Base; h=Altura; } virtual double TornaArea() = 0; }; class Rectangle : public BaseAltura { public: double TornaArea() { double Base, Altura; DonamDimensions(Base,Altura); return Base*Altura; } }; class Triangle : public BaseAltura { public: double TornaArea() { double Base, Altura; DonamDimensions(Base,Altura); return Base*Altura/2; } }; main() { BaseAltura *pBA; Rectangle R; R.PosaDimensions(4,5); Triangle T; T.PosaDimensions(10,10); pBA = &R; cout << "El rectangle té àrea " << pBA->TornaArea() << endl; pBA = &T; cout << "El triangle té àrea " << pBA->TornaArea() << endl; } | La classe BaseAltura és una classe que serveix de base per a dues
classes Triangle i Rectangle. Aquesta classe BaseAltura té una funció virtual pura, la funció: que ha de definir-se en les classes derivades. Aixó fa que la classe BaseAltura sigui una classe abstracta que serveix en aquest cas per proveir a les classes derivades de les dades Base i Altura i els mètodes d'assignació i extracció de dades. Més important és la declaració de la funció TornaArea() com a virtual que proveeix a les classes derivades d'un prototipat obligatori així com la obligació de definir-la en les classes derivades. |
#include <iostream.h> class Punt { double x,y; public: Punt(double n1=0.0, double n2=0.0) { x = n1; y = n2; } void Imprimeix() { cout << "(" << x << "," << y << ")"; } double TornaX() {return x;} double TornaY() {return y;} }; |
class Vehicle { char Tipus[50]; int nRodes; public: Posa(char * T=NULL, int nRodes=0); TornaTipus(char *T); int TornaRodes(); } |