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


11. INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS II.
11.1. EXCEPCIONES.
11. INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS II.
11.1. EXCEPCIONES.
11. INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS II.
11.1. EXCEPCIONES.

SIGUIENTE

SIGUIENTE

SIGUIENTE


‒ Excepciones.

Las excepciones son clases que se usan para manejar los errores de programación, la mayoría de las excepciones, se encuentran en la unidad sysutils. Una de las ventajas de usar excepciones, es el permitir hacer un código más ordenado para el manejo de los errores de programación, separando el flujo normal de un conjunto de instrucciones, del conjunto de instrucciones que manejan los errores de programación. Es decir, si hacemos un programa tan simple, que nos permita dividir dos números reales ingresados por teclado, y tomando en cuenta los siguiente errores de programación:

  • El usuario ingresa datos no numéricos.
  • El usuario ingresa dos ceros a dividir 0/0, una operación de punto flotante invalida.
  • El usuario intenta dividir un numero cualquiera con cero, n/0.

El programa se podría hacer del siguiente modo:


Descargar
{$codepage utf8}
{$mode objfpc}

Var a,b,c:double;	
  cada,cadb:string;
  errorA,errorB:integer;
  rpta:char;
Begin
  rpta:='S';  
  Repeat
    c:=0;
    a:=0;
    b:=0;

    Write('a=');readln(cada);
    Write('b=');readln(cadb);

    Val(cada,a,errorA);  
    Val(cadb,b,errorB); 

    if errorA<>0 then Writeln('Error datos no validos ingresados')
    else if errorB<>0 then Writeln('Error datos no validos ingresados')
    else if ((a=0)and(b=0)) then Writeln('Operacion de punto flotante invalido')
    else if b=0 then Writeln('Error division por cero')
    else c:=a/b;	  

    Writeln(c:10:10);
    Write('¿Desea continuar dividiendo?:');
    Readln(rpta)
  Until rpta in ['N','n']
End.
Código fuente 1: Manejo de errores usando if-the-else anidados.
Descargar

El tratamiento de los errores se hace a través de una serie de if/then/else anidados, que son como una serie de compuertas que verifican si los datos ingresados son correctos, en caso contrario sean correctos realizará la división.

Para hacer lo mismo usando excepciones, se debe primero incluir la unidad sysutils, y usar la estructura try/except para el manejo de excepciones. A continuación el programa de ejemplo:


Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils;

Var a,b,c:double;
    cada,cadb:string;
    rpta:char;
Begin
  rpta:='S';
  Repeat
    c:=0;
    a:=0;
    b:=0;
    try
      Write('a=');readln(cada);
      Write('b=');readln(cadb);
      a:=StrTofloat(cada);
      b:=StrTofloat(cadb);
      c:=a/b;
    except
      on EConvertError do Writeln('Error datos no validos ingresados');
      on EDivByZero do Writeln('Error division por cero');
      on EInvalidOp do Writeln('Operacion de punto flotante invalido');
    end;  
    Writeln(c:10:10);
    Write('¿Desea continuar dividiendo?:');
    Readln(rpta)	  
  Until rpta in ['N','n']
End.
Código fuente 2: Manejo de errores usando excepciones, con try-except.
Descargar

Las instrucciones, que se usan para la lectura de datos, conversión y para la división se colocan dentro del bloque try, y dentro del bloque except, se colocan las excepciones que se manejarán cuando el usuario coloque datos incorrectos al realizar la operación. Una de las ventajas de usar este modo de tratar los errores de programación, es el de tener un código claro y bastante manejable, sobre todo cuando los programas requieren de muchas comprobaciones para evitar los errores de programación.

Cada vez que se produce un error como por ejemplo la división por cero, el flujo del programa se interrumpe y se ejecuta la excepción, en este caso la excepción EdivByZero.

Toda Excepción, se debe colocar entre las palabras reservadas on y do, después del do se puede colocar también un bloque de instrucciones, que debe empezar con Begin y terminar con End y su punto y coma.

Una excepción puede tener un identificador tal como se muestra a continuación:

   on E:EConvertError do Writeln(E.Message);
   on E:EDivByZero do Writeln(E.Message);
   on E:EInvalidOp do Writeln(E.Message);

