Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Herencia Interfaces PDF
Herencia Interfaces PDF
Herencia e Interfaces
Herencia
Introducción
En C# cualquier dato es un objeto porque todos los tipos derivan implícitamente de este
tipo, y “heredan“ los métodos y campos definidos en dicha clase. Cada nuevo tipo tiene
todo lo que tiene el tipo object –y puede utilizarlo e incluso redefinirlo- y añade una
serie de campos y métodos.
Cuando, por ejemplo, se está diseñando una interfaz gráfica, sería absurdo tener que
escribir todo el código para cada ventana cuando muchas de ellas son casi iguales y
realizan tareas parecidas. Lo lógico es “aprovechar” ese código que ya está escrito y
probado y cambiar y añadir lo que sea necesario para ir obteniendo nuevas ventanas
particularizadas. Piense, por ejemplo, en un cuadro de diálogo común. Resulta
coherente escribir un código bastante general que sirva para cualquier ventana y
posteriormente modificarlo –que no sea redimensionable, que tenga un título diferente,
etc-, añadiendo características –nuevos botones, etc- o cambiando algunas de ellas.
La herencia proporciona un mecanismo para definir una nueva clase, a partir de otra
que ya existe, modificándola. La nueva clase que se define, se denomina clase derivada
y la clase de la que se “hereda” se llama clase base.
La clase derivada es la misma clase base a la que se añaden nuevos miembros (campos,
métodos, etc) y/o se redefinen alguno de ellos.
La clase base puede ser a su vez, clase derivada de otra. Cuando hay muchas clases
relacionadas entre sí por el mecanismo de la herencia, se habla de jerarquía de clases.
Fundamentos de la herencia
Para indicar que una clase hereda de otra, se utiliza el siguiente formato general:
La clase derivada “hereda” todos los miembros de la clase base, es decir, tiene todos y
cada uno miembros de la clase base y los que el programador desee añadir.
Ejemplo:
using System;
namespace Herencia
{
public class ClaseBase
1/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
{
public int a;
public int b;
public void Imprimir_ab()
{
Console.WriteLine("a={0},b={1}",a,b);
}
}
class HerenciaApp
{
static void Main(string[] args)
{
//Se crean objetos de las clases base y derivada
ClaseBase claseBase=new ClaseBase();
ClaseDerivada claseDerivada=new ClaseDerivada();
a=11, b=12
a=25, b=26
c=27
Suma=78
2/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
En este ejemplo se observa que la ClaseDerivada tiene como miembros todos los
miembros que ha definido como propios y todos los miembros que tiene la clase de la
que deriva.
Campos: a, b y c
Métodos: Imprimir_ab(), Imprimir_c(), ImprimirSuma()
En este caso, se dice que la clase ClaseDerivada deriva de la clase ClaseBase o que la
clase ClaseBase es una superclase (clase padre) de la ClaseDerivada -(clase hija o
subclase).
La forma de acceso a cada uno de los miembros heredados de la clase derivada, depende
de los modificadores de acceso que cada uno de dichos miembros tenga en la clase base.
En el primer ejemplo se ha considerado que todos los miembros fueran públicos para
explicar directamente la herencia. En general, esto no es una buena práctica de
programación. Los datos de una clase deben estar protegidos. Se ha estudiado con
anterioridad cómo es el acceso a los miembros de una clase, dependiendo de cómo esté
definido cada uno de los miembros –public o private-.
3/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
la que deriva, no puede acceder a aquellos miembros que han sido declarados
como private en la clase base.
c) Un miembro declarado como protected, puede ser llamado desde el interior del
código de la clase derivada pero no desde el exterior de dicha clase, es decir, los
objetos de la clase derivada no pueden acceder a ellos. Un miembro protected
es en realidad un miembro private para cualquier clase excepto para una clase
derivada, que es public, con la excepción antes aludida.
using System;
namespace AccesoConHerencia
{
public class Base
{
private int xPri;
public int yPub;
protected int zPro;
unaClaseBase.yPub=3;
4/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
unaClaseDerivada.yPub=13;
unaClaseBase.Imprimir();
unaClaseDerivada.Imprimir();
unaClaseDerivada.Suma();
}
}
Sobrescritura
En C#, el programador debe indicar qué métodos de una clase pueden ser sobrescritos y
cuáles no. Para ello lo debe indicar por medio del modificador virtual. En la clase
derivada se debe preceder el nombre del método del modificador override.
La palabra reservada base permite utilizar los métodos de la clase base que están
sobrescritos en la clase derivada.
using System;
namespace ConsoleApplication1
{
5/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
claseBase.a=11;
claseBase.b=12;
claseBase.Imprimir();
claseDerivada.a=25;
claseDerivada.b=26;
claseDerivada.c=27;
claseDerivada.Imprimir();
}
}
}
a=11, b=12
a=25, b=26, c=27
6/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
Para invocar un método de la clase base que está sobrescrito en la clase derivada se
utiliza la referencia base.
Por ejemplo, si desde la clase base se desea llamar al método Imprimir() de la clase
base se invoca de la siguiente forma:
base.Imprimir().
El mismo código del ejemplo anterior daría una salida del programa ligeramente
diferente:
a=11, b=12
a=25, b=26
c=27
Constructores y herencia
using System;
namespace Herencia
{
public class ClaseBase
{
int x,y;
public ClaseBase()
{
Console.WriteLine("Constructor de la clase base");
}
7/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
}
public class ClaseDerivada : ClaseBase
{
int z;
public ClaseDerivada()
{
Console.WriteLine("Constructor de la clase derivada");
}
}
public class Aplicacion
{
static void Main(string[] args)
{
ClaseDerivada d=new ClaseDerivada();
}
}
}
base es muy parecido a this. La diferencia más importante es que la segunda se refiere
siempre al propio objeto, y base hace referencia a la superclase, a la clase de la que
deriva la clase actual, a la clase padre. base puede utilizarse de dos formas:
using System;
namespace TemasMatematicos
{
public class Circulo
{
public const double PI=3.141592;
protected double radio;
public Circulo(double radio)
{
this.radio=radio;
8/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
}
public virtual double Area()
{
return PI*radio*radio;
}
}
public class Cilindro : Circulo
{
double altura;
public Cilindro(double radio,double altura):base(radio)
{
this.altura=altura;
}
public override double Area()
{
return PI*radio*radio*altura;
}
}
class Aplicacion
{
static void Main(string[] args)
{
Cilindro c=new Cilindro(1,2);
Console.WriteLine("Area={0}",c.Area());
}
}
}
Area=6.283184
9/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
B) Para invocar un método de la clase base desde la clase derivada –se utiliza
cuando dicho método está sobrecargado-.
base.Area().
En ese mismo bloque de código –es decir, en la clase derivada- para referirse al método
Area() de la clase Cilindro, se puede hacer de dos formas:
Area()
o bien
this.Area()
Por ejemplo,
base.HacerAlgo();
se refiere al método de la clase base, que tendrá el mismo nombre que en la clase
derivada.
Polimorfismo de referencias
Se puede asignar a una referencia de una superclase una referencia de una subclase. Esta
es una característica muy útil y tremendamente potente de C#, que también se encuentra
en C++ y en Java, aunque con diferencias sustanciales.
10/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
namespace Polimorfismo
{
public class Caja
{
protected double x;
protected double y;
protected double z;
double volumen;
volumen=refCaja.Volumen();
Console.WriteLine("Vol={0}",volumen);
volumen=refCaja.Volumen();
Console.WriteLine("Vol={0}",volumen);
//Console.WriteLine("Peso={0}", refCaja.Peso);
}
}
}
11/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
Vol=60
Es muy importante entender bien que el que determina qué miembros son accesibles y
cuáles no es el tipo de variable de referencia ni el tipo de objeto al que se refiere.
Cuando una referencia a un objeto de una subclase se asigna a una referencia de la
superclase, sólo se tiene acceso a aquéllas partes del objeto definidas en la superclase
(figura 6.1).
En este caso, refCaja es una referencia de tipo Caja a un objeto de tipo CajaConPeso.
refCaja
x x
y y
refCajaCoPeso
z z
Volumen() Volumen()
Peso
Objeto tipo Caja
Objeto tipo CajaConPeso
Figura 6.1: La referencia refCaja sólo puede invocar los miembros de la clase
derivada que conoce, que son los que tiene en la superclase.
12/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
por ejemplo: suponga que se desea definir un método que puede admitir como
parámetro cualquier tipo de dato. Dicho método podría tener la siguiente forma:
13/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
Interfaces.
Una interface es similar a una clase o a una estructura, pero sus miembros son
abstractos, es decir, no están definidos, no tienen código. Declara modos de
comportamiento, pero deja su definición para las clases que la implementen.
Cuando una clase implementa una interface, debe implementar todos los métodos de
la interface.
Hay una gran diferencia entre heredar de una clase abstracta e implementar una
interface. Por ejemplo: un Coche es un vehículo –hereda las características y
comportamiento de un vehículo-, pero puede tener la capacidad de
PoderRegularLaTemperatura (como una casa, por ejemplo). Cuando se hereda, se
hace referencia a lo que se es, y cuando se implementa una interface se hace
referencia a la capacidad de “comportarse” de una determinada manera.
En este capítulo se estudia cómo crear, implementar y usar las interfaces. Además, se
tratará cómo implementar múltiples interfaces.
Los atributos se tratarán más adelante. Por ahora es suficiente con decir que los
atributos en C# contienen información sobre el tipo de dato y puede ser consultada
mediante reflexión. Los atributos son opcionales.
Los modificadores de acceso –opcionales- pueden ser los mismos que los de las clases y
con el mismo efecto, a excepción de abstract y sealed, que no tienen sentido para
una interface, es decir: new, public, protected, internal y private.
14/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
Por ejemplo:
Suponga que desea crear una interface que defina la capacidad de “ser imprimible” que
se llame IImprimible y que tenga un método que se llame Imprimir()
La definición sería:
interface IImprimible
{
void Imprimir();
}
Por ejemplo, se puede crear una clase Documento. Para indicar que el tipo Documento se
“puede imprimir” basta con que implemente la interface IImprimible. Implementar
una interfce no es más que escribir código en los métodos definidos en la interface.
La sintaxis es la misma que si derivara de la interface, aunque, como se ha dicho, es
necesario implementar todos los métodos de la interface. Por ejemplo:
class MiAplicacion
{
static void Main(string[] args)
{
Documento unDocumento=new Documento("Contenido 1");
unDocumento.Imprimir();
}
}
Contenido 1
15/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
Suponga que se desea crear otra interface que defina el comportamiento necesario
para guardar y leer desde una fuente de datos –una base de datos, o el disco duro, ...-. Se
le llamará, por ejemplo, IArchivable. Esta interface podría tener dos métodos:
Leer() y Escribir().
interface IArchivable
{
void Leer();
void Escribir()
}
Para indicar que la clase Documento tiene la capacidad de ser almacenado en el disco
duro, basta con que implemente la interface IArchivable e IImprimible.
public class Documento: IImprimible, IArchivable
{
void Leer()
{
//Código que implementa el método
}
void Escribir()
{
//Código que implementa el método
}
public void Imprimir()
{
//Código que implementa el método
}
//Otros miembros y código propio de la clase Documento
}
Todos los miembros de una interface son públicos –por defecto- para que puedan ser
implementados por otras clase. Por esta razón no llevan ningún modificador.
interface IArchivable
{
void Leer();
void Escribir();
}
16/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
}
}
Polimorfismo de referencias
17/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
No es posible crear objetos de tipo interface. Esto es lógico si pensamos que sus
métodos están declarados, pero no definidos. No tendría sentido un objeto sin métodos
implementados.
Sin embargo, puede crearse una referencia de tipo interface para que apunte a
cualquier objeto de un tipo que implemente dicha interface. Por ejemplo:
IImprimible refInterface;
Documento unDocumento=new Documento(“texto del documento”);
refInterface = (IImprimible)unDocumento;
Para ilustrar esta idea, piense en la aplicación anterior con el siguiente código en el
método Main():
o bien:
IImprimible refInterfaceImprimible;
refInterfaceImprimible=new Documento("Una frase");
refInterfaceImprimible.Imprimir();
18/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
refInterfaceImprimible.Imprimir();
refInterfaceImprimible=rect;
refInterfaceImprimible.Imprimir();
o bien:
IImprimible refInterfaceImprimible;
refInterfaceImprimible=new Documento("Una frase");
refInterfaceImprimible.Imprimir();
refInterfaceImprimible=new Rectangulo(12,10);
refInterfaceImprimible.Imprimir();
Miembros de interface.
Los miembros de una interface son:
Una interface puede declarar cero o más miembros, los cuales tienen acceso public
por defecto. Por lo tanto, los miembros de una interface no pueden ser declarados con
los modificadores abstract, public, protected, internal, private, virtual,
override, o static.
Herencia de interfaces.
Una interface puede heredar cero o más interfaces de modo explícito (herencia
múltiple de interfaces). A tales interfaces se les llama “interfaces base explícitas”. No
obstante, una interface no sólo hereda las interface que explícitamente indica, sino
también aquéllas heredadas implícitamente, es decir, aquéllas que han heredado las
interface de las que hereda.
Por ejemplo:
interface IControl
{
void Paint();
}
// ITextBox hereda de IControl
interface ITextBox: IControl
{
void SetText(string text);
}
19/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
Ejemplo:
interface IControl
{
void Paint();
}
interface ITextBox: IControl
{
void SetText(string text);
}
class TextBox: ITextBox
{
public void Paint() {...}
public void SetText(string texto) {…}
}
En este caso la clase TextBox no sólo implementa ITextBox, sino también IControl.
objeto is tipo
Por ejemplo:
Pero el uso de is es ineficaz porque puede generar excepciones. Una solución mejor es
utilizar el operador as.
20/21
Marco Besteiro y Miguel Rodríguez Herencia e Interfaces
objeto as tipo
Por ejemplo:
21/21