You are on page 1of 8

Herència i Polimorfisme

A la lliçó anterior, varem veure els objectes, i una forma de relació entre objectes
anomenada composició. Aquesta relació es defineix pensant per exemple en que
l’objecte casa té una taulada, i per tant hi ha una relació de composició entre els objectes
casa i taulada ( que es un objecte de la classe Triangle). La pregunta que responen és si
un objecte té un altre objecte.

En POO hi ha un altre tipus de relació que es diu d’herència. Per exemple, rectangle,
quadrat, triangle, son figures geomètriques. Per tant podem pensar en la classe figura
com la classe mare de totes les demes classes. Aleshores, les classes quadrat, rectangle,
triangle són filles de la classe mare Figura. Pel fet de ser filles, hereten les seves
propietats, mètodes i atributs, i poden accedir a ells a través de les propietats heretades.
La idea darrera d’això és que la classe mare contingui tots els atributs comuns a les
classes filles, mentre que les classes filles, tinguin els atributs específics de cada classe,
això es coneix com especialització, les classes filles són especialitzacions de la classe
mare.

Nosaltres podem definir mètodes a la classe mare, i després re definir-los a les classes
filles, per exemple en la classe Figura podem tenir un mètode Mostrar. Aquest mètode
no sap quina figura ha de dibuixar, per tant el deixem en blanc. Ara bé , a les classes
filles, Triangle, Rectangle, quadrat, podem re definir aquest mètode de manera que com
ja sabem quina figura s’ha de mostrar, podem posar el codi. Aquest procés se’n diu
Sobre escriptura del mètode ( Overriding). El mètode Mostrar de la classe mare (
Figura en aquest cas) es declara virtual, i a les classes filles ( Triangle, Rectangle,
Quadrat), el mètode Mostrar es declara override

En C#, totes les classes que fem i les del propi C#, hereten
d’una última classe, la classe Object que és la classe
mare de totes les classes. Aquesta classe té uns quants
mètodes virtual, i per tant els podem fer servir per
adaptar-los a la nostra classe particular.
El mètode més habitual per sobreescriure és el mètode ToString () que és una funció
que ens retorna una representació en forma de cadena del objecte. Per exemple en la
classe Persona amb atributs nom i DNI, el mètode ToString ens retornaria la cadena
formada pel nom i el DNI amb el format adient, per exemple

public override string ToString()


{
string cad = "";
cad = string.Format("{0} {1,9}", nom, DNI);
return cad;

}
Una cosa a tenir present, és que en els constructors d’una classe derivada ( que hereta)
d’una classe base, la primera cosa que ha de cridar el constructor de la classe base a
través de base() Això és lògic, ja que al crear una classe filla( quan es crida el seu
constructor) primer s’han de crear les parts comunes ( que formen la classe mare) i
després les parts especifiques de cada classe.

Farem un exemple, semblant al de la casa, ara però, pensarem en l’objecte figura, com
classe mare de les classes, rectangle,i triangle. Les dos classes filles, tenen dos atributs
comuns, l’altura, i el color que ferm servir per dibuixar-les. Per tant, podem pensar que
la classe figura, tindrà dos atributs _altura i _color. A més, volem que totes les classes
filles es puguin mostrar ( dibuixar) per això declarem un mètode virtual void
Mostrar() que tindrà codi per posar el color de lletra al que haguem triat. A les
classes filles, (Rectangle, Triangle) aquest mètode tindrà el codi adient per mostrar un
rectangle o un triangle).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace figures
{
// figura es la classe base, que conté la informacio comuna
a rectangle i triangle
public class Figura
{
private int _altura;// altura i color son atributs
comuns tant a rectangle com a triangle
private ConsoleColor _color;
public int Altura // propietat Altura
{
set { _altura = value; }
get { return _altura; }
}
public ConsoleColor Color // propietat Color
{
get { return _color; }
set { _color = value; }
}
public Figura() // constructor per defecte
{
this.Altura= 1;
this.Color = ConsoleColor.Red;
}
public Figura(int xalt) // constructor amb un argument,
el color per defecte es vermell
{
this.Altura = xalt;
this.Color = ConsoleColor.Red;
}
public Figura(int xalt, ConsoleColor xcolor) //
constructor amb 2 arguments
{
this.Altura = xalt;
this.Color = xcolor;

}
public virtual void mostrar()
{
// aquest metode nomes fa la feina comuna ( posa el
color de lletra
// al color triat), despres, quan estiguem a
Triangle
// el metode Mostrar de triangle fara la feina
especifica
Console.ForegroundColor = this.Color;
}
}
}

Ara hem de construir les classes filles, triangle, i rectangle, que han d’heretar de la
classe mare, això ho fem posant DOS PUNTS I EL NOM DE LA CLASSE MARE, en
aquest cas Figura

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace figures
{// aqui indiquem que Triangle es filla de Figura ( els :
indican això)

public class Triangle:Figura


{
public Triangle():base(1)
{
// base(1) crida el constructor de la classe mare
Figura amb el valor 1
// per defecte crea un triangle amb Altura=1 i
color=Vermell
}
public Triangle(int xalt):base(xalt)
{
// base(xalt) crida el constructor de la classe mare
Figura amb el valor xalt
// que rep el constructor de Triangle
// crea un triangle amb Altura=xalt i color=Vermell
}
public Triangle(int xalt, ConsoleColor xcolor)
: base(xalt, xcolor)
{
// base(xalt,xcolor) crida el constructor de la
classe mare Figura amb
//els valors xalt xcolor
// que rep el constructor de Triangle
// crea un triangle amb Altura=xalt i color=xcolor
}
public override void mostrar()
{// ara podem definir mostrar ja que sabem que tindrem
un triangle
//
int f, c;
// guardem el color inicial
ConsoleColor colorAntic = Console.ForegroundColor;
base.mostrar();// cridem el metode mostrar de la
classe mare per tal
// que ens posi el color de lletra
for (f = 1; f <= this.Altura; f++)

{
for (c = 1; c <= this.Altura - f; c++)
Console.Write(" ");
// canviem de color per pintar els asteriscs
for (c = 1; c <= 2 * f - 1; c++)
Console.Write("*");
Console.WriteLine();// saltem de linea
}
// tornem a posar el color Antic
Console.ForegroundColor = colorAntic;
}

}
}