De esa manera se puede acceder a los métodos de una excepción, pero sólo dentro del bloque de instrucciones que aparecen después del do, en este ejemplo se accede a la propiedad Message de la clase correspondiente. Los identificadores, pueden ser el mismo identificador para cualquier excepción, ya que este identificador sólo se usará dentro del bloque de instrucciones después del do.

A diferencia del programa anterior en donde se usa Val para convertir la cadena de caracteres en un número, en este caso se hace uso de StrTofloat, esta función no devuelve un valor numérico cuando se produce un error, si no que se ejecuta una excepción, la excepción es EconvertError.

Para lo que viene a continuación se necesita de la siguiente unidad Complejos06.pp, esta unidad tiene la Clase TComplejo, la clase TComplejo tiene los métodos para realizar operaciones sobre números complejos, de entre ellos tenemos la división de números complejos. El siguiente programa hace uso de esta clases, para hacer una división errónea entre 0.


Descargar
{$codepage utf8}
{$mode objfpc}
Uses Complejos06,sysutils;

Var A,B:TComplejo; 
Begin
  A:=TComplejo.crear(10,4);
  B:=TComplejo.crear(0,0);
  try
    A.Division(B);
  except
   on E:EDivByZero do Writeln(E.Message);
   on E:EInvalidOp do Writeln(E.Message);
  end;
  Writeln(A.ObtCad(3))
End.
Código fuente 3: Uso de excepciones con la unidad Complejo06.pp.
Descargar

Al ejecutar el programa, este no ejecutará, las instrucciones correspondiente a EdivByZero, si no que por el contrario ejecutará las que corresponden a EInvalidOp, esto es debido a la manera en como se dividen los números complejos. Observando el código del método División de la clase TComplejo de la unidad Complejos06.pp:


Descargar
Procedure TComplejo.Division(n:TComplejo);
      var aux:double;
          PR,PI:double;
      Begin
       aux:=sqr(n.ObtReal)+sqr(n.ObtImag);
       PR:=(((ObtReal*n.ObtReal)+(ObtImag*n.ObtImag))/aux);
       PI:=(((ObtImag*n.ObtReal)-(ObtReal*n.ObtImag))/aux);
       PonReal(PR);
       PonImag(PI);
      End;
Código fuente 4: Método division que genera la excepción EInvalidOp.
Descargar

Se puede observar que lo primero que hace este método es obtener la raíz cuadrada de la parte real del divisor sumado con la raíz cuadrada de la parte imaginaria del divisor, y como el divisor es 0, entonces al intentar obtener la raíz cuadrada de 0, se ejecuta o se lanza la excepción EinvalidOp. Podemos cambiar este comportamiento, haciendo uso de la palabra reservada raise:


Descargar
Procedure TComplejo.Division(n:TComplejo);
      var aux:double;
          PR,PI:double;
      Begin	
       if (n.ObtReal=0) and (n.ObtImag=0) then
           raise EdivByZero.Create('Error division por cero');
       aux:=sqr(n.ObtReal)+sqr(n.ObtImag);
       PR:=(((ObtReal*n.ObtReal)+(ObtImag*n.ObtImag))/aux);
       PI:=(((ObtImag*n.ObtReal)-(ObtReal*n.ObtImag))/aux);	   
       PonReal(PR);	   
       PonImag(PI);	   
      End;
Código fuente 5: Método division que genera la excepción EdivByZero con el uso de raise.
Descargar

Ahora cuando ejecutemos el programa, que divide un numero complejo con 0, entonces al producirse el error se lanzará la excepción EdivByZero. Cuando creamos una excepción, debemos incluir el mensaje, ya que si no la instrucción E.Message del programa no mostrará el mensaje. El siguiente archivo Complejos07.pp, tiene la versión modificada del método Division.

No siempre podemos predecir con certeza, que error puede ocurrir en determinado momento en la ejecución del programa, si por ejemplo no supiéramos que la división 0/0 generá la excepción EinvalidOp, entonces para poder saberlo, debemos de capturar de algún modo la excepción desconocida. Esto se puede hacer con la siguiente instrucción:

   on E: Exception do Writeln(E.classname,'::',E.Message);

En donde el identificador E es de la clase Exception, el método classname nos da el nombre de la excepción, y como una excepción es una clase este método en realidad nos da el nombre de la clase. Classname es un método que toda clase tiene por defecto o por omisión.

