<?xml version="1.0"  encoding="ISO-8859-1" ?> <!-- encoding="windows-1252" ?> -->
<?xml-stylesheet type="text/xsl" href="../csharp.xsl"?>

<document>
<title>Herencia</title>
<author>Fernando Berzal Galiano &amp; Francisco Cortijo Bon</author>

<navigation>
 <prev>
  <ref>classes.xml</ref>
  <title>Clases</title>
 </prev>
 <next>
   <ref>classes2.xml</ref>
   <title>Clases (2)</title>
 </next>
</navigation>




<!-- Concepto de herencia -->

<document>
<tag>ConceptoHerencia</tag>
<title>Concepto de herencia</title>



<text>
El mecanismo de <b>herencia</b> es uno de los pilares fundamentales 
en los que se basa la programación  orientada a objetos. 
Es un mecanismo que <i>permite definir nuevas clases a partir de 
otras ya definidas</i>. 
Si en la definición de una clase indicamos que ésta deriva de otra, 
entonces la primera -a la que se le suele llamar <b>clase hija</b> o 
<b>clase derivada</b>- será tratada por el compilador automáticamente 
como si su definición incluyese la definición de la segunda 
-a la que se le suele llamar <b>clase padre</b> o <b>clase base</b>. 
</text>

<text>
Las clases que derivan de otras se definen usando la siguiente sintaxis:
</text>
<example>
<code>
<![CDATA[
  class <claseHija> : <clasePadre>
  {
    <miembrosHija>
  }
]]>
</code>
</example>

<text>A los miembros definidos en la clase hija se le 
añadirán los que hubiésemos definido en la clase padre: 
la clase derivada "hereda" de la clase base.</text>

<text>La palabra clave <type>base</type> se utiliza para 
obtener acceso a los miembros de la clase base desde 
una clase derivada. 
</text>

<text>
C# sólo permite herencia simple.
</text>



<!-- Herencia de constructores -->

<document>
<title>Herencia de constructores</title>

<text>
Los objetos de una clase derivada contarán con los mismos 
miembros que los objetos de la clase base y además incorporarán 
nuevos campos y/o métodos. 
El constructor de una clase derivada puede emplear el constructor 
de la clase base para inicializar los campos heredados de la clase 
padre con la construcción <type>base</type>. 
En realidad se trata de una llamada al constructor de la 
clase base con los parámetros adecuados. 
</text>
<example>
<code>
<![CDATA[
	: base(<parametrosBase>)
]]>
</code>
</example>

<text>Si no se incluye el compilador consideraría que vale 
<type>:base()</type>, lo que provocaría un error si la clase base 
carece de constructor sin parámetros.
</text>


<example>
<title>Ejemplo de "herencia" de constructores</title>
<code>
public class B 
{
  private int h; // Campo 

  public B () {   // Constructor sin parámetros
    this.h = -1;
  }		
  public B (int h) // Constructor con parámetro
  {               
    this.h = h; 
  }
  public int H    // Propiedad 
  { 
    get { return h; }
    set { h = value; } 
  }
} // class B

public class D : B  // "D" hereda de "B"
{
  private int i;  // Campo 

  public D () : this(-1) {} // Constructor sin parámetros
  
  public D (int i) {  // Constructor con un parámetro
     this.i = i; 
  }
  public D (int h, int i) : base(h) { // Constructor con 
     this.i = i;                      // dos parámetros
  }
     
  public int I    // Propiedad
  { 
    get { return i; }
    set { i = value; } 
  }

} // class D

  ......
  B varB1 = new B(); // Const. sin parámetros de B
  B varB2 = new B(5); // Const. con 1 parámetro de B
  Console.WriteLine("varB1 : (H={0})", varB1.H);
  Console.WriteLine("varB2 : (H={0})\n", varB2.H);

  D varD1 = new D();       // Const. sin parámetros de D
  D varD2 = new D(15);     // Const. con 1 parámetro de D
  D varD3 = new D(25, 11); // Const. con 2 parámetros de D

  Console.WriteLine("varD1 : (I={0},H={1})", varD1.I, varD1.H);
  Console.WriteLine("varD2 : (I={0},H={1})", varD2.I, varD2.H);
  Console.WriteLine("varD3 : (I={0},H={1})", varD3.I, varD3.H);
  Console.ReadLine();
  ......
</code>
</example>


<image>
<url>image/out-Clases3.gif</url>
</image>


<text>En el siguiente ejemplo se muestra cómo puede extenderse 
la clase <type>CocheSimple</type> vista anteriormente para 
construir, a partir de ella, la clase <type>Taxi</type>. 
Observar como se emplea la construcción <type>base</type> 
para referenciar a un constructor de la clase base y que 
cuando actúa el constructor sin parámetros de la clase 
<type>Taxi</type> se llama implícitamente al constructor sin 
parámetros de la clase <type>CocheSimple</type>. 
</text>