Aquí veiem que els constructors, ( hi hem posat 3) tres criden a base() amb un valor, o
dos valors, això es fa per crear a través de base() la part comuna, i després afegir la part
específica ( en el cas del triangle no hi ha)

També fixeu-vos a la declaració del mètode Mostrar: public override void


mostrar() aquest mètode indica que està sobreescrivint ( reemplaçant) el mètode
mostrar de la classe Base (Figura). El que fem es primer cridar el mètode
base.mostrar() que posa el color de lletra i després posar el codi que dibuixa el
triangle.

Igualment podem crear la classe Rectangle.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace figures
{/* la classe Rectangle hereda de figura, per tant
* tindra una altura, i un color, només afegim
* un nou atribut, labase (per no confondre amb base que es una
paraula reservada
* del C# per referir-se a la classe mare)
*/
public class Rectangle:Figura
{
private int _labase;// atribut nou, per indicar quan
mesura la base del rectangle
public int LaBase // propietat
{
get { return _labase; }
set { _labase = value; }
}
public Rectangle():base(1,ConsoleColor.Red)
{
// base crea la part comuna, altura i color
this.LaBase = 1; // nomes ens cal posar el valor de
la base

}
public Rectangle(int xb, int
xa):base(xa,ConsoleColor.Red)
{
// si cridem aquest constructor tindrem un rectangle
vermell ( per defecte)
// amb base xb i altura xa
this.LaBase = xb;
}

public Rectangle(int xb, int xa, ConsoleColor xcolor)


: base(xa, xcolor)
{
// si cridem aquest constructor, tindrem un
rectangle amb
// amb altura xa, base xb i color xcolor
this.LaBase = xb;// només cal assignar el valor a la
base
}
public override void mostrar()
{// aquest metode substitueix el metode mostrar de la
classe Figura
// ara ja sabem que dibuixem un rectangle
int f, c;
// guardem el color antic
ConsoleColor colorAntic = Console.ForegroundColor;
base.mostrar();// fa la part comuna, posa el color
de lletra
for (f = 1; f <= this.Altura; f++)
{
for (c = 1; c <= this.LaBase; c++)
{// posem els asteriscs
Console.Write("*");
}
Console.WriteLine();
}// retornem al color antic
Console.ForegroundColor = colorAntic;
}
}
}

Ara farem servir les classes que hem creat a un programa però traurem profit del
polimorfisme, ja que crearem un vector de figures i després decidirem quines figures
creem,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace figures
{
class Program
{
static void Main(string[] args)
{

Figura[] f = new Figura[3];// creem un vector de 3


figures
f[0] = new Triangle(3,ConsoleColor.Green);// la
primera un triangle verd de 3 pisos
f[1] = new Rectangle(3, 4,ConsoleColor.Yellow);// la
segona un rectangle 3x4 groc
f[2] = new Rectangle(5, 6,ConsoleColor.Magenta);//
la tercera un rectangle 5x6 magenta
for (int i = 0; i < f.Length; i++)
{// aquest for mostra les figures, per cada una
detecta de
// quina figura es, i crida el mostrar
corresponent!!!
f[i].mostrar();
}
Console.ReadLine();
}
}
}

Aquí, creem un vector f[] de figures, igual que si fos un vector d’integers i després
inicialitzem cada element a una figura diferent, podem mostrar tot en un bucle for, que
recorre el vector f[] mostrant cada element. Això és una aplicació del polimorfisme,
totes les classes filles són figures, per tant si creem f[] com un vector de figures, després
podem decidir ( mentre s’executa el programa) quines són les figures que realment
volem mostrar per fer la casa. Aquest concepte és molt important i fa que els programes
siguin més generals. Si ara volguéssim introduir un nou objecte, per exemple cercle
podríem fer que heretes de la classe figura i amb això ja el podríem incloure al
programa principal, nomes posant el codi del nou objecte

NOTA:Fixeu-vos que en molts llocs hem fet servir this, això és una referència al propi
objecte, per tant si hem de treballar amb dades del propi objecte, farem servir this per
referir-nos amb ell. Per exemple, la classe triangle, quan ha d’accedir a la seva propietat
Altura ho pot fer amb

this.Altura
This és una referència ( un punter en C++) que apunta al propi objecte. De vegades ens
pot ser útil per exemple en el problema de sumar fraccions, trobar la distancia entre dos
punts etc. Imaginem una classe punt amb dos valors enters per la X i per la Y i un
mètode esIgualA que rep com a argument un altre punt. Declarem al programa
principal p1 i p2 com a punts. Si volem saber si p1 es igual a p2 farem

bool res=p1.esIgualA(p2);

a dintre del mètode esIgualA hem de accedir als valors X,Y del primer punt per fer-ho,
cal fer servir this ( que apunta al objecte que crida el mètode, en aquest cas p1)

public bool esIgualA(Punt p2)


{
if ( this.X==p2.X) && ( this.Y==p2.Y) return true;
else return false;
}

You might also like