5.A Herencia¶
La herencia permite crear una clase nueva a partir de otra ya existente, aprovechando todo lo que esta tiene y añadiendo o cambiando lo que haga falta. Se usa cuando entre dos clases hay una relación «es un»: un perro es un animal; un gato es un animal.
| Término | Significa | Ejemplo |
|---|---|---|
| Superclase (o clase base, o padre) | La clase de la que se hereda | Animal |
| Subclase (o clase derivada, o hija) | La clase que hereda y la especializa | Perro, Gato |
| Sobrescribir (override) | Redefinir un método heredado para que haga otra cosa | Hablar() |
Un ejemplo¶
var animales = new List<Animal> { new Perro("Rex"), new Gato("Misi"), new Animal("Bicho") };
foreach (Animal a in animales)
{
Console.WriteLine(a.Presentarse());
}
foreach (Animal a in animales)
{
if (a is Perro perro)
{
Console.WriteLine(perro.TraerPelota());
}
}
class Animal
{
public string Nombre { get; }
public Animal(string nombre)
{
Nombre = nombre;
}
public virtual string Hablar() => "...";
public virtual string Presentarse() => $"{Nombre} dice: {Hablar()}";
}
class Perro : Animal
{
public Perro(string nombre) : base(nombre) { }
public override string Hablar() => "Guau";
public string TraerPelota() => $"{Nombre} trae la pelota";
}
class Gato : Animal
{
public Gato(string nombre) : base(nombre) { }
public override string Hablar() => "Miau";
public override string Presentarse() => $"{base.Presentarse()} (y se hace el distraído)";
}
Salida:
Rex dice: Guau
Misi dice: Miau (y se hace el distraído)
Bicho dice: ...
Rex trae la pelota
Qué ocurre aquí:
PerroyGatono repiten la propiedadNombreni el métodoPresentarse: los reciben deAnimal.- Cada subclase sobrescribe
Hablar()para dar su propio sonido;Animaltiene una versión genérica (...), yBicho, que es unAnimalnormal, la usa. Gatoademás sobrescribePresentarse()y reutiliza la versión del padre conbase, añadiéndole algo.Perroañade un método queAnimalno tiene (TraerPelota). Para llamarlo hay que comprobar el tipo antes (a is Perro perro, que además convierte la variable), porque la lista contiene animales de todo tipo.- Las tres líneas se imprimen con la misma llamada (
a.Presentarse()), pero el resultado depende de qué objeto concreto hay detrás. Eso se llama polimorfismo y se explica en el siguiente apartado.
Cómo se escribe en C#¶
| Necesito... | En C# |
|---|---|
| Heredar | class Perro : Animal. Las clases se pueden heredar por defecto (para impedirlo, sealed) |
| Constructor del padre | Se llama tras los dos puntos: public Perro(string nombre) : base(nombre). Los constructores no se heredan |
| Sobrescribir un método | El de la base debe ser virtual (o abstract) y el de la hija lleva override (obligatorio). Sin virtual, el método no se puede sobrescribir |
| Llamar a la versión del padre | base.Presentarse() |
| Comprobar el tipo | a is Perro o a is Perro perro (declara la variable ya convertida) |
| Impedir que hereden de ti | sealed class Perro : Animal |
| ¿Cuántos padres? | Uno (herencia simple); se completa con interfaces |
Si olvidas virtual, la hija «oculta» en vez de sobrescribir
Si en la base escribes public string Hablar() (sin virtual) y en la hija public string Hablar(), el compilador avisa con una advertencia (hides inherited member): el método de la hija no sustituye al del padre. Con una variable de tipo Animal se ejecutaría siempre el del padre. Usa siempre virtual + override.
¿Herencia o composición?¶
La herencia es muy cómoda, pero crea un vínculo fuerte: si la clase base cambia, todas las hijas se ven afectadas. Antes de heredar, pregúntate si la relación es de verdad «es un».
| Relación | Se resuelve con | Ejemplo |
|---|---|---|
| «es un» (un perro es un animal) | Herencia | class Perro : Animal |
| «tiene un» (un coche tiene un motor) | Composición: una propiedad con otro objeto (ver 4.D) | Coche con una propiedad Motor |
| «sabe hacer» (un pato sabe volar) | Interfaz (ver 5.C) | Pato implementa IVolador |
No heredes solo para reutilizar código
Si Pila heredara de List<T> solo para aprovechar Add, una pila no es una lista: acabaría ofreciendo operaciones que no tienen sentido en ella. En ese caso, la pila tiene una lista dentro (composición). Regla práctica: ante la duda, composición.
Errores frecuentes¶
| Error | Cómo evitarlo |
|---|---|
| Heredar cuando la relación no es «es un» | Probar la frase «un A es un B» en voz alta |
| Jerarquías muy profundas (A → B → C → D → E) | Mantenerlas cortas; más de tres niveles suele ser mal signo |
| Llamar a un método de la subclase desde una variable del tipo base | Comprobar el tipo antes (is), o replantear el diseño |
| Olvidar inicializar la parte heredada en el constructor | Llamar siempre a base(...) con lo que necesite |
Olvidar virtual en la base o override en la hija |
El método no se sobrescribe: el compilador lo avisa con una advertencia o un error |
Para practicar¶
Los ejercicios de herencia y sobrescritura están en U5.1 (por ejemplo, los de artículos y vehículos). Compara cómo se escribe en otro lenguaje con Pasar de uno a otro.