BotonMenu
BotonIndice

Visita : conoce3000.com
Paypal : https://www.paypal.com/donate/?hosted_button_id=XY8TZ3MGN64GE

PASCAL CON FREE PASCAL

PASCAL CON FREE PASCAL

PASCAL CON FREE PASCAL


10. INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS I.
10.7. POLIMORFISMO POR SOBRE-ESCRITURA CON ENLACE POSTERIOR.
10. INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS I.
10.7. POLIMORFISMO POR SOBRE-ESCRITURA CON ENLACE POSTERIOR.
10. INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS I.
10.7. POLIMORFISMO POR SOBRE-ESCRITURA CON ENLACE POSTERIOR.

SIGUIENTE

SIGUIENTE

SIGUIENTE


‒ Polimorfismo por sobre-escritura con enlace posterior.

Los métodos y constructores que hemos visto en todas las clases de los capítulos anteriores, se conocen como métodos y constructores estáticos, y se ejecutan con un enlace anterior o estático. Esto quiere decir que la dirección de memoria del método a ejecutar se establece cuando se compila el programa.

Lo contrario son los métodos y constructores virtuales o dinámicos, en donde la dirección de memoria del método o constructor a ejecutar se establece, sólo cuando se ejecuta el programa, es decir los métodos o constructores se ejecutan con un enlace posterior o dinámico. Para explicar estos conceptos veremos a continuación el siguiente ejemplo. Dadas las siguientes clases:


Descargar
{$codepage utf8}
{$mode objfpc}
Unit Clase01;
Interface
 Type Tclase01=class
        A:integer;
        Procedure Poner;
      Procedure Mostrar;
      End;
 
Implementation
    Procedure TClase01.Poner;
      Begin     
        a:=9 
      End;    
      
   Procedure TClase01.Mostrar;
      Begin
        Poner;
        Writeln(a)
      End;
End.
Código fuente 17: Unidad Clase01.pp con la clase TClase01.
Descargar


Descargar
{$codepage utf8}
{$mode objfpc}
Unit Clase02;
Interface
 Uses Clase01;
 Type Tclase02=class(TClase01)
        Procedure Poner;
      End;

Implementation
    Procedure TClase02.Poner;
      Begin
        a:=5
      End;

End.
Código fuente 18: Unidad Clase02.pp con la clase TClase02.
Descargar

Las clases TClase01 y TClase02, tienen un método Poner en común, en donde el método Poner de la clase TClase02, sobre-escribe al método Poner de la clase TClase01. También existe un método Mostrar en la clase TClase01, este ejecuta el método Poner de la clase TClase01. Ahora el siguiente programa hace uso de las clases a través de los objetos C01 y C02.


Descargar
{$codepage utf8}
{$mode objfpc}
Uses Clase01,Clase02;
Var C01:TClase01;
    C02:TClase02;
Begin
  C01:=TClase01.create;
  C02:=TClase02.create;
  C01.Mostrar;
  C02.Mostrar
End.
Código fuente 19: Programa que usa las clases TClase01 y TClase02.
Descargar

Cuando ejecute el programa se mostrará dos veces el numero 9. Esto es debido a que el método Mostrar del objeto C01 ejecutará el método poner de la clase TClase01, lo cual es correcto ya que el objeto C01 es de la clase TClase01. Pero cuando ejecutamos el método Mostrar del objeto C02, esté hará lo mismo y ejecutará el método Poner de la clase TClase01, ignorando el método Poner sobrescrito, de la clase TClase02. Si queremos que el método mostrar de la clase TClase01, ejecute el método poner de la clase descendiente TClase02, podemos sobre-escribir el método mostrar en la clase TClase02, para cambiar su comportamiento. Pero existe otro modo de hacer que el método Mostrar de la clase TClase01, ejecute el método Poner correspondiente a determinada clase. Para ello se hace uso de los métodos virtuales o dinámicos.

Primero se declara cómo virtual el método poner de la clase TClase01, colocando la palabra reservada virtual después del nombre del método, y del mismo modo, se coloca la palabra reservada override, al método poner de la clase TClase02. A continuación las clases con los cambios indicados:


Descargar
{$codepage utf8}
{$mode objfpc}
Unit Clase01b;
Interface
 Type Tclase01=class
        A:integer;
        Procedure Poner;virtual;
        Procedure Mostrar;
      End;

Implementation
    Procedure TClase01.Poner;
      Begin
        a:=9
      End;

   Procedure TClase01.Mostrar;
      Begin
        Poner;
        Writeln(a)
      End;
