Ajedrez, un programa de ejemplo
Para
explicar la herencia, vamos a crear un nuevo programa que juegue al ajedrez,
para ello crearemos una clase base llamada CPieza con los atributos comunes a
todas las piezas y de ella derivarán las clases hijas CTorre, CCaballo,
CAlfil, CDama, CRey y CPeon que incluirán la sobrecarga del método mover()
específica de cada tipo de pieza.
Cada
pieza incluye los siguientes atributos comunes: Nombre, Color, un atributo
booleano que indique si la pieza está en Juego y por último otro atributo que
contenga su posición en el tablero.
      Private m_nombre as string
      Private m_color
as boolean
      Private m_enjuego
as boolean
      Private m_posicion
as string
Utilizando la herencia, se puede crear una
nueva clase de añadiendo o modificando
una clase existente. En este documento,
vamos a crear una primera clase, CPieza, y a
continuación, utilizaremos  la herencia para crear clases
especializadas como CTorre, CCaballo, CAlfil etc. La herencia no se limita a las clases que se creen; se puede heredar de muchas de las clases
de Microsoft. NET.
El código de
cliente creará un array de objetos, con la generación de todas las piezas del
tablero, asignando a cada una de ellas sus atributos correspondientes, luego al
jugar, se llamará a los diferentes métodos mover, que irán modificando los
atributos de cada pieza en función del transcurso de la partida.
Esquema teórico
Para
evitar errores y escribir programas potentes, se recomienda utilizar la
herencia y tener en cuenta las siguientes consideraciones de diseño. 
Herencia
La
relación tiene-un (clase),  es-un
(objeto) es fundamental en el diseño orientado a objetos. Se crean clases que
contienen instancias de otras clases. Estos diseños de modelo tienen una
relación entre un objeto y sus propiedades (un formulario tiene-un botón)  permiten
crear una aplicación mediante la combinación de los objetos ya existentes. 
La
herencia es el método de programación utilizado para implementar la relación es-un  de  los objetos.
Una caja de texto es un control, un coche es un vehículo, un alfil es una pieza
de ajedrez. Si ya se ha escrito el código para el modelo propietario de una pieza
de ajedrez, CPieza, nos gustaría poder ser capaces de utilizar ese código para todas
las piezas del tablero.
La
herencia consiste en la creación de nuevas clases derivadas o hijas a partir de
clases existentes. A la clase padre también se le puede llamar clase base.
También se puede hablar de superclase, clase y subclase, pero la terminología
clase base y clase derivada es más adecuada para la programación con Visual
Basic.
La relación es-un
Tener en
cuenta que la clase derivada que creemos necesite realmente derivarse de la
clase base elegida. Es decir que el objeto creado sea realmente un objeto
especial derivado del objeto base. Una forma de saberlo es hacerse la pregunta es-un. 
¿Una torre es-una pieza de
ajedrez? Si tratamos de eliminar propiedades o métodos de una clase base, debe
advertirnos de si realmente el objeto creado debe derivar de la clase base
elegida. Por ejemplo si estamos tratando de eliminar el evento mover de la
clase pieza para alojar el tablero, es evidente que lo estamos haciendo mal. El
tablero NO es-una pieza.
Polimorfismo
Una pieza de ajedrez es un único tipo de pieza de ajedrez CPieza. Pero hay piezas que son peones, torres, alfiles, etc aunque derivan todas de pieza de ajedrez. A esto se llama comportamiento polimórfico y permite a los desarrolladores utilizar una variable Pieza para referirse a cualquiera de las clases derivadas de una pieza de ajedrez. El Polimorfismo describe el comportamiento de las clases que se derivan de una clase base común, También permite que cada clase derivada maneje un método con idéntico nombre pero con un comportamiento diferente. Por ejemplo, el método mover estará presente en cada clase derivada, CPeon, CReina, CCaballo, etc pero será diferente para cada una de ellas.
Aquí nos
centraremos en los mecanismos de la herencia. Se pueden desarrollar resultados
sofisticados heredando de clases de. NET. Incluso con implementaciones sencillas.
Debemos
hacer un estudio de nuestras clases para ver si realmente necesitamos utilizar la
herencia. O al contrario, si tenemos muchas clases inconexas debemos
preguntarnos si algunas se pueden derivar de otras. También es posible que la
clase sólo necesite contener una instancia de la clase en lugar de servir como
clase base.
Comprobación de tipos
En
general, controlar el  tipo (utilizando
el operador type) es un indicio de que se está utilizando la herencia de forma
incorrecta. Determinar si se están definiendo correctamente las propiedades y
métodos para que la comprobación de tipos no sea necesaria. 
Seleccionar o cambiar los estados
Si el código
contiene muchos selects o switchs, hay que considerar si el uso de la herencia
podría  simplificar el código. 
CPieza: Un ejemplo sencillo
En este
ejemplo crearemos una clase base llamada CPieza con los
atributos genéricos de una pieza de ajedrez, como su color o su posición, y
luego se derivarán varias clases CCaballo, CTorre etc, (Recordar que son derivadas por que un
caballo es una pieza de ajedrez, una torre es una pieza de
ajedrez, etc.) que además incluirán el comportamiento específico de cada tipo
de pieza. En estas clases irá el método Mover() que será
específico para cada clase de pieza.
Descripción de los Miembros
 m_nombre as string
