La herencia en POO es una de las características fundamentales de la Programación Orientada a Objetos por la que, tomando como base una clase ya existente, es posible derivar una nueva, que heredará todos sus miembros, teniendo posibilidad de sobrecargarlos, crear unos nuevos o utilizarlos. La idea básica por tanto, es reutilizar las clases existentes y extender o modificar su semántica.

 

Para crear una clase derivada, tras el nombre de la clase, se pondrán dos puntos y el nombre de la clase que se quiere tomar como base. Además, deberemos especificar el tipo de herencia en POO, lo cual se especificará delante del nombre de la clase base.

 

 

Por ejemplo, supongamos que a partir de la clase Ventana, que permite gestionar ventanas en modo texto, queremos crear una clase Ventanagrafica que las gestiona en modo gráfico. Para ello empleamos el siguiente código:

class Ventanagrafica: public Ventana
{
.
.
.
.
};

Herencia Pública o Privada

¿Qué estado tendrán en una clase derivada los miembros y métodos heredados de su clase base? En cuanto a esa cuestión, todo va a depender del cualificador que se utilice delante del nombre de la clase base: public o private.

 

Los miembros de la clase base que sean private no serán accesibles en la clase derivada en ningún momento.

Los miembros de la clase base que sean declarados protected serán accesibles en la clase derivada, aunque no fuera de ella, es decir, que si una clase deriva de forma privada miembros protegidos de la base, en la derivada van a ser accesibles, pero en una futura derivada de la actual derivada van a ser privados.

Si por el contrario, se derivan como public, en la clase derivada van a seguir siendo públicos, pero si se deriva de forma privada, serán privados.

#include <iostream>
class Base
{
int Entero; // Miembro privado por defecto
protected:
void FijaEntero( int N)
{
Entero=N;
}
public:
void ObtenEntero(void)
{
return Entero;
}
};
class Derivada : public Base
{
public:
void ImprimeEntero(void)
{
cout<<Entero; // Error: Entero no está
// accesible aquí
}
void ActivaBase(int N)
{
FijaEntero(N); // Correcto: acceso a
// miembro protegido
}
void MuestraEntero(void)
{
cout << ObtenEntero();
// Correcto: acceso a miembro público
}
};
void main(void)
{
Derivada A;
A.ActivaBase(5); // Se accede a un miembro público
cout << A.ObtenEntero(); // Correcto, al ser un miembro
// público
A.FijaEntero(10); //Error, FijaEntero está protegido,
} //y por tanto, no accesible desde
//fuera

Problemas de Accesibilidad

Vamos a ver lo que ocurre cuando tenemos una clase derivada de otra, en la cual (en la derivada), hay miembros que coinciden en nombre con miembros de la clase base.

Como regla general, una clase siempre utilizará por defecto sus miembros antes que cualquier otro que se llame igual, aunque esté en la clase de donde se ha derivado.

Para hacer uso de la clase base es necesario usar el operador :: precedido del nombre de dicha clase.

#include <iostream.h>
int Entero; // Variable global
class Base
{
protected:
int Entero; // Miembro protegido
};
class Derivada : public Base
{
int Entero;
public:
void ImprimeValores(void);
};
void Derivada::ImprimeValores(void)
{
cout << Entero; // Imprime el Entero de la clase derivada
cout << Base::Entero; // Imprime el Entero de la clase Base
cout << ::Entero; // Imprime el Entero varible global
}

Conversión de la Clase Derivada a Base

Un objeto de una clase derivada tendrá más información que uno de la clase base. Así, esto nos va a permitir hacer asignaciones de un objeto de la clase derivada a otro de la clase base, aunque no al revés, es decir, BASE=DERIVADA, pero no al revés.

class Base
{
int Entero1;
};
class Derivada : public Base
{
int Entero2; // Se hereda Entero1
};
void main(void)
{
Base A;
Derivada B;
A = B; // Ningún problema, Entero1 se asigna de B a A
B = A; // Error, en A existe Entero1 para asignar a B, pero
// no Entero2
}

En este ejemplo, el objeto A está compuesto de un miembro -un entero-, mientras que B está compuesto de dos miembros -el entero heredado y el suyo propio-. Por tanto, B tiene información suficiente para ”llenar” el objeto A, pero no así en sentido contrario.

Herencia en POO, Constructores y Destructores

Si se tiene una clase derivada se comprobará que parte de los miembros pertenecen a la clase base, y será ella quien los cree, y parte pertenecen a la derivada.

 

Por tanto, en la creación de una clase derivada intervendrán el constructor de la clase base y el de la derivada. Por tanto, el constructor de la clase derivada, normalmente, llamará al de la clase base.

En el caso de que el constructor de la clase base no tenga parámetros, no va haber problemas, puesto que se llamará de forma automática, pero si por el contrario, tiene parámetros, la clase derivada tendrá que llamar al constructor de la clase base. Por tanto, el constructor de la clase derivada deberá recibir dos conjuntos de parámetros, el suyo y el de la clase base, al cual deberá de llamar con el conjunto de parámetros correspondiente.

#include <iostream.h>
class Base
{
int Entero1;
public:
Base()
{
Entero1=0;
cout <<(“Constructor Base \n”);
}
Base(int N)
{
Entero1=N;
}
};
class Derivada : public Base
{
// Se hereda Entero1
int Entero2;
public:
Derivada()
{
Entero2=0;
cout <<(“Constructor Derivado\n”);
}
Derivada(int N1, int N2) : Base (N1)
{
Entero2=N2;
}
};
void main(void)
{
Base A(5);
Derivada B(3,6);
}

En cambio, con los destructores ocurre todo lo contrario, puesto que se destruirá primero el objeto de la clase heredada y después se irán llamando a los destructores de objetos de las clases bases. Además, una ventaja que tiene es que como los destructores no tienen parámetros, no es necesario llamar al destructor de la clase base, sino que la
llamada se hará de forma automática.

#include <iostream>
class Base
{
protected:
int Entero1;
public:
Base()
{
Entero1=0;
cout <<(“Constructor Base\n”);
}
Base(int N)
{
Entero1=N;
}
∼Base()
{
cout <<(“Destructor Base\n”);
}
};
class Derivada : public Base
{
int Entero2; // Se hereda Entero1
public:
Derivada()
{
Entero2=0;
cout <<(“Constructor Derivado\n”);
}
Derivada(int N1, int N2) : Base(N1)
{
Entero2=N2;
}
∼Derivada()
{
cout << “Destructor Derivado\n”;
}
}
void main(void)
{
Base A(5);
Derivada B(3,6);
}

Herencia en POO: Tipo Múltiple

Una misma clase puede heredar de varias clases base, e incorporar por tanto los distintos miembros de éstas, uniéndolos todos en una sola clase.

Para construir una clase derivada tomando varias como base, se pondrán los nombres de cada una de las clases base separadas por coma, antecedidos, cada una de la palabra public o private. Siempre que sea posible, evite usar herencia en poo de tipo múltiple.

Herencia

aprendeinformaticas.com

netmentor