<example>
<title>Ejemplo: herencia sobre la clase <type>CocheSimple</type></title>
<code>
<![CDATA[
using System;

namespace DemoHerencia {

  class CocheSimple 
  {
    private int VelocMax;
    private string Marca;  
    private string Modelo;

    public CocheSimple () {
      this.VelocMax = 0; 
      this.Marca = "??";
      this.Modelo = "??";
    }
    public CocheSimple (string marca, string mod, int velMax) 
    {
      this.VelocMax = velMax; 
      this.Marca = marca;
      this.Modelo = mod;
    }

    public void MuestraCoche () {
      Console.WriteLine (this.Marca + " " + this.Modelo + 
                         "  (" + this.VelocMax + " Km/h)");
    }

  } // class CocheSimple

  class Taxi : CocheSimple

      private string CodLicencia;

      public Taxi () {}
      public Taxi (string marca, string mod, int vel, 
                   string lic) : base (marca, mod, vel) 
      {
        this.CodLicencia = lic;
      }
      public string Licencia {
        get { return this.CodLicencia; }
      }
  } // class Taxi
  
  class DemoHerenciaApp {

    static void Main(string[] args) {
 
       CocheSimple MiCoche = 
          new CocheSimple ("Citröen", "Xsara Picasso", 220);
       CocheSimple TuCoche = 
          new CocheSimple ("Opel", "Corsa", 190);
       CocheSimple UnCoche = new CocheSimple ();

       Console.Write ("Mi coche: "); 
       MiCoche.MuestraCoche(); 
       Console.Write ("El tuyo: ");          
       TuCoche.MuestraCoche(); 
       Console.Write ("Un coche sin identificar: ");          
       UnCoche.MuestraCoche(); 

       Console.WriteLine();

       Taxi ElTaxiDesconocido = new Taxi ();
       Console.Write ("Un taxi sin identificar: ");          
       ElTaxiDesconocido.MuestraCoche(); 

       Taxi NuevoTaxi= new Taxi ("Ford", "KA", 150, "GR1234");
       Console.Write ("Un taxi nuevo: ");          
       NuevoTaxi.MuestraCoche(); 
       Console.Write ("   Licencia: {0}", NuevoTaxi.Licencia); 

       Console.ReadLine ();

     } // Main

  } // class DemoHerenciaApp

} // namespace DemoHerencia
]]>
</code>
</example>


<image>
<url>image/out-Clases4.gif</url>
</image>


</document>  <!-- Herencia de constructores -->




<!-- Redefinición de métodos -->

<document>
<title> Redefinición de métodos</title>

<text>
Siempre que se redefine un método que aparece en la 
clase base, hay que utilizar explícitamente la palabra 
reservada <type>override</type> y, de esta forma, se evitan 
redefiniciones accidentales (una fuente de errores en 
lenguajes como Java o C++).
</text>

<text>Sabemos que todos los objetos (incluidas las variables 
de los tipos predefinidos) derivan, en última instancia, 
de la clase <type>Object</type>. Esta clase proporciona 
el método <type>ToString</type> que <i>crea una cadena de texto 
legible para el usuario que describe una instancia de la 
clase</i>. Si dejamos sin redefinir este método y empleando 
la clase <type>CocheSimple</type> las siguientes instrucciones:
</text>
<example>
<code>
<![CDATA[
   CocheSimple MiCoche  = 
      new CocheSimple ("Citröen", "Xsara Picasso", 220);
      
   Console.WriteLine ("Mi coche: " + MiCoche.ToString()); 
]]>
</code>
</example>   
<text>producen el siguiente resultado: </text>
<example>
<code>
<![CDATA[
   Mi coche: DemoHerencia.CocheSimple
]]>
</code>
</example>   
   
<text>
lo que nos invita a redefinir el método <type>ToString</type> 
en la clase <type>CocheSimple</type>:</text>
<example>
<code>
  class CocheSimple  
  {
    ...
    public override string ToString() 
    {
      return (this.Marca + " " + this.Modelo + 
                  "  (" + this.VelocMax + " Km/h)");
    }
    ...
  }		
</code>	
</example>
<text>
Las dos instrucciones siguientes son equivalentes: 
<example>
<code>
    Console.WriteLine ("Mi coche: " + MiCoche.ToString()); 

    Console.WriteLine ("Mi coche: " + MiCoche); 
</code>	
</example>
</text>