Propiedad de sólo lectura que identifica la pieza por su nombre.
TD  torre de la dama PTD Peón de torre de
la dama, etc.
m_color as
boolean
Propiedad de sólo lectura que identifica el color de la pieza  (True = blanca, False = Negra).
Posicion as string
Propiedad que identifica mediante unas coordenadas la posición de
cada pieza sobre el tablero.  (Ver
esquema de la izquierda)
EnJuego as bolean
Propiedad que identifica si la pieza está en juego (True) o ha
sido eliminada (False).
Public Function Mover(Byval Posicion as string) as
boolean
Método que será definido en las clases hijas para definir como se
mueve cada pieza, pasando como parámetro la casilla de destino este devolverá true si la
posición es correcta y false si es prohibida.
Crear la clase base CPieza
Public Class CPieza
    Private m_nombre As String
    Private m_color As Boolean
    Private m_posicion
As String
    Private m_enjuego
As Boolean
    Public ReadOnly Property Nombre() As String
        Get
            Return m_nombre
        End Get
    End Property
    Public ReadOnly Property Color() As String
        Get
            Return m_color
        End Get
    End Property
    Public Property
Posicion() As String
        Get
            Return m_posicion
        End Get
        Set(ByVal value As String)
           
m_posicion = value
        End Set
   End Property
    'True si la pieza
está en juego, False si la pieza ha sido     
capturada
    Public Property
EnJuego() As Boolean
        Get
            Return m_enjuego
        End Get
        Set(ByVal value As Boolean)
           
m_enjuego = value
        End Set
    End Property
   
‘Constructor 
    Public Sub New()
        m_nombre
= "TD" 'torre
Dama
        m_color =
True
       
m_posicion = "A1"
        m_enjuego
= True
    End Sub
End Class
Creando la clase derivada CTorre
La primera clase derivada se crea será
la clase CTorre. En este ejemplo CTorre es idéntica a la clase CPieza, excepto en el
método Mover que es
específico para la torre.
Public Class CTorre
    Inherits
CPieza
End Class
Examinar el entorno de desarrollo
Si pulsamos el botón para ver el diagrama de clases.
Podemos ver un esquema de las clases creadas
También podemos consultar el visor  de clases
Crear campos de clase usando la palabra clave Protected
Saltar el
seguro de protección private.
Para que la clase hija pueda acceder a los campos de la clase
padre pero estos sigan siendo privados para el código cliente, se usa la
palabra clave protected.
Public Class CPieza
    Protected m_color As Boolean
Ahora en el Class View aparece con una llave. 
Crear métodos y propiedades sobrecargados, Overridable
Sobreescritura de miembros, para ello
se  hace esto en la clase base.
'Método padre vacio, se definirá en cada clase hija
Public Overridable Function Mover(ByVal
NuevaPos As String)
As Boolean
        Me.Posicion = NuevaPos
        Return True
