Concepto: Herencia
#1
Escrito 17 diciembre 2008 - 05:47
En esta oportunidad voy a hablar sobre la herencia de clases.
¿Que es la herencia de clases?
En términos generales la herencia es una propiedad que permite que algún objeto sea creado a partir de otros ya existentes, obteniendo características (métodos y atributos) similares al objeto base.
La herencia es uno de los mecanismos de la programación orientada a objetos, por medio del cual una clase se deriva de otra, de manera que extiende su funcionalidad y una de sus funciones más importantes es la de proveer Polimorfismo que es la capacidad que tienen los objetos de una clase de responder al mismo mensaje o evento en función de los parámetros utilizados durante su llamado.
Bueno, para no aburrirlos con teoría que bien pueden leer en cualquier sitio web o en la ayuda de Delphi , vamos a ver un ejemplo de esto.
#2
Escrito 17 diciembre 2008 - 05:52
2. Agregamos en la forma un botón y un Memo.
3. Creamos una clase con el clasico ejemplo de Mamifero.
TMamifero = class(TObject) Nombre: string; Patas: integer; function MuestraDatos:string; end;
4. Ahora escribimos algo de código en la función MuestraDatos (puedes hacerlo posicionandote en la función y presionando con Ctrl+Shift+C)
{ TMamifero } function TMamifero.MuestraDatos: string; begin result := nombre + ' tiene ' + inttostr(patas) + ' patas'; end;
5. En el evento onClick del botón escribimos este código.
procedure TForm1.Button1Click(Sender: TObject); var Mamifero: TMamifero; //Asignamos una variable del tipo TMamifero begin Mamifero := TMamifero.Create; //Creamos el objeto with Mamifero do begin Nombre := 'Perro'; Patas := 4; Memo1.Lines.Add(MuestraDatos); //Mostramos en el memo el resultado de la función MuestraDatos end; end;
Bueno, hasta aquí podrán observar que hemos creado una clase base TMamifero, ahora vamos a crear una clase que va a heredar de la clase base sus caracteristicas.
6. Creamos una clase de nombre TPerro la cual decenderá de la clase TMamifero.
TMamifero = class(TObject) Nombre: string; Patas: integer; function MuestraDatos:string; virtual; end; TPerro = class(TMamifero) Raza: string; function MuestraDatos:string; override; end;
Esta clase hereda de la clase TMamiferos El Nombre y las Patas, pero se agrega a ella el dato Raza y la función MuestraDatos que tiene el mismo nombre que la función base. Hay que notar que se han escrito dos palabras reservadas (virtual en la clase base y override en la clase derivada) adelante de cada una de las funciones, esto es necesario cuando una función en la clase base es redefinida en la clase derivada.
7. Ahora escribimos algo de código en la función MuestraDatos de la clase derivada, la cual requerimos que tenga diferente retorno (puedes hacerlo posicionandote en la función y presionando con Ctrl+Shift+C)
function TPerro.MuestraDatos: string; begin result := nombre + ' tiene ' + inttostr(patas) + ' patas y es de raza ' + Raza; end;
8. Agregamos mas código a nuestro evento del Botón
procedure TForm1.Button1Click(Sender: TObject); var Mamifero: TMamifero; Perro: TPerro; begin //Clase base Mamifero := TMamifero.Create; with Mamifero do begin Nombre := 'Perro'; Patas := 4; Memo1.Lines.Add(MuestraDatos); end; //Clase derivada Perro := TPerro.Create; with Perro do begin Nombre := 'Bobby'; Patas := 4; Raza := 'Chihuahua'; Memo1.Lines.Add(MuestraDatos); end; end;
Ejecutamos el programa y veremos la diferencia entre las dos funciones declaradas.
8. Podemos notar que las dos funciones MuestraDatos son realmente similares, pero aquí es donde vamos a ver los beneficios de la herencia de clases.
Reescribimos el código de la función de la clase derivada MuestraDatos de esta forma:
function TPerro.MuestraDatos: string; begin result := inherited MuestraDatos + ' y es de raza ' + Raza; end;
Agregamos la palabra reservada inherited para heredar el comportamiento de la función MuestraDatos de la clase base dentro de la función de la clase derivada, ejecutamos el programa y vean el resultado.
Con esto terminamos este tutorial, esperando que sea de utilidad.
Salud OS
#3
Escrito 17 diciembre 2008 - 05:57
Unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TMamifero = class(TObject) Nombre: string; Patas: integer; function MuestraDatos:string; virtual; end; TPerro = class(TMamifero) Raza: string; function MuestraDatos:string; override; end; TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TMamifero } function TMamifero.MuestraDatos: string; begin result := nombre + ' tiene ' + inttostr(patas) + ' patas'; end; procedure TForm1.Button1Click(Sender: TObject); var Mamifero: TMamifero; Perro: TPerro; begin Mamifero := TMamifero.Create; with Mamifero do begin Nombre := 'Perro'; Patas := 4; Memo1.Lines.Add(MuestraDatos); end; Perro := TPerro.Create; with Perro do begin Nombre := 'Bobby'; Patas := 4; Raza := 'Chihuahua'; Memo1.Lines.Add(MuestraDatos); end; end; { TPerro } function TPerro.MuestraDatos: string; begin result := inherited MuestraDatos + ' y es de raza ' + Raza; end; end.
Salud OS
#4
Escrito 17 diciembre 2008 - 10:02
Disculpa que este post arruine un poquito el tutorial.
Me he quedado sorprendido por la simpleza de tus palabras para explicar el tema sin demasiado tecnicismos.
Si es que no estoy obrando mal, me preguntaba si es posible complementar el tema con una pequeña explicación de la diferencia entre virtual y abstract.
Cuando uno desea, o mejor dicho tiene pensando diseñar, contar con un método que pueda ser sobreescrito en una clase base necesita declarar al método como "virtual". Pero además de virtual, existe otra clásula: abstract.
Cuando uno declara un método virtual abre la posibilidad de que las clases que heredan de la base, puedan modificar e implementar su propio "código" dentro del método. Una clase heredera (o hija) puede o no sobreescribirlo.
El compilador solito se encarga de invocar al método de la clase base o hija según sea necesario.
Por ejemplo, siguiendo tus demostraciones:
type TGato = class(TMamifero) public Largobigotes: integer; Maullar; end;
En TGato no implemento la función MostrarDatos. Por tanto cuando haga algo como:
var Gato: TGato; begin Gato := TGato.Create; Gato.Nombre := 'Garfield'; Gato.Patas := 4; Gato.MostrarDatos; end;
Se ejecutará el MostrarDatos de la clase TMamifero.
Pero si uso el TPerro, observaremos que se llama al MostrarDatos de TPerro.
Ahora, Abstract es algo similar. No está demás decir que para que un método sea abstracto necesariamente debe ser virtual. ¿Qué hace abstract?
En pocas obliga a que sean las clases hijas las que implementen el algoritmo del método. Por tanto no se da ninguna implementación en la clase base.
En resumen:
Virtual se emplea cuando el método pueda ser sobreescrito por el de una clase hija.
Abstracto se emplea cuando se busca que el método sea obligadamente implementado por la clase hija.
Por ejemplo, podríamos hacer algo así:
TMamifero = class(TObject) ... public procedure Hablar; virtual; abstract; end; TPerro = class(TMamifero) ... public procedure Hablar; override; end; TGato = class(TMamifero) ... public procedure Hablar; override; end; ... procedure TPerro.Hablar; begin ShowMessage('Guau'); end; procedure TGato.Hablar; begin ShowMessage('Miau'); end;
Si se intenta implementar el método Hablar a TMamifero el compilador nos advierte de que es abstracto.
No está demás decir que en las clases hijas se debe incluir la clásula override.
Espero no ser inoportuno con este post. Me pareció que puede contribuir a comprender los conceptos complementarios en el tema de herencia.
Saludos,
#5
Escrito 17 diciembre 2008 - 10:47
Los miembros Public, Private, Protected, Published y Property los queria abordar en tutoriales futuros, sin embargo me parece excelente que hayas enriquecido este tutorial con tu aportación.
Salud OS
Animate a publicar algún tutorial en este tu foro.
#6
Escrito 17 diciembre 2008 - 11:05
Revisando el ejemplo he encontrado una omisión grave de mi parte. No estoy liberando los objetos creados. Lo siento :$
procedure TForm1.Button1Click(Sender: TObject); var Mamifero: TMamifero; Perro: TPerro; begin Mamifero := TMamifero.Create; with Mamifero do begin Nombre := 'Perro'; Patas := 4; Memo1.Lines.Add(MuestraDatos); Free; //Liberamos el objeto *********** end; Perro := TPerro.Create; with Perro do begin Nombre := 'Bobby'; Patas := 4; Raza := 'Chihuahua'; Memo1.Lines.Add(MuestraDatos); Free; //Liberamos el objeto *********** end; end;
Salud OS
#7
Escrito 18 diciembre 2008 - 11:37
OK, entonces evito dar indicaciones de visibilidad por el momento .Gracias amigo Delphius,
Los miembros Public, Private, Protected, Published y Property los queria abordar en tutoriales futuros, sin embargo me parece excelente que hayas enriquecido este tutorial con tu aportación.
Salud OS
Animate a publicar algún tutorial en este tu foro.
Bueno, ya que me invitas a hablar de algo, quisiera aprovechar este sub-foro de Manuales y Tutoriales para tratar en forma un poco más completa lo que es polimorfismo.
Espero que no salga tan técnico.
Saludos,
#8
Escrito 18 diciembre 2008 - 11:54
OK, entonces evito dar indicaciones de visibilidad por el momento .
Bueno, ya que me invitas a hablar de algo, quisiera aprovechar este sub-foro de Manuales y Tutoriales para tratar en forma un poco más completa lo que es polimorfismo.
Me parece muy bien amigo, mi intención era comenzar con Herencia, seguir con Polimorfismo y despues con la visibilidad de miembros
Espero que no salga tan técnico.
Bueno amigo, la verdad es que seria muy bueno que no fuera tan técnico (pero no tan simple como yo lo hago :$) la idea es que aprendamos divirtiendonos y la teoria pues es algo engorrosa a veces, bueno, eso desde mi (paranoico) punto de vista
Salud OS
#9
Escrito 19 diciembre 2008 - 09:11
Saludos.
#10
Escrito 22 julio 2016 - 08:05
Hola , ¿ no conocen un ejemplo sobre como hacer esto en units por separado me refiero a mamifero y perro en unit diferentes como se hace en Visual ?.
#11
Escrito 22 julio 2016 - 08:41
Hola , ¿ no conocen un ejemplo sobre como hacer esto en units por separado me refiero a mamifero y perro en unit diferentes como se hace en Visual ?.
No hace falta un ejemplo. Basta con que crees una unit para cada clase y referencies la unidad en donde se encuentre la clase base en la sección uses.
Para el ejemplo que se expone aquí digamos que tienes una unidad UMamifero y UPerro, en cada unidad se va a definir su respectiva clase. Ahora, para que TPerro pueda heredad de TMamifero debemos poner en la sección uses de UPerro la UMamifero:
Unit UPerro; interface uses UMamifero; type TPerro = class(TMamifero) // aquí ponemos lo que tiene que tener TPerro end; implementation ...
Por cierto, te agradecería que en lo posible se evite exponer dudas en los hilos que sean Manuales y/o Tutoriales.
Si la duda es sobre alguno de ellos, en su lugar consideramos oportuno iniciar un propio hilo en el foro más apropiado al caso y allí hacer referencia al manual o tutorial sobre el cual se tienen dudas o problemas.
Muchas gracias.
Saludos,
Saludos,