<text>
por lo que podemos sutituir las instrucciones que muestran los 
datos de los objetos <type>CocheSimple</type> por: 
<example>
<code>
    Console.WriteLine ("Mi coche: " + MiCoche); 
    Console.WriteLine ("El tuyo: " + TuCoche); 
    Console.WriteLine ("Un coche sin identificar: " + UnCoche);
</code>	
</example>
</text>

<text>
y eliminamos el (innecesario) método <type>MuestraCoche</type>, 
el resultado de la ejecución del programa anterior es: 
</text>

<image>
<url>image/out-Clases5.gif</url>
</image>


<text>
La palabra reservada <type>base</type> sirve para hacer referencia 
a los miembros de la clase base que quedan ocultos por otros miembros 
de la clase actual. Por ejemplo, podríamos redefinir también el 
método <type>ToString</type> de la clase <type>Taxi</type> 
empleando el método redefinido <type>ToString</type> de la clase 
base <type>CocheSencillo</type>: </text>
<example>
<code>
  class CocheSimple  
  {
    ...
    public override string ToString() 
    {
      return (this.Marca + " " + this.Modelo + 
                  "  (" + this.VelocMax + " Km/h)");
    }
    ...
  }		
  class Taxi : CocheSimple  
  {
    ...
    public override string ToString() 
    {
      return (base.ToString() + "\n   Licencia: " + 
              this.Licencia);
    }
    ...
  }		
  
  ......  
  Taxi ElTaxiDesconocido = new Taxi ();
  Console.WriteLine ("Un taxi sin identificar: " + 
                      ElTaxiDesconocido);          
	
  Taxi NuevoTaxi= new Taxi ("Citröen", "C5", 250, "GR1234");
  Console.WriteLine ("Un taxi nuevo: " + NuevoTaxi);   
  ......    
</code>	
</example>  			
<text>y el resultado es:</text>

<image>
<url>image/out-Clases6.gif</url>
</image>


<!-- Otros ejemplos -->
 
<!--
<document>
<title>Otros ejemplos </title>
-->

<text>En la sección dedicada a la 
<link><url>classes.xml#Sobrecarga</url><text>sobrecarga de 
operadores </text></link>
introdujimos la clase <type>Point</type>. 
No había ningún método que mostrara los datos de 
interés de un objeto de tipo <type>Point</type>. 
Podemos sobreescribir el método <type>ToString</type> 
de manera que fuera:</text>
<example>
<code>
  public class Point  
  {
  ...
    public override string ToString() 
    {
      return ("["+this.X+", "+this.Y+"]");
    }
  ...
  }		
</code>	
</example>
<text>Ahora las instrucciones de escritura se convierten 
en llamadas a este método, por ejemplo: </text>
<example>
<code>
    Console.WriteLine ("p1 es: " + p1); 
    // Console.WriteLine ("p1 es: "  + p1.ToString()	    
</code>	
</example>

<text>El resultado de la ejecución de ese programa será: </text>

<image>
<url>image/out-Over3.gif</url>
</image>

<!--
</document> 
-->
<!-- Otros ejemplos -->


</document>  <!-- Redefinición de métodos -->



<document>
<title>Métodos virtuales</title>

<text>Un método es <b>virtual</b> si puede redefinirse en 
una clase derivada. Los métodos son no virtuales por defecto. 
<list>
<item>Los métodos no virtuales no son polimórficos 
(no pueden reemplazarse) ni pueden ser abstractos.</item> 
<item>Los métodos virtuales se definen en una clase base 
(empleando la palabra reservada <type>virtual</type>) y 
pueden ser reemplazados (empleando la palabra reservada 
<type>override</type>) en las subclases (éstas proporcionan 
su propia -específica- implementación). </item>
<item>Generalmente, contendrán una implementación por defecto 
del método (si no, se deberían utilizar métodos 
<i>abstractos</i>).</item>
</list>
</text>

<example>
<code>
class Shape // Clase base
{
  // "Draw" es un método virtual
  public virtual void Draw() { ... } 
}

class Box : Shape 
{ 
  // Reemplaza al método Draw de la clase base 
  public override void Draw() { ... }
}

class Sphere : Shape 
{ 
  // Reemplaza al método Draw de la clase base 
  public override void Draw() { ... }
}
</code>
</example>

<example>
<code>
void HandleShape(Shape s) 
{
  ...
  s.Draw();  // Polimorfismo 
  ...
}
</code>
</example>

<example>
<code>
HandleShape(new Box());
HandleShape(new Sphere());
HandleShape(new Shape());
</code>
</example>

<text>
NOTA: Propiedades, indexadores y eventos 
también pueden ser virtuales.
</text>

</document> <!-- Métodos virtuales -->


</document> <!-- Concepto de herencia -->


<!-- Clases abstractas -->