End Function
Esta propiedad o método podrá ser sobreescrito en
las clases derivadas.
Crear métodos y propiedades sobrecargados Overrides
Para indicarlo en la clase derivada lo marco con la palabra clave Overrides.
'Dada una torre se le indica moverse desde su posición actual a otra
posición.
'True si la nueva posisión es correcta, False si es prohibida
Public Overrides Function Mover(ByVal
NuevaPos As String)
As Boolean
      Dim PosActual As String
      Dim ColActual As String
      Dim FilActual As String
      Dim NuevaCol As String
      Dim NuevaFil As String
        PosActual = Me.Posicion
        ColActual = Mid(PosActual, 1, 1)
        FilActual = Mid(PosActual, 2, 1)
        NuevaCol = Mid(NuevaPos, 1, 1)
        NuevaFil = Mid(NuevaPos, 2, 1)
        If
ColActual = NuevaCol Then
            'si se
mueve por la misma columna, no importa el valor de la fila, es movimiento
correcto
            Me.Posicion =
NuevaPos
            Return True
        Else
            If FilActual = NuevaFil Then
                'Si se mueve por la misma fila, no importa el valor de la columna, es
movimiento correcto
                Me.Posicion
= NuevaPos
                Return
True
            Else
                'En
cualquier otro caso es movimiento prohibido
                Me.Posicion =
PosActual
                Return False
            End If
        End If
       'En cualquier otro caso
        Me.Posicion =
PosActual
        Return false
End Function
También
se permite el uso de la palabra NotOverridable para marcar explícitamente
un miembro como no reemplazable. (Este es el comportamiento predeterminado)
-
No podrá cambiar el atributo ReadOnly ni WriteOnly si se quiere sobrescribir una
propiedad en una clase derivada.
-
No se pueden sobrescribir campos, constantes ni miembros compartidos definidos
en la clase base.
-
De forma predeterminada los métodos que estén marcados como Overrides en las clases
derivadas son reemplazables (Overridable) en las siguientes clases derivadas, por lo
que nunca utilizará simultáneamente las palabras Overrides y Overridable.
-
Solo se podrá utilizar la palabra NotOverridable en conjunto con la
palabra Overrides
para declarar un método como No reemplazable.
- No necesitará introducir la palabra Overrides en la
clase derivada ni la palabra Overridable en la clase base si está
agregando un miembro con el mismo nombre en la clase derivada (Aunque note un
mensaje de advertencia).
Además de que no es obligatoria la palabra  Overloads en el miembro de la clase
derivada.
A esto se le conoce con el nombre de ‘Sombreado de Miembros’
(Shadows) y podemos indicarle al compilador que interprete estas advertencias
como errores o que simplemente las ignore. (Ver propiedades del proyecto).
Usar la palabra clave MyBase
Esta
palabra resulta útil cuando desea hacer referencia a un campo, propiedad o
método de la
Clase
base. Si no ha reemplazado a algún miembro en la clase derivada la expresión Me.miembro y MyBase.miembro harán referencia al
mismo miembro y ejecutarán el mismo código, sin embargo cuando en la clase
derivada se ha redefinido el Miembro, se tendrá que usar la palabra Mybase si se quiere hacer
referencia al miembro de la clase base.
Si en la clase derivada necesito llamar al método
sobrecargado de la clase padre utilizo MyBase para evitar sobrecargar la pila.
Public Overrides Property Color() As String
        mybase.Color()
End Property
Usar la palabra clave Me
Si es
necesario referirse a un propiedad, campo o función de la propia clase o de una
clase padre, se puede poner me para referirnos a un
objeto de esta clase.
Public Class CPieza
Private m_posicion As String
Public Property Posicion() As String
      Get
            Return
m_posicion
      End Get
      Set(ByVal value As String)
            m_posicion = value
      End Set
End Property
Public Function Mover(ByVal NuevaPos As String) As Boolean
        Dim PosActual As String
        PosActual = Me.Posicion