El método message nos da el mensaje de error, este método es virtual y sólo pertenece a la clase Exception. Toda excepción, es en realidad descendiente de la clase Exception. Asumiendo que no sabemos que la división 0/0 genera la excepción EinvalidOp, se modifico el programa anterior, a modo de ejemplo:


Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils;

Var a,b,c:double;
    cada,cadb:string;
    rpta:char;
Begin
  rpta:='S';
  Repeat
    c:=0;
    a:=0;
    b:=0;
    try
    Write('a=');readln(cada);
    Write('b=');readln(cadb);
    a:=StrTofloat(cada);
    b:=StrTofloat(cadb);
    c:=a/b;
    except
      on EConvertError do Writeln('Error datos no validos ingresados');
      on EDivByZero do Writeln('Error division por cero');
      on E: Exception do Writeln(E.classname,'::',E.Message);
    end;  
    Writeln(c:10:10);
    Write('¿Desea continuar dividiendo?:');
    Readln(rpta)
  Until rpta in ['N','n']
End.
Código fuente 6: Uso de Exception, para saber sobre un error en el programa.
Descargar

Al ejecutar el programa, cada vez que ingresemos una división 0/0, nos mostrará el nombre de la clase (EinvalidOp) y el mensaje de error de la excepción generada.

Una vez conocido la excepción, el programa se debe modificar para que de un tratamiento, más adecuado a la excepción. Es importante entender que es recomendable usar:

   on E: Exception do Writeln(E.classname,'::',E.Message);

sólo para saber de algún error que no hayamos podido predecir. Si sabemos del error no es necesario usar la clase Exception.

El último bloque para el manejo de las excepcione es el bloque try/finally, a diferencia de lo que hemos visto este tiene la particularidad de que si ocurre un error el programa se detiene y ejecuta lo que se encuentra en el bloque finally, y si en caso no ocurre un error, el programa no se detiene pero ejecuta lo que esta en el bloque finally. Es decir, así haya o no haya un error lo que se encuentra en el bloque finally siempre se ejecuta.

Este bloque es muy útil para realizar tares de limpieza en la manipulación de archivos, liberación de memoria cuando se trabaja con punteros o se destruyen objetos. Veamos el siguiente ejemplo:


Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils;

Var Arch:File of longint;
    NombreArch:Unicodestring;
    j,i:longint;
Begin
  NombreArch:='numeros.dat';
  Assign(Arch,NombreArch);
  Rewrite(Arch);
  j:=0;
  try
    for i:= 1000 downto 0 do 
     Begin
      j:=j + j div i; //al llegar a cero crea un error
      Write(Arch,j);
     End;
  finally
   Writeln('Siempre se cierra el archivo');   
   Close(Arch)
  End;  
End.
Código fuente 7: Manejo de errores usando excepciones con try-finally.
Descargar

En este ejemplo, dentro del bloque try se realiza un cálculo erróneo ocasionando una división con cero, lo que hará que se ejecute lo que se encuentre en el bloque finally, asumiendo que no ocurra el error siempre se ejecutará lo que se encuentra dentro del bloque finally. Es decir el programa siempre cerrará el archivo, así se produzca o no un error. El inconveniente que presenta la estructura try/finally, es que no permite manejar o gestionar las excepciones. La solución si queremos gestionar las excepciones, es usar los bloques try/except y try/finally anidados, como se muestra en el siguiente ejemplo:


Descargar
{$codepage utf8}
{$mode objfpc}
Uses sysutils;

Var Arch:File of longint;
    NombreArch:Unicodestring;
    j,i:longint;
Begin
  NombreArch:='numeros.dat';    
  Assign(Arch,NombreArch);
  Rewrite(Arch);
  j:=0;  
  try      
   try
    for i:= 1000 downto 0 do 
     Begin
      j:=j + j div i; //al llegar a cero crea un error
      Write(Arch,j); 
     End;
   except
     on EDivByZero do Writeln('Error division por cero');
   end;   
  finally
   Writeln('Siempre se cierra el archivo');   
   Close(Arch)
  End;  
End.
Código fuente 8: Uso de try/except y try/finally anidados.
Descargar




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.