<document>
<tag>ClasesAbstractas</tag>
<title>Clases abstractas</title>

<text>
Una <b>clase abstracta</b> es una clase que no puede 
ser instanciada. Se declara empelando la palabra 
reservada <type>abstract</type>. 
</text>

<text>Permiten incluir métodos abstractos y métodos no 
abstractos cuya implementación hace que sirvan de clases 
base (herencia de implementación). Como es lógico, no 
pueden estar "selladas".
</text>


<!-- Métodos abstractos -->

<document>
<title>Métodos abstractos</title>

<text>
Un método abstracto es un método sin implementación que 
debe pertenecer a una clase abstracta. Lógicamente se trata de 
un método virtual forzoso y su implementación se realizará en 
una clase derivada.
</text>


<example>
<code>
abstract class Shape // Clase base abstracta
{
  public abstract void Draw(); // Método abstracto 
}

class Box : Shape 
{ 
  public override void Draw() { ... }
}

class Sphere : Shape 
{ 
  public override void Draw() { ... }
}
</code>
</example>

<example>
<code>
void HandleShape(Shape s) 
{
  ...
  s.Draw();
  ...
}
</code>
</example>

<example>
<code>
HandleShape(new Box());
HandleShape(new Sphere());
HandleShape(new Shape());    // Error !!!
</code>
</example>

</document> <!-- Métodos abstractos -->

</document> <!-- Clases abstractas -->


<!-- Clases selladas -->

<document>
<tag>SealedClasses</tag>
<title>Clases selladas</title>

<text>
Una clase sellada (<type>sealed</type>), es una 
clase de la que no pueden derivarse otras clases 
(esto es, no puede utilizarse como clase base). 
Obviamente, no puede ser una clase abstracta.
</text>

<text>Los <type>struct</type> en C# son 
<i>implícitamente</i> clases selladas.</text>

<text>
¿Para qué sirve sellar clases? Para evitar que se 
puedan crear subclases y optimizar el código 
(ya que las llamadas a las funciones de una clase 
sellada pueden resolverse en tiempo de compilación).
</text>

</document> <!-- Clases selladas-->


<!-- Tipos anidados -->

<document>
<tag>TiposAnidados</tag>
<title>Tipos anidados</title>

<text>
C# permite declarar tipos anidados, esto es, tipos 
definidos en el ámbito de otro tipo. El anidamiento 
nos permite que el tipo anidado pueda acceder a 
todos los miembros del tipo que lo engloba 
(independientemente de los modificadores de 
acceso) y que el tipo esté oculto de cara al 
exterior (salvo que queramos que sea visible, 
en cuyo caso habrá que especificar el nombre del 
tipo que lo engloba para poder acceder a él).
<!-- Unlike Java inner classes, nested types imply 
no relationship between instances -->
</text>

</document> <!-- Tipos anidados -->


<!-- Operadores especiales -->

<document>
<tag>OperadoresEspeciales</tag>
<title>Operadores especiales</title>

<document>
 <title>is</title>
 <text>
 Se utiliza para comprobar dinámicamente si el 
 tipo de un objeto es compatible con un tipo 
 especificado (<type>instanceof</type> en Java). 
 </text>
 
 <text>
 No conviene abusar de este operador (es 
 preferible diseñar correctamente una jerarquía de tipos).
 </text>
 <example>
<code>
static void DoSomething(object o) 
{
  if (o is Car) ((Car)o).Drive();
}
</code>
 </example>
</document>

<document>
 <title>as</title>
 <text>
 Intenta convertir de tipo una variable (al estilo de 
 los casts dinámicos de C++). Si la conversión de tipo 
 no es posible, el resultado es <type>null</type>. 
 Es más eficiente que el operador <type>is</type>, 
 si bien tampoco es conveniente abusar del 
 operador <type>as</type>.
 </text>
 <example>
<code>
static void DoSomething(object o) 
{
  Car c = o as Car;

  if (c != null) c.Drive();
}
</code>
 </example>
</document>

<document>
 <title>typeof</title>
 <text>
 El operador <type>typeof</type> devuelve el 
 objeto derivado de <type>System.Type</type> 
 correspondiente al tipo especificado. 
 De esta forma se puede hacer <i>reflexión</i> para 
 obtener dinámicamente información sobre 
 los tipos (como en Java).
 </text>
 <example>
<code>
...
Console.WriteLine(typeof(int).FullName);
Console.WriteLine(typeof(System.Int).Name);
Console.WriteLine(typeof(float).Module);
Console.WriteLine(typeof(double).IsPublic);
Console.WriteLine(typeof(Point).MemberType);
...
</code>
</example>
  
<image>
<url>image/out-Over4.gif</url>
</image>

</document>

</document>

</document>
