AnteriorPosterior

Tema 16e. Programación orientada a objetos (5)

  Curso: Curso de Pascal, por Nacho Cabanes

Curso de Pascal. Tema 16.5: Métodos virtuales.

Entonces está claro que el error aparece cuando un método llama a otro que no hemos redefinido, porque puede no saber con quien enlazarlo.  Lo intentará con su padre o ascendiente más cercano, y los resultados quizá no sean los adecuados.

Deberíamos regañar a nuestro compilador y decirle...

   "Mira, no me presupongas cosas.  Cuando alguien te diga Escribe, haz
   el favor de mirar quién es, y hacerlo como sabes que él quiere."  ;-)

¿Ah, pero se puede hacer eso?  Pues resulta que sí: lo que el compilador hace si no le decimos nada es un enlace estático o "temprano" (en inglés, early binding), en el momento de compilar el programa.  Pero también podemos pedirle que haga un enlace dinámico o "tardío" (late binding) justo en el momento de la ejecución, que es lo que nos interesa en estos casos.

De modo que con el enlace dinámico damos una mayor flexibilidad y potencia a la Herencia.  Por contra, como los enlaces se calculan en tiempo de ejecución, el programa resultante será ligeramente más lento.

¿Y cómo se hace eso del enlace dinámico?  Pues indicando que se trata de un método VIRTUAL.  ¿Y eso otro cómo se hace?  Fácil:, en la cabecera del método añadimos esa palabra después del punto y coma:

type                                { Aquí definimos nuestro objeto }
  titulo = object
    [...]
    procedure Escribe; virtual;
    [...]
  end;

Antes de ver cómo quedaría nuestro programa, unos comentarios:

  • Si un método es virtual en un cierto objeto, deberá serlo también en todos sus descendientes (objetos definidos a partir de él mediante herencia).
  • Antes de llamar al método virtual, el compilador debe hacer alguna inicialización que le asegure que va a encontrar a dónde apunta ese método virtual, etc.  Para ello deberemos definir un método  constructor . El simple hecho de definir un método (el primero que vayamos a utilizar) como "constructor" en vez de "procedure" hace que el compilador nos asegure que todo va a ir bien.  Ese contructor podemos llamarlo, por ejemplo, "init" (inicializar, en inglés; es el nombre que usa Turbo Pascal en todos los ejemplos que incluye).

 {--------------------------} 
 {  Ejemplo en Pascal:      } 
 {                          } 
 {    Quinto ejemplo de     } 
 {    Prog. Orientada Obj.  } 
 {    OBJETOS5.PAS          } 
 {                          } 
 {  Este fuente procede de  } 
 {  CUPAS, curso de Pascal  } 
 {  por Nacho Cabanes       } 
 {                          } 
 {  Comprobado con:         } 
 {    - Free Pascal 2.2.0w  }
 {    - Turbo Pascal 7.0    } 
 {--------------------------}
 program Objetos5;                  { Nuestro quinto 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 } 
     constructor FijaCoords(nuevoX, nuevoY: byte);        { <======= } 
     procedure FijaTexto(mensaje: string);                    { Idem } 
     procedure Escribe; virtual;                 { <===== Lo escribe } 
     procedure AsignaYEscribe(nuevoTexto:string); 
   end;
  type 
   TituloColor = object( titulo ) 
     color: byte;                                  { El color, claro } 
     procedure FijaColores(pluma, fondo: byte);           { Pues eso } 
     procedure Escribe; virtual;           { <====== Virtual también } 
   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 --- }
 constructor 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;
 procedure titulo.AsignaYEscribe(nuevoTexto:string); 
 begin 
   FijaTexto(NuevoTexto); 
   Escribe; 
 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.AsignaYEscribe('Hola'); 
   T2.FijaCoords(37,13); 
   T2.FijaColores(14,2); 
   T2.AsignaYEscribe('Adiós'); 
   T2.Escribe; 
   T3.FijaCoords(35,14); 
   T3.FijaColores(15,3); 
   T3.AsignaYEscribe('Y una más'); 
 end.
 

Continuará...  :-)

Actualizado el: 08-07-2012 14:16

AnteriorPosterior