End.
Código fuente 20: Unidad Clase01b.pp con la clase TClase01 y él método virtual Poner.
Descargar


Descargar
{$codepage utf8}
{$mode objfpc}
Unit Clase02b;
Interface
 Uses Clase01b;
 Type Tclase02=class(TClase01)
        Procedure Poner;override;
      End;

Implementation
    Procedure TClase02.Poner;
      Begin
        a:=5
      End;

End.
Código fuente 21: Unidad Clase02b.pp con la clase TClase02 y él método Poner con override.
Descargar

Ahora cuando, se compila y ejecuta el programa prueba.pp, se mostrarán los números 9 y 5. Gracias al enlace posterior, el método mostrar de la clase TClase01, podrá determinar que método poner se ejecutará, dependiendo de qué objeto lo esté ejecutando. A esto se le conoce como Polimorfismo por enlace posterior.

Siguiendo con el ejemplo de las clases TComplejo y TReal, se desea añadir el método cuadrado, que nos permitirá elevar al cuadrado el número complejo colocado en su parámetro, pero para ello primero debemos sobre-escribir el método multiplicar en la clase TReal. Esto debido a que el método multiplicación tal como está, realiza cálculos innecesarios cuando es un objeto de la clase TReal, Es decir, si un objeto es de la clase TReal entonces no es necesario que multipliquemos la parte imaginaria, ya que este siempre será cero.

Primero sobre-escribimos el método multiplicación en la clase TReal, el método sería el siguiente:

   Procedure TReal.Multiplicacion(n:TComplejo);
     Begin
       PonReal(ObtReal*n.ObtReal)
     End;

Luego implementamos el método cuadrado que es el siguiente:

   Procedure TComplejo.Cuadrado(n:Tcomplejo);
     Begin
       PonReal(n.obtReal);
       PonImag(n.ObtImag);
     Multiplicacion(n)
   End;

Cómo podemos observar, el método cuadrado hace uso del método Multiplicación de la clase TComplejo, con lo que si creamos un objeto de la clase TReal y usamos el método Cuadrado, este ejecutará el método de la clase TComplejo y no el de la clase TReal. Pero como ya se explicó anteriormente debemos hacer que los métodos Multiplicación de ambas clases usen el enlace posterior, con ayuda de las palabras reservadas virtual y override. A continuación las clases TComplejo y TReal con los cambios indicados:


Descargar
{$codepage utf8}
{$mode objfpc}
Unit Complejos04;
Interface
Type
  TComplejo = class
    private
    ParteReal,ParteImag:double;
    public
    Constructor Crear(i:double); //Crea un imaginario puro
    Constructor Crear(r,i:double);
    Function ObtReal:double;
    Function ObtImag:double;
    Procedure PonReal(n:double);
    Procedure PonImag(n:double);
    Function ObtCad(dec:integer):string;
    Function PonCad(n:string):integer;
    Procedure Adicion(n:TComplejo);
    Procedure Multiplicacion(n:TComplejo);virtual;
    Procedure Cuadrado(n:TComplejo);
  End;