End Function
End
Class
Añadir el constructor
Los constructores no se heredan,
por lo que se debe agregar a la clase derivada. Además, cada vez que se define
un constructor hay que incluir una llamada implícita al constructor sin
parámetros que pertenece a la clase base. 
Public Class CPieza
    Public Sub New()
        Dim
posicion As New
CTablero
        m_color = True
        posicion.Columnas(1) = 1
        posicion.Filas(1) = 1
        m_posicion = posicion
        m_enjuego = True
    End Sub
End Class
Public Class CTorre
    Inherits CPieza
    Private Sub New()
        MyBase.New()
    End Sub
End Class
Public Class CCaballo
    Inherits CPieza
    Private Sub New()
        MyBase.New()
    End Sub
End Class
Herencia en un control: La Clase CBotonEliptico
Gracias a
la herencia, es posible derivar clases de nuestras propias clases pero también
de las  clases base suministradas por
.NET.  A Continuación crearemos una clase
llamada CBotonEliptico que derive de la clase base System.Windows.Forms.Button
en este caso sólo será necesario reemplazar el método OnPaint de la clase Button.
Creamos
la clase CBotonEliptico, para crear una clase derivada de una clase. NET, se declara la clase
e indicamos la clase base.
Añadir la clase CBotonEliptico
Public Class CBotonEliptico
    Inherits Button
End Class
Sobreescribiendo el Método OnPaint
El método OnPaint se llama cada vez que
se dibuja el control en el
formulario. La clase base dibuja
el rectángulo familiar. Reemplazando
el método OnPaint, se puede determinar el aspecto del botón.
Protected Overrides Sub OnPaint(ByVal
pevent As System.Windows.Forms.PaintEventArgs)
      Me.Size = New
Size(50, 70)
      Dim bEliptico
As System.Drawing.Drawing2D.GraphicsPath = New           System.Drawing.Drawing2D.GraphicsPath()
      bEliptico.AddEllipse(New System.Drawing.RectangleF(0, 0, 50,70))
      Me.Region = New
Region(bEliptico)
End Sub
Agregar el siguiente código para dibujar
el botón elíptico. Además de elíptico, el área clickable
del botón también deber ser elíptica.
Para hacer un control que asuma una forma particular, en este caso elíptico, debe
definir su propiedad Región para que se logre esa forma. Se puede crear la forma, utilizando el objeto GraphicsPath. El objeto GraphicsPath permite crear un dibujo. En este ejemplo, se crea un dibujo mediante la adición de un círculo de GraphicsPath. El tamaño del botón está limitado a 50 por 70 píxeles de modo que se ve una elipse y rellena.
definir su propiedad Región para que se logre esa forma. Se puede crear la forma, utilizando el objeto GraphicsPath. El objeto GraphicsPath permite crear un dibujo. En este ejemplo, se crea un dibujo mediante la adición de un círculo de GraphicsPath. El tamaño del botón está limitado a 50 por 70 píxeles de modo que se ve una elipse y rellena.
Uso de la Clase 
La clase CBotonEliptico se ha definido en el
archivo de origen y no aparece en
la 
caja de herramientas para el arrastre en el formulario. Para agregar una instancia CBotonEliptico al Form1, se pueden utilizar los mismos métodos que se utilizaron para crear botones en el anterior documento.
caja de herramientas para el arrastre en el formulario. Para agregar una instancia CBotonEliptico al Form1, se pueden utilizar los mismos métodos que se utilizaron para crear botones en el anterior documento.
Añadir el Botón Elíptico al formulario
Private Sub BotonEliptico_Click(ByVal sender As
System.Object, ByVal e As
System.EventArgs)
       
MessageBox.Show("Hola")
End Sub
En el Form_Load
del formulario creamos el objeto
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles
Me.Load
      Dim rb As New CBotonEliptico()
      Me.Controls.Add(rb)
      AddHandler (rb.Click), AddressOf
BotonEliptico_Click
End Sub
Ejecutando la aplicación tenemos
Y si
pulsamos sobre el área negra aparece.
















