Este sitio web usa cookies de terceros para analizar el tráfico y personalizar los anuncios. Si no está de acuerdo, abandone el sitio y no siga navegando por él. ×


16.3: Problemas con la herencia.

Hemos visto una introducción a los objetos, y hemos empezado a manejar la herencia y el polimorfismo.  Ahora vamos a ver algo que puede parecer desconcertante y que nos ayudará a entender qué son los métodos virtuales (espero)  ;-)

Por cierto, este tema es "denso".  No intentes "dominarlo" a la primera lectura.  Si te pierdes, prueba a releerlo entero.  Si te siguen quedando dudas, pregunta...  :-)
 

Habíamos creado nuestro objeto "Titulo".  Despues introdujimos otro llamado "TituloColor" que aprovechaba parte de las definiciones del primero, le añadimos cosas nuevas y retocamos las que nos interesaron.

Ahora vamos a crear un "TituloParpadeo", que será exactamente igual que "TituloColor", con la diferencia de que además el texto parpadeará.

Si alguien ha trabajado un poco con los colores en modo texto, sabrá que el único cambio que tenemos que hacer es sumar 128 al color que vamos a usar (o si lo preferís ver así: fijamos el primer bit de los atributos, que es el que indica el parpadeo).

Entonces crearemos un nuevo objeto que heredará todo de "TituloColor" y sólo redefinirá "FijaColores".  El programa queda así:

 {--------------------------} 
 {  Ejemplo en Pascal:      } 
 {                          } 
 {    Tercer ejemplo de     } 
 {    Prog. Orientada Obj.  } 
 {    OBJETOS3.PAS          } 
 {                          } 
 {  Este fuente procede de  } 
 {  CUPAS, curso de Pascal  } 
 {  por Nacho Cabanes       } 
 {                          } 
 {  Comprobado con:         } 
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    } 
 {--------------------------}
 program Objetos3;                  { Nuestro tercer programa en OOP }
 uses crt;                            { Usaremos "GotoXY" y TextAttr }
 type                                { Aquí definimos nuestro objeto } 
   titulo = object 
     texto: string;                      { El texto que se escribirá } 
     x,y : byte;                                   { En qué posición } 
     procedure FijaCoords(nuevoX, nuevoY: byte);          { Pues eso } 
     procedure FijaTexto(mensaje: string);                    { Idem } 
     procedure Escribe;                          { Lo escribe, claro } 
   end;
  type 
   TituloColor = object( titulo ) 
     color: byte;                                  { El color, claro } 
     procedure FijaColores(pluma, fondo: byte);           { Pues eso } 
     procedure Escribe;               { Lo escribe de distinta forma } 
   end;
  type 
   TituloParpadeo = object( tituloColor ) 
     procedure FijaColores(pluma, fondo: byte);          { Pues eso } 
   end;
 var 
   T1: titulo;                      { Una variable de ese tipo } 
   T2: tituloColor;                 { Y otra del otro ;-)  } 
   T3: tituloParpadeo;              { Y el que queda }
 { --- Desarrollo del objeto Titulo --- }
 procedure titulo.FijaCoords(nuevoX, nuevoY: byte); 
 begin                                 { Definimos el procedimiento: } 
   x := nuevoX;                          { Actualiza las coordenadas } 
   y := nuevoY; 
 end;
 procedure titulo.FijaTexto(mensaje: string); 
 begin                                          { Actualiza el texto } 
   Texto := Mensaje; 
 end;
 procedure titulo.Escribe; 
 begin                                           { Muestra el título } 
   Gotoxy(X,Y); 
   Write(Texto); 
 end;
 { --- Métodos específicos de TituloColor --- }
 procedure tituloColor.FijaColores(pluma,fondo: byte); 
 begin                                 { Definimos el procedimiento: } 
   color := pluma + fondo*16;                   { Actualiza el color } 
 end;
 procedure tituloColor.Escribe; 
 begin                                           { Muestra el título } 
   textAttr := color; 
   Gotoxy(X,Y); 
   Write(Texto); 
 end;
 { --- Métodos específicos de TituloParpadeo --- }
 procedure tituloParpadeo.FijaColores(pluma,fondo: byte); 
 begin                                 { Definimos el procedimiento: } 
   color := pluma + fondo*16 + 128;             { Actualiza el color } 
 end;
 { -- Cuerpo del programa --}
 begin 
   ClrScr; 
   T1.FijaCoords(37,12); 
   T1.FijaTexto('Hola'); 
   T1.Escribe; 
   T2.FijaCoords(37,13); 
   T2.FijaColores(14,2); 
   T2.FijaTexto('Adiós'); 
   T2.Escribe; 
   T3.FijaCoords(35,14); 
   T3.FijaColores(15,3); 
   T3.FijaTexto('Y una más'); 
   T3.Escribe; 
 end.

No hemos definido Escribe para TituloParpadeo y sin embargo lo hemos usado.  Claro, es que tampoco hacía falta redefinirlo.  Recordemos la definición de TituloColor.Escribe:

procedure tituloColor.Escribe;
begin
  textAttr := color;    { Asignamos el color }
  Gotoxy(X,Y);          { Vamos a la posición adecuada }
 Write(Texto);         { Y escribimos el texto }
end;

Todo nos sirve: queremos hacer eso mismo, pero con "TituloParpadeo" en vez de con "TituloColor".  No hay problema, el compilador se da cuenta de que es T3 quien intenta escribir, y toma las variables X, Y, Color y Texto apropiadas.

Así tenemos el primer rótulo "Hola", con letras grises y fondo negro. El segundo, "Adiós", tiene letras amarillas y fondo verde.  El tercero, "Y una más", tiene fondo azul claro y letras blancas parpadeantes.

Inciso momentáneo:  En OOP se suele llamar CLASE a una definición genérica de un objeto, como en nuestro caso "TituloColor" e INSTANCIA a una variable concreta que pertenece a ese clase, como T2 en nuestro ejemplo.  Como ejemplo más general, "persona" sería una clase, formada por muchos individuos con unas características comunes, mientras que "Pepe" sería un objeto (sin ánimo de ofender) de la clase persona, una instancia de esa clase.

Así me puedo permitir el lujo de usar las palabras "clase" e "instancia" cuando quiera y ya nadie tiene excusa para protestar... O:-)