02/10/26 · 7 min de lectura

Herencia en C#

Cómo usar la herencia para reutilizar código y construir una relación sólida entre clases relacionadas.

Imagen por Hanna Lazar .

Los lenguajes de scripting con los que es compatible Unity tienen una característica llamada Herencia. La herencia es uno de los pilares de la Programación Orientada a Objetos o POO.

Cuando una clase hereda de otra gana las características de la clase de la que hereda.

Cuando se habla sobre la herencia, la clase de la que se hereda se llama clase Base o Parent. La clase que hereda se llama la clase derivada o Child.

Parent => child

El resultado de la herencia es que los elementos que existen en la clase Base también estarán disponibles en la clase derivada. Por lo tanto, los métodos y las variables se pueden usar en la clase derivada como si fuera la clase Base.

Por ejemplo, considera que tienen una clase Base llamada Class A, la misma que contiene dos métodos: Dance() y Sing(). Si tienes otra clase, Class B, que hereda de Class A, entonces Class B también tendrá dos métodos: Dance() y Sing(). No es necesario crear esos métodos en Class B porque ya existen en Class A.

// Parent
class A
{
    public void Dance() { /*...*/ }
    public void Sing() { /*...*/ }
}
// Child 
class B : A { /*...*/ }

public class AccessExample : MonoBehaviour
{
    // B puede usar los métodos de A
    var b = new B();
    b.Dance();
    b.Sing()
}

Cuando estamos tratando con asuntos de herencia, hay tres modificadores de acceso que tenemos que conocer: public (público), private (privado) y protected(protegido), ya deberías estar familiarizado con estos conceptos de modificadores de acceso public y private.

Solo ten en cuenta que las herramientas de una clase base que son públicas van a existir y estarán disponibles en la clase derivada, mientras que las herramientas que son privadas existirán, pero no serán accesibles en la clase derivada.

// Parent
class A
{
    public void Dance() { /*...*/ }
    private void Sing() { /*...*/ }
}
// Child 
class B : A { /*...*/ }

public class AccessExample : MonoBehaviour
{
    // B puede usar los métodos de A
    var b = new B();
    b.Dance();
    // no será accesible
    // b.Sing()
}

El modificador de acceso protected actúa como un híbrido entre los public y private. Todas las herramientas de una clase Base que son protegidas existirán y serán accesibles en una clase derivada, como herramientas públicas, pero no podrán ser accedidas fuera de las clases base o derivadas como herramientas privadas.

// Parent
class A
{
    protected void Dance() { /*...*/ }
    protected void Sing() { /*...*/ }
}
// Child 
class B : A
{
    public void DanceAndSing()
    {
        // accesible
        Dance();
        Sing();
    }
}

public class AccessExample : MonoBehaviour
{
    var b = new B();
    // accesible
    b.DanceAndSing();
    // no serán accesibles
    // b.Dance() 
    // b.Sing()
}

Es muy probable que la mayoría de las clases que has usado hasta ahora en Unity han sido heredadas. Ciertamente, todos los scripts que se aplican como componentes para GameObjects son MonoBehaviours. Esto significa que han heredado de la clase MonoBehaviours.

Por defecto, los scripts hechos en Unity siguen este formato: public class seguido del nombre de la clase, seguido de dos puntos y el nombre de la clase: MonoBehaviours.

public class SomeClass : MonoBehaviour
{
    /*...*/
}

Los dos puntos en el nombre de una clase está diciéndole al script que hereda de MonoBehaviour, para hacer que esta clase herede de otra clase, simplemente cambia el nombre MonoBehaviours con el nombre de cualquier otra clase.

Para cambiar la clase de tal manera que no herede de ninguna clase Base, simplemente elimina los dos puntos y el nombre de la clase padre.

public class SomeClass
{
    /*...*/
}

Tal vez te estés preguntando por qué nuestros scripts heredan de MonoBehaviours. Elementos como GameObjects, Transform, el método Start(), el método Update() y más, todos provienen de MonoBehaviours.

Nuestros scripts heredan de MonoBehaviours de tal manera que tengan acceso a esas herramientas. La estructura hereditaria es jerárquica. Una manera muy común de considerar la herencia es compararla con el reino animal.

Es este ejemplo, tenemos una clase Base llamada Animal. Esta clase contiene todas las definiciones y propiedades necesarias para hacer que la clase se comporte como un animal. De esta clase Base Animal podemos tener un par de clases derivadas: Vertebrados e Invertebrados. La clase Vertebrados sería, entonces, por consiguiente la clase Base para más clases, tales como mamíferos, reptiles o anfibios. Cada una de estas clases derivadas toman la información que proveen su clase Base y añadirían más a ella.

img

Al igual que nuestro ejemplo sobre los animales, la herencia en la Programación Orientada a Objetos se conoce como una relación. Esto significa que la clase derivada es una clase Base. Un reptil es un Vertebrados. Un mamífero es un Animal.

Un ejemplo en Unity que tal vez habrás encontrado antes es: Un Capsule Collider (colisionador en forma de cápsula) es un Collider (colisionador). Este concepto se cubrirá más a fondo en Polimorfismo.

La idea de la herencia puede ser muy útil y aplicable en el desarrollo de los videojuegos. Por ejemplo, podemos tener una clase llamada Humanoid. Esta clase cubre todas las cosas que los Humanoides deben hacer en nuestro juego. Tenemos entonces dos clases derivadas: Enemy y Player. Estas controlan los particulares de cómo los jugadores y los enemigos funcionan en el juego mientras que ya se comportan como Humanoides, porque han heredado todos los miembros de la clase Humanoides. Luego podemos tener dos más clases derivadas de Enemy: Orc (orcos) y Globin (duende). Estas ya se comportan como enemigos los mismos que se comportan como Humanoides. De esta manera, tenemos que escribir mucho menos código para hacer que los Orc y los Globin se comporten como quieres que se comporten, porque estamos reusando el código de Humanoides y Enemy.

img

Los constructores son una excepción a lo que las clases derivadas heredan ya que son únicos a la clase y nunca se comparten. Sin embargo; cuando se invoca un constructor en una clase derivada, el constructor de su clase base se invoca justo antes.

Desde que las clases pueden tener muchos tipos diferentes de constructores tal vez querramos poder controlar cuál constructor de la clase Base se invoca. Lo hacemos con la palabra reservada base. Al seguir la lista de parámetros del constructor de la clase derivada con dos puntos puedes invocar explícitamente un constructor específico de la clase base usando la palabra clase base en la lista de parámetros de la clase base.

public class Apple : Fruit
{
    public Apple() : base("apple") { /* constructor code...*/}
}

Si el constructor de la clase base no se invoca explícitamente, entonces el constructor por defecto todavía se llamará implícitamente.

Aparte de invocar el constructor de la clase base, puedes usar la palabra reservada de la clase base para acceder a otros miembros de la clase base. Esto es muy útil en situaciones donde quieras acceder la versión de la clase base de algo, porque es diferente que la versión de la clase derivada. Esto pasa a menudo cuando estamos sobreescribiendo funciones.

public class Fruit
{
    public Fruit(string name) {  /* constructor code...*/ }
    public virtual void Juicy() { /*...*/}
}

public class Apple : Fruit
{
    public Apple() : base("apple")
    {
        /* constructor code...*/
    }

    public virtual void Juicy() override
    {
        /*algún código jugoso */
        base.Juicy(); // acceso a la versión de la clase base
    }
}

Para obtener más información sobre esto, consulta la sección de overriding (sobrescritura) .

Gist del proyecto

Apoya el contenido de mi blog a través de:

Fuente:

Copiado!