Implementation

    Constructor TComplejo.Crear(i:double);
      Begin
        ParteReal:=0;
        ParteImag:=i
      End;

    Constructor TComplejo.Crear(r,i:double);
      Begin
        ParteReal:=r;
        ParteImag:=i;
      End;

    Function TComplejo.ObtReal:double;
      Begin
        ObtReal:=ParteReal
      End;

    Function TComplejo.ObtImag:double;
      Begin
        ObtImag:=ParteImag
      End;

    Procedure TComplejo.PonReal(n:double);
      Begin
        ParteReal:=n;
      End;

    Procedure TComplejo.PonImag(n:double);
      Begin
        ParteImag:=n
      End;

    Function TComplejo.ObtCad(dec:integer):string;
      var aux1,aux2,p:string;
      Begin
        p:='';
        Str(ParteReal:0:dec,aux1);
        Str(ParteImag:0:dec,aux2);
        if ParteImag>=0 then p:='+';
        ObtCad := aux1 + p +  aux2 + 'i';
      End;

      Function TComplejo.PonCad(n:string):integer;
      Var aux:string;
          p,i,error:integer;
          PR,PI:string;
          encontro:boolean;
      Begin
       aux:=n;
       ParteReal:=0;
       ParteImag:=0;
       error:=0;
       if (aux[length(aux)]='i') and (Not(aux[length(aux)-1]in['0'..'9']))
          then aux:=Copy(aux,1,length(aux)-1)+'1i';
       if aux[length(aux)]='i' then
         Begin
           delete(aux,length(aux),1);
           if aux[length(aux)] in ['0'..'9']
              then Begin
                     i:=length(aux);
                     encontro:=false;
                     p:=0;
                     while (not encontro) and (i>1) do
                      Begin
                       if (aux[i]='+') or (aux[i]='-')
                         then Begin
                               encontro:=true;
                               p:=i
                              end;
                       i:=i-1
                      End;
                     PR:=Copy(aux,1,p-1);
                     delete(aux,1,p-1);
                     PI:=aux;
                     Val(PR,ParteReal,error);
                     Val(PI,ParteImag,error);
                     if error<>0 then
                       Begin
                         ParteReal:=0;
                         ParteImag:=0
                       End
                   End;
         End
       else
        Begin
         Val(aux,ParteReal,error);
        End;
       PonCad:=error
      End;

    Procedure TComplejo.Adicion(n:TComplejo);
      Begin
        PonReal(ObtReal+n.ObtReal);
        PonImag(ObtImag+n.ObtImag)
      End;

    Procedure TComplejo.Multiplicacion(n:TComplejo);
      var PR,PI:double;
      Begin
       Writeln('Multiplicando con TComplejo');
       PR:=(ObtReal*n.ObtReal)-(ObtImag*n.ObtImag);
       PI:=(ObtReal*n.ObtImag)+(ObtImag*n.ObtReal);
       PonReal(PR);
       PonImag(PI)
      End;

    Procedure TComplejo.Cuadrado(n:Tcomplejo);
     Begin
       PonReal(n.obtReal);PonImag(n.ObtImag);
       Multiplicacion(n)
     End;

End.
Código fuente 22: Unidad Complejos04.pp con el método virtual Multiplicación.
Descargar


Descargar
{$codepage utf8}
{$mode objfpc}
Unit Reales04;
Interface
Uses Complejos04;
Type
TReal = class(TComplejo)
    Constructor Crear(r:double);
    Function ObtCad(dec:integer):string;
    Procedure Multiplicacion(n:TComplejo);override;
 End;

Implementation
    Constructor TReal.Crear(r:double);
      Begin
        inherited Crear(r,0);
      End;

    Function TReal.ObtCad(dec:integer):string;
      var p:string;
      Begin
         Str(ObtReal:0:dec,p);
         ObtCad := p
      End;

    Procedure TReal.Multiplicacion(n:TComplejo);
     Begin
       Writeln('Multiplicando con TReal');
       PonReal(ObtReal*n.ObtReal)
     End;

End.
Código fuente 23: Unidad Reales04.pp con el método Multiplicación con override.
Descargar

Cuando una clase tiene un método virtual, se asume que las clases descendientes implementaran dicho método del modo adecuado. Pero a veces se desea que ese comportamiento no suceda, es decir sólo se desea sobrescribir el método de la clase padre y que cuando algún método de la clase padre ejecute, el método virtual entonces ejecute dicho método y no el sobre-escrito por la clase descendiente. En esos casos simplemente no se debe usar la palabra reservada override en el método que sobre-escribe el método virtual. Pero al no hacerlo cuando se compila la clase, el compilador nos mostrará un mensaje de advertencia en ingles: “Warning: An inherited method is hidden by … ”, que en español sería: “Cuidado: Un método heredado es escondido por ...”. Si queremos que no aparezca ese mensaje entonces el método que sobre-escribe el método virtual, se le debe colocar la palabra reservada reintroduce.


Última revisión: 28/10/2013.



SIGUIENTE
SIGUIENTE
SIGUIENTE


 
‒ Comentarios y sugerencias.

Agradezco de antemano, todo comentario, sugerencia, y donativo a través de , que ayude a mejorar los contenidos educativos de Conoce 3000. Además, cualquier pregunta o duda que tengas lo puedes hacer por este medio. Pero, todo contenido que pueda resultar ofensivo, malicioso, racista, sexista, discriminatorio, obsceno, vulgar será eliminado. Para clases particulares contactame por whatsapp al 📲 (+51) 999 264 073








PORTADA |  INTERESANTE |  APUNTES |  LIBROS |  GALERIA


Creative Commons License


Todos los textos, imágenes y videos de Conoce3000 estan colocados bajo una licencia : Creative Commons Reconocimiento-NoComercial 3.0 Unported License.