Herencia

Anuncio
Herencia
La herencia es el proceso por el cual un objeto puede adquirir las propiedades de otro
objeto. En C++, la herencia se soporta permitiendo a una clase incorporar otra clase
dentro de su declaración.
Las clases que heredan propiedades se llaman clase derivada, mientras que la clase de
la que se heredan se denomina clase base.
La forma de declarar una clase derivada es:
class <nombre_clase_derivada> : <acceso> <nombre_clase_base>
<acceso> puede ser public o private:
- public: los miembros public siguen siendo public, los private en private y los
protected en protected.
-private: los miembros public, private y protected son todos private en la clase
derivada.
- protected: los miembros public y protected pasan a ser protected y los private
siguen siendo private.
MTP II C++
Herencia
// Clase base Persona:
class Persona {
public:
Persona(char *n, int e);
const char *LeerNombre(char *n) const;
int LeerEdad() const;
void CambiarNombre(const char *n);
void CambiarEdad(int e);
protected:
char nombre[40];
int edad;
};
// Clase derivada Empleado:
class Empleado : public Persona {
public:
Empleado(char *n, int e, float s);
float LeerSalario() const;
void CambiarSalario(const float s);
protected:
float salarioAnual;
};
MTP II C++
Herencia
Constructores de las clases derivadas:
Cuando se crea un objeto de una clase derivada, primero se invoca al constructor de la
clase o clases base y a continuación al constructor de la clase derivada.
Si la clase base es a su vez una clase derivada, el proceso se repite recursivamente.
class ClaseA {
public:
ClaseA() : datoA(10) {cout << "Constructor de A" << endl;}
int LeerA() const {return datoA;}
protected:
int datoA;
};
class ClaseB : public ClaseA {
public:
ClaseB() : datoB(20) {cout << "Constructor de B" << endl;}
int LeerB() const {return datoB;}
protected:
int datoB;
};
MTP II C++
Herencia
int main()
{
ClaseB objeto;
cout << "a = " << objeto.LeerA() << ", b = " << objeto.LeerB() << endl;
system("pause");
return 0;
}
La salida es ésta:
Constructor de A
Constructor de B
a = 10, b = 20
Presione una tecla para continuar . . .
Se ve claramente que primero se llama al constructor de la clase base A, y
después al de la clase derivada B.
MTP II C++
Herencia
Cuando queramos inicializar las clases base usando parámetros desde el
constructor de una clase derivada lo haremos de modo análogo a como lo hacemos con
los datos miembro, usaremos el constructor de la clase base con los parámetros
adecuados. Las llamadas a los constructores deben escribirse antes de las
inicializaciones de los parámetros.
<clase_derivada>(<lista_de_parámetros>) : <clase_base>(<lista_de_parámetros>) {}
class ClaseA {
public:
ClaseA(int a) : datoA(a) {cout << "Constructor de A" << endl;}
int LeerA() const {return datoA;}
protected:
int datoA;
};
class ClaseB : public ClaseA {
public:
ClaseB(int a, int b) : ClaseA(a), datoB(b) {cout << "Constructor de B" << endl;} (1)
int LeerB() const {return datoB;}
protected:
int datoB;
};
MTP II C++
int main()
Herencia
{
ClaseB objeto(5,15);
cout << "a = " << objeto.LeerA() << ", b = " << objeto.LeerB() << endl;
system("pause");
return 0;
}
La salida es ésta:
Constructor de A
Constructor de B
a = 5, b = 15
Presione una tecla para continuar . . .
Observar cómo hemos definido el constructor de la ClaseB (1). Para empezar,
recibe dos parámetros: "a" y "b". El primero se usará para inicializar la clase
base ClaseA, para ello, después de los dos puntos, escribimos el constructor de
la ClaseA, y usamos como parámetro el valor "a". A continuación escribimos la
inicialización del datoB, separado con una coma y usamos el valor "b".
MTP II C++
Herencia
Destructores de las clases derivadas:
Cuando se destruye un objeto de una clase derivada, primero se invoca al destructor
de la clase derivada, si existen objetos miembro a continuación se invoca a sus
destructores y finalmente al destructor de la clase o clases base.
Si la clase base es a su vez una clase derivada, el proceso se repite recursivamente.
class ClaseA {
public:
ClaseA() : datoA(10) {cout << "Constructor de A" << endl;}
~ClaseA() {cout << "Destructor de A" << endl;}
int LeerA() const {return datoA;}
protected:
int datoA;
};
class ClaseB : public ClaseA {
public:
ClaseB() : datoB(20) {cout << "Constructor de B" << endl;}
~ClaseB() {cout << "Destructor de B" << endl;}
int LeerB() const {return datoB;}
protected:
int datoB;
};
MTP II C++
int main()
Herencia
{
ClaseB objeto;
cout << "a = " << objeto.LeerA() << ", b = " << objeto.LeerB() << endl;
system("pause");
return 0;
}
La salida es ésta:
Constructor de A
Constructor de B
a = 10, b = 20
Presione una tecla para continuar . . .
Destructor de B
Destructor de A
Se ve que primero se llama al destructor de la clase derivada B, y después
al de la clase base A.
MTP II C++
Herencia
Superposición de Funciones:
En una clase derivada se puede definir una función que ya existía en la clase base, esto
se conoce como superposición de una función.
La definición de la función en la clase derivada oculta la definición previa en la clase
base.
En caso necesario, es posible acceder a la función oculta de la clase base mediante su
nombre completo:
<objeto>.<clase_base>::<método>;
class ClaseA {
public:
ClaseA() : datoA(10) {}
int LeerA() const {return datoA;}
void Mostrar() {cout << "a = " << datoA << endl;} (1)
protected:
int datoA;
};
class ClaseB : public ClaseA {
public:
ClaseB() : datoB(20) {}
int LeerB() const {return datoB;}
void Mostrar() {cout << "a = " << datoA << ", b = " << datoB << endl;} (2)
protected:
int datoB;
MTP II C++
};
Herencia
int main()
{
ClaseB objeto;
objeto.Mostrar();
objeto.ClaseA::Mostrar();
system("pause");
}
return 0;
La salida de este programa es:
a = 10, b = 20
a = 10
Presione cualquier tecla para continuar . . .
La definición de la función "Mostrar" en la ClaseB (1) oculta la definición
previa de la función en la ClaseA (2).
MTP II C++
Superposición y Sobrecarga
Herencia
Cuando se superpone una función, se ocultan todas las funciones con el mismo nombre
en la clase base.
Supongamos que hemos sobrecargado la función de la clase base que después
volveremos a definir en la clase derivada.
class ClaseA {
public:
void Incrementar() {cout << "Suma 1" << endl;}
void Incrementar(int n) {cout << "Suma " << n << endl;}
};
class ClaseB : public ClaseA {
public:
void Incrementar() {cout << "Suma 2" << endl;}
};
MTP II C++
int main()
{
ClaseB objeto;
}
Herencia
objeto.Incrementar();
// objeto.Incrementar(10);
objeto.ClaseA::Incrementar();
objeto.ClaseA::Incrementar(10);
system("pause");
return 0;
La salida sería:
Suma 2
Suma 1
Suma 10
Presione cualquier tecla para continuar . . .
Ahora bien, no es posible acceder a ninguna de las funciones superpuestas
de la clase base, aunque tengan distintos valores de retorno o distinto
número o tipo de parámetros. Todas las funciones "incrementar" de la clase
base han quedado ocultas, y sólo son accesibles mediante el nombre
completo.
MTP II C++
Herencia
Polimorfismo:
C++ nos permite acceder a objetos de una clase derivada usando un puntero a la clase
base. En eso consiste el polimorfismo. Por supuesto, sólo podremos acceder a datos y
funciones que existan en la clase base, los datos y funciones propias de los objetos de
clases derivadas serán innacesibles.
class Persona {
public:
Persona(char *n) { strcpy(nombre, n); }
char *VerNombre(char *n) { strcpy(n, nombre); return n;}
protected:
char nombre[30];
};
class Empleado : public Persona {
public:
Empleado(char *n) : Persona(n) {}
char *VerNombre(char *n) { strcpy(n, "Emp: "); strcat(n, nombre); return n;}
};
class Estudiante : public Persona {
public:
Estudiante(char *n) : Persona(n) {}
char *VerNombre(char *n) { strcpy(n, "Est: "); strcat(n, nombre); return n;}
};
MTP II C++
Herencia
int main()
{
char n[40];
Persona *Pepito = new Estudiante("Jose");
Persona *Carlos = new Empleado("Carlos");
}
cout << Carlos->VerNombre(n) << endl;
cout << Pepito->VerNombre(n) << endl;
delete Pepito;
delete Carlos;
system("pause");
return 0;
La salida es como ésta:
Carlos
Jose
Presione cualquier tecla para continuar . . .
Vemos que se ejecuta la versión de la función "VerNombre" que hemos
definido para la clase base
MTP II C++
Funciones Virtuales:
Herencia
El ejemplo anterior demuestra algunas de las posibilidades del polimorfismo, pero tal
vez sería mucho más interesante que cuando se invoque a una función que se superpone
en la clase derivada, se llame a ésta última función, la de la clase derivada.
Esto se consigue mediante el uso de funciones virtuales. Cuando en una clase
declaramos una función como virtual, y la superponemos en alguna clase derivada, al
invocarla usando un puntero de la clase base, se ejecutará la versión de la clase
derivada.
virtual <tipo> <nombre_función>(<lista_parámetros>) [{}];
Modifiquemos en el ejemplo anterior la declaración de la clase base
"Persona".
class Persona {
public:
Persona(char *n) { strcpy(nombre, n); }
virtual char *VerNombre(char *n) { strcpy(n, nombre); return n;}
protected:
char nombre[30];
};
MTP II C++
Herencia
La salida es como ésta:
Emp: Carlos
Est: Jose
Presione cualquier tecla para continuar . . .
Ahora, al llamar a "Pepito->VerNombre(n)" se invoca a la función "VerNombre"
de la clase "Estudiante", y al llamar a "Carlos->VerNombre(n)" se invoca a la
función de la clase "Empleado".
Una vez que una función es declarada como virtual, lo seguirá siendo en las
clases derivadas, es decir, la propiedad virtual se hereda.
Si la función virtual no se define exactamente con el mismo tipo de valor de
retorno y el mismo número y tipo de parámetros que en la clase base, no se
considerará como la misma función, sino como una función superpuesta.
MTP II C++
Descargar