19
L U I S F E R N A N D O E S P I N O S A C O C I A N 140 6 6 . . T T r r a a t t a a m m e e n n t t o o d d e e E E x x c c e e ç ç õ õ e e s s As exceções são situações anómalas que requerem de um tratamento especial e não tem porque ser consideradas como erros. Ao conseguir dominar toda a programação a qualidade das aplicações que se desenvolvme aumenta consideravelmente. O funcionamento geral do mecanismo de emissão e tratamento das exceções é o seguinte: 1. Existe um método que invoca a execução de outro. 2. O método mais interno se encontra em uma situação que pode ser considerada como excepcional. Portanto emite uma exceção. 3. Neste momento o termina a execução do método mais interno e se retorna imediatamente ao método invocador. 4. O método invocador deve capturar a exceção e tratá-la. Parte do tratamento da exceção pode ser voltar a emití-la ao método que a invocou. A correta programação das exceções significa desenhar os algoritmos pensando unicamente na forma habitual em que se deve executar, manipulando as situações extraordinárias à parte. Desta forma se consegue um desenho muito mais estuturado, legível, robusto e fácil de manter. EXEMPLO ALOCAÇÃO DINÂMICA DE MEMÓRIA Quando se solicita a alocação de memória do sistema, é habitual que exista suficiente e que náo haja nenhum problema. Mas se for necessário realizar uma aplicação robusta deve-se levar em conta a eventualidade de que dita memória não seja concedida o qual pode complicar enormemente o algoritmo mais simples. Veja a seguir uma função escrita na linguagem C que simplesmente tenta alocar memória de forma dinâmica para três números inteiros: #include <stdlib.h> #include <stdio.h> //--------------------------------------------------------------------------- void SemExecoes(void); //--------------------------------------------------------------------------- void main(void) {

06-Excecoes-C++BuilderV10

Embed Size (px)

DESCRIPTION

A correta programação das exceções significa desenhar os algoritmos pensando unicamente na forma habitual em que se deve executar, manipulando as situações extraordinárias à parte. Desta forma se consegue um desenho muito mais estuturado, legível, robusto e fácil de manter. 3. Neste momento o termina a execução do método mais interno e se retorna imediatamente ao método invocador. 140

Citation preview

Page 1: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

140

66.. TTrraattaammeennttoo ddee EExxcceeççõõeess As exceções são situações anómalas que requerem de um tratamento

especial e não tem porque ser consideradas como erros. Ao conseguir dominar

toda a programação a qualidade das aplicações que se desenvolvme aumenta

consideravelmente.

O funcionamento geral do mecanismo de emissão e tratamento das

exceções é o seguinte:

1. Existe um método que invoca a execução de outro.

2. O método mais interno se encontra em uma situação que pode ser

considerada como excepcional. Portanto emite uma exceção.

3. Neste momento o termina a execução do método mais interno e se

retorna imediatamente ao método invocador.

4. O método invocador deve capturar a exceção e tratá-la. Parte do

tratamento da exceção pode ser voltar a emití-la ao método que a

invocou.

A correta programação das exceções significa desenhar os algoritmos

pensando unicamente na forma habitual em que se deve executar, manipulando

as situações extraordinárias à parte. Desta forma se consegue um desenho muito

mais estuturado, legível, robusto e fácil de manter.

EEXXEEMMPPLLOO –– AALLOOCCAAÇÇÃÃOO DDIINNÂÂMMIICCAA DDEE MMEEMMÓÓRRIIAA Quando se solicita a alocação de memória do sistema, é habitual que

exista suficiente e que náo haja nenhum problema. Mas se for necessário realizar

uma aplicação robusta deve-se levar em conta a eventualidade de que dita

memória não seja concedida o qual pode complicar enormemente o algoritmo

mais simples.

Veja a seguir uma função escrita na linguagem C que simplesmente tenta

alocar memória de forma dinâmica para três números inteiros:

#include <stdlib.h> #include <stdio.h> //--------------------------------------------------------------------------- void SemExecoes(void); //--------------------------------------------------------------------------- void main(void) {

Page 2: 06-Excecoes-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

141

SemExecoes(); } //--------------------------------------------------------------------------- void SemExecoes(void){ int *p1, *p2, *p3; p1 = (int*) malloc(sizeof(int)); if (p1 == NULL){ printf("Não há memória suficiente"); abort(); } if (p2 == NULL){ printf("Não há memória suficiente"); abort(); } if (p3 == NULL){ printf("Não há memória suficiente"); abort(); } } //---------------------------------------------------------------------------

Programando em C++ e fazendo uso das exeções:

#include <stdlib.h> #include <stdio.h> //--------------------------------------------------------------------------- void ComExecoes(void); //--------------------------------------------------------------------------- void main(void){ ComExecoes(); } //--------------------------------------------------------------------------- void ComExecoes(void){ int *p1, *p2, *p3; try { p1 = new int; // Comportamento normal. p2 = new int; p3 = new int; } catch(...){ // Comportamento excepcional. printf("Não há memória suficiente"); abort(); } } //---------------------------------------------------------------------------

A norma ANSI C++ especifica que se uma instrução new falhar (porque

não há memória disponível) deve ser emitida uma exceção bad_alloc. As

instruções que podem provocar a emissão de uma exeção ou zona crítica se

englobam dentro de um bloco try{}. Se alguma das instruções do bloco try{}

provocarem uma exeção, o fluxo do programa vai até o final do bloco buscando

um bloco catch(...){} que capture a exeção (se não a encontrar, o programa

termina). Neste caso, a instrução catch(...){} captura qualquer exeção, e em

particular, a exeção bad_alloc. O tratamento se efetua neste caso é a

apresentaçào de uma mensagem de erro e se termina a execução do programa.

Page 3: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

142

EEXXEEMMPPLLOO –– AALLOOCCAAÇÇÃÃOO DDIIVVIISSÃÃOO PPOORR ZZEERROO O seguinte programa lê dois valores e calcula o quociente entre ambos. Se

o divisor for zero tenta-se fazer a divisão e o programa emite uma exeção de

divisão por zero (EZeroDivide).

Para executar este exemplo crier um novo projeto com a opção de menu

File + New Application. Usando o Gerenciador de Projetos remova os arquivos da

Unit1 com o botão direito do mouse encima da mesma, selecionar Remove from

project.

Dentro do arquivo Project1.cpp apague tudo o que estiver ali e insira o

seguinte código:

//---------------------------------------------------------------- #include <vcl.h> #pragma hdrstop //---------------------------------------------------------------- WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { AnsiString Valor; float Dividendo, Divisor, Quociente; // Lê dados de entrada: dividendo e divisor Valor = InputBox ("Divisão", "Dividendo", ""); // Lê o dividendo e Dividendo = StrToFloat (Valor); // converte-o em float. Valor = InputBox ("Divisão", "Divisor", ""); // Lê o divisor e Divisor = StrToFloat (Valor); // converteo em float. // Calcula quociente. Zona critica: perigo se Divisor for igual a 0 Quociente = Dividendo / Divisor; // Mostrar o resultado ShowMessage ("Quociente = " + AnsiString(Quociente)); return (0); } //----------------------------------------------------------------

Page 4: 06-Excecoes-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

143

Execute o projeto, e quando aparecer a janela de salvar, salve como

zero.bpr.

Depois de salvo, o projeto é executado abrindo duas janelas de inserção

para os valores de dividendo e divisor e uma janela de apresentação do resultado.

O programa não supõe o tratamento da exceção no caso do usuário inserir

o valor 0 no divisor. Se isto porventura venha a acontecer se produzirá uma

exeção, e por não ser tratada pelo programa, o entorno de programação (IDE do

Builder C++) se encarregará dela.

Page 5: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

144

Figura 6-1 - Janela de erro que surge devido a uma exeção EzeroDivide não tratada.

Se for executado diretamente o arquivo executável for a do ambiente de

programação, o sistema operacional irá reagir ao erro da seguinte forma:

Se o usuário pressionar o botão Debug aparece a seguinte janela horrível

(caso ele tenha instalado o Bulder C++, Visual C++ ou algum outro software de

depuração de baixo nível):

Page 6: 06-Excecoes-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

145

O Windows XP pergunta ao usuário se quiser enviar os dados do erro para

a Microsoft. Se ele quiser ver o que será enviado, ele pode selecionar a opção

click here.

Page 7: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

146

Resumindo em poucas palavras, fica horrível para o usuário ter que se

defrontar com este tipo de problema, mais ainda se ele pagou pelo software. Um

errinho imbecil deste tipo (feito pelo próprio usuário) porém não protegido pelo

programador, pode fazer que um programa hiper complexo seja tratado como um

programa “porcaria” pelo usuário (injustamente, é claro).

Para proteger a instrução crítica, capturar e tratar a exeção, instroduzir a

seguinte modificação:

try{ Quociente = Dividendo / Divisor; ShowMessage ("Quociente = " + AnsiString(Quociente)); } catch (...) { ShowMessage ("O divisor não pode ser zero."); Application->Terminate(); }

Para ceder o controle do gerenciamento de exeções a nosso programa deve

se desabilitar a opção pela qual o entorno integrado gerencia as interrupções e

indicar que serão gerenciadas pelo programa. Para isto, selecionar a opção de

menu Tools + Debugger Options e na aba OS Exceptions modificar de acordo com

a Figura 6-2 (retirar a seleção do item Integrated debugging no canto inferior

esquerdo).

Figura 6-2 – Janela Debugger Options

Page 8: 06-Excecoes-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

147

Assim, é indicado ao depurador do C++Builder que o nosso programa se

encarregará de gerenciar as exeções C++ que possam chegar a ocorrer. Agora ao

executar o programa e introduzindo o valor 0 como divisor aparecerá a janela a

seguir:

Depois disto, o programa sera encerrado.

66..11.. EEmmiissssããoo ddee EExxcceeççõõeess A emissão de uma exceção se realiza usando a função throww(). Quando

se emite uma exceção, em realidade o que se faz é criar um objeto de uma classe

que se indique a throw() que será a própria exceção em si. Costuma ser bastante

útil criar classes de exceções próprias para controlar as situações anómalas de

nossa aplicação. Para ilustrar a emissão de exceções, usaremos o projeto POOEx.

Em ObjGraph.h coloque o seguinte código antes da declaração da classe

TObjGraf:

//--------------------------------------------------------------------------- // Definição da classe EForaFaixa // Classe de exceção por ficar “fora da faixa” de visualização: // sair dos limites do objeto PaintBox ao calcular // as novas coordenadas do desenho da bola. class EForaFaixa{}; //---------------------------------------------------------------------------

Agora podem ser emitidas exceções da seguinte maneira:

throw EForaFaixa();

Mesmo que as exeções sejam classes, em C++ Builder existe a convenção

de que o seu nome comece pela letra E e não por T como o resto das classes.

Mesmo que no exemplo anterior, a classe criada para a exceção não tem nenhum

membro (propriedades e métodos), esses poderão ser adicionados. Eles servirão

para poder incorporar informações no objeto de exceção sobre a situação em que

foi produzida a exceção e poderão ser usados pela seção de código que as trate.

Por exemplo, se houver um método que emite uma exceção por falta de

memória pode ser interessante incorporar uma propriedade que indique qual foi

a máximo tamanho de memória disponível quando foi emitida a exceção.

Page 9: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

148

66..22.. EEssppeecciiffiiccaaççããoo ddee EExxcceeççõõeess A linguagem C++ conta com uma característica denominada especificação

de exceções, que serve para enumerar, em uma declaração, as exceções que

pode emitir um determinado método. Se quisermos que um método possa emitir

um determinado tipo de exceção deve se especificar dessa forma. Alterar como

segue em ObjGraf.h, dentro da classe TObjGraf:

//--------------------------------------------------------------------------- // Definição da classe TObjGraf //--------------------------------------------------------------------------- class TObjGraf { private: unsigned int unFX; // foram alterados os nomes unsigned int unFY; // de unX para unFX e unY para unFY void SetX(unsigned int _X) throw (EForaFaixa); // Se houver algum // problema é criado void SetY(unsigned int _Y) throw (EForaFaixa); // um objeto da classe // EForaFaixa virtual int GetLargura (void) = 0; // Método virtual puro virtual int GetAltura (void) = 0; // Método virtual puro

Em ObjGraf.cpp:

//--------------------------------------------------------------------------- // Funções de escrita das propriedades virtuais unX e unY void TObjGraf::SetX(unsigned int _X) throw (EForaFaixa) { if (_X < 0){ // Coordenada negativa unFX = 0; // Ajustar para a margem esquerda throw EForaFaixa(); // Emitir uma exeção } else{ if (_X > (PaintBox->Width - unLargo)){ // Alta demais unFX = PaintBox->Width - unLargo;// Ajustar para a margem // direita throw EForaFaixa(); // Emitir uma exeção } else{ unFX = _X; // Correto: escrever sem modificar } } } //--------------------------------------------------------------------------- void TObjGraf::SetY(unsigned int _Y) throw (EForaFaixa) { if (_Y < 0){ // Coordenada negativa unFY = 0; // Ajustar a margem superior throw EForaFaixa(); // Emitir uma exeção } else{ if (_Y > (PaintBox->Height - unAlto)){ // alto demais unFY = PaintBox->Height - unAlto;// Ajustar para a margem //inferior throw EForaFaixa(); // Emitir uma exeção } else{ unFY = _Y; // Correto: escrever sem modificar } }

Page 10: 06-Excecoes-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

149

} //---------------------------------------------------------------------------

66..33.. CCaappttuurraa ddee EExxcceeççõõeess O bloco suscetível de produzir alguma exceção (zona crítica) se coloca

dentro de um bloco try{}, e a captura (discriminação da exceção que foi

produzida) se efetua em uma instrução catch e o seu processamento se realiza a

continuação no bloco catch.

try{ <bloco de instruções críticas> } catch(<tipo exceção1> <variável>){ <manipulador1> } catch(<tipo exceção2> <variáve2>){ <manipulador2> } ...

Pode se especificar tantos blocos catch para um bloco try quando forem

necessários. No momento que ocorra uma exceção se executará o bloco catch

cuja classe concorde com a da exceção. Se for expecificado catch(...) se

capturará qualquer exceção.

A exceção não tem por que ser emitida explicitamente no bloco try senão

como conseqüência da execução de uma função chamada dentro desse bloco.

Alterar em ObjGraf.cpp:

//--------------------------------------------------------------------------- void TBola::Mover (void) { Apagar (); try{ unX += FDirX * Velocidade; } catch(EForaFaixa){ FDirX = -FDirX; } try{ unY += FDirY * Velocidade; } catch(EForaFaixa){ FDirY = -FDirY; } Mostrar (); } //---------------------------------------------------------------------------

Neste exemplo, a instrução crítica:

unX += FDirX * Velocidade;

traduzida em:

Page 11: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

150

unX = unX + FDirX * Velocidade;

e como unX é uma propriedade virtual, na realidade trata-se de fazer:

SetX(unX + FDirX * Velocidade)

Onde se observa que é o método SetX() quem pode provocar a emissão da

exceção.

Em UPrincipal.cpp colocar a seguinte declaração global:

TBola *Bola;

Modificar as funções FormCreate() e FormDestroy() para que fiquem da

seguinte maneira:

//--------------------------------------------------------------------------- void __fastcall TFrmPrincipal::FormCreate(TObject *Sender) { Bola = new TBola (PaintBox, clYellow, 120, 70, 25); } //--------------------------------------------------------------------------- void __fastcall TFrmPrincipal::FormDestroy(TObject *Sender) { delete Bola; } //---------------------------------------------------------------------------

Eliminar o gerenciador para o evento OnPaint do componente PaintBox

(apagando o corpo da função tão somente).

Adicionar ao FrmPrincipal um objeto TTimer (aba System) e fixar a

propriedade Interval = 100.

No evento OnTimer colocar:

//--------------------------------------------------------------------------- void __fastcall TFrmPrincipal::Timer1Timer(TObject *Sender) { Bola->Mover(); } //---------------------------------------------------------------------------

Neste ponto o projeto deve estar como mostra a Figura 6-310.

Figura 6-3 - Dois instantes de movimento da bola.

10 O entorno deve estar configurado para que o programa gerencie as exceções e não o entorno de programação. Se não estiver assim configurado, selecionar Tools + Debugger Options, abrir a aba OS Exceptions e configurar como mostra a Figura 6-2.

Page 12: 06-Excecoes-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

151

Executando o programa, quando a bola chegar ao limite do componente

TPaintBox haverá a emissão de uma exceção como mostra a figura a seguir.

O entorno deve estar configurado para que o programa gerencie as

exceções e não o entorno de programação. Se não estiver assim configurado,

selecionar Tools + Debugger Options, abrir a aba OS Exceptions e configurar como

mostra a Figura 6-2.

66..44.. EExxcceeççõõeess nnããoo TTrraattaaddaass Se uma exceção que foi emitida não encontrar um manipulador apropriado,

será chamada a função terminate(), que por default realiza um abort().

Entretanto pode se definir uma função própria terminate() com set_terminate().

Uma coisa parecida ocorre se um método emite uma exceção de um tipo

não listado na especificação de exceções, então se chama a função unexpected()

que por default chama a função terminate(). Da mesma maneira que com

terminate() pode se definir a função unexpected() própria com set_unexpected().

Page 13: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

152

66..55.. EExxcceeççõõeess ddaa VVCCLL Quando se utilizam componentes da VCL as aplicações é necessário

compreender o mecanismo de tratamento de exceções da VCL. O motivo é que as

exceções estão integradas em numerosas classes e se emitem automaticamente

quando se apresenta uma situação inesperada. Se não se realiza um tratamento

da exceção , a VCL levará a cabo um tratamento default. Normalmente aparece

uma mensagem que descreve o tipo de erro que foi produzido.

66..55..11.. CCllaasssseess ddee EExxcceeççõõeess O C++ Builder incorpora um extenso conjunto de classes de exceção

integradas que permitem tratar automaticamente os erros de divisão por zero, de

entrada/saída de arquivos, conversões de tipos e muitas outras situações

anómalas. Todas as classes de exceção da VCL derivam de um objeto raíz

chamado Exception, que encapsula as propriedades e métodos fundamentais

para todas as exceções por parte das aplicações.

66..55..22.. TTrraattaammeennttoo ddee EExxcceeççõõeess ddaa VVCCLL As exceções de tipo VCL, assim como todas as classes da VCL, devem

estar localizadas no heap (criação dinâmica) e por isso deve se ter em conta o

seguinte:

� As classes de exceção do tipo VCL somente podem ser capturadas por ponteiro ou

por referência (preferencialmente).

� As exceções do tipo VCL devem ser emitidas com sintaxe “por valor”.

As exceções podem ser passadas a um bloco catch que toma um

parämetro do tipo Exception. Utilizar a seguinte sintaxe para capturar as

exceções da VCL:

catch(const exception_class & exception_variable)

Se especifica a classe de exceção que se deseja capturar e se proporciona

uma variável por meio da qual se faz referência à exceção. Por exemplo:

//-------------------------------------------------------- #include <vcl.h> #pragma hdrstop //-------------------------------------------------------- WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { try { throw Exception("Minha exceção VCL"); }

Page 14: 06-Excecoes-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

153

catch (const Exception & E) { ShowMessage("Classe da exceção capturada: " + AnsiString(E.ClassName()) + "\nMessage: " + E.Message); } return (0); } //--------------------------------------------------------

A sentença throw do exemplo anterior cria uma instância da classe

Exception e chama o seu construtor. Todas as exceções que descendem de

Exception contam com uma mensagemque se pode apresentar na tela, passar aos

construtores e serem recuperadas mediante a propriedade Message. O resultado

do programa anterior é o mostrado na Figura 6-4.

Figura 6-4 - Ejemplo de lanzamiento y captura de excepción VCL.

66..55..33.. CCllaasssseess ddee EExxcceeççããoo TTiippiiccaass Mesmo que as exeções não necessariamente indiquem um erro na

execução de uma aplicação, as exceções da VCL costumam ser erros sim. Veja a

seguir uma lista das classes de exceção mais utilizadas em C++ Builder.

Classe Descrição

EAccessViolation Erro de acceso à memoria.

EDatabaseError Especifica um erro de aceso à base de dados.

EDBEditError Dados incompatíveis com uma máscara especificada.

EDivByZero

EZeroDivide

Captura erros de divisão por zero (para divisão inteira e real,

respectivamente).

EInOutError Representa um erro de E/S de arquivo.

EInvalidPointer Operações não válidas com ponteiros.

EPrinterError Indica um erro de impressão.

Mesmo que todas essas classes funcionem da mesma maneira, cada uma

delas possui particularidades derivadas da exceção concreta que elas indicam.

EEXXEEMMPPLLOO –– DDIIVVIISSÃÃOO PPOORR ZZEERROO [[22]] O seguinte programa é uma ampliação do projeto de divisão anteriormente

colocado. Neste exemplo se discriminam distintas exceções.

//--------------------------------------------------------------------- #include <vcl.h>

Page 15: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

154

#pragma hdrstop //--------------------------------------------------------------------- WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { AnsiString Valor; float Dividendo, Divisor, Quociente; float sigo = true; while (sigo) { try { // Ler e converter dividendo Valor = InputBox ("Divisão", "Dividendo", ""); Dividendo = StrToFloat (Valor); if (Dividendo == 0) { sigo = false; } else { // Ler e converter divisor Valor =InputBox ("Divisão", "Divisor", ""); Divisor = StrToFloat (Valor); Quociente = (Dividendo / Divisor); ShowMessage ("Quociente = " + AnsiString(Quociente)); } } // try // Se captura se foi realizada uma divisão por zero. catch (EZeroDivide & ) { ShowMessage ("O divisor não pode ser zero."); } // Mais geral: se alcanza se não se captura a anterior. catch (Exception & e) { ShowMessage ("Se produziu uma exceção: " + AnsiString(e.ClassName())+ "\n " + e.Message); } } // while sigo return (0); } //---------------------------------------------------------------------

Se for tentado realizar uma divisão por zero, o resultado é o indicado na

Erro! Fonte de referência não encontrada..

Page 16: 06-Excecoes-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

155

Agora, se for introduzido um dado incorreto, a função StrToFloat() emite

uma exceção EConvertError que se captura no último bloco catch. Ver a Figura

6-5.

Figura 6-5 - Exemplo de entrada incorreta.

Mais ainda, se for produzido algum tipo de overflow também pode ser

controlado com o último bloco catch, como mostra a Figura 6-6.

(a)

(b)

Figura 6-6 - Exemplos de overflow: a) na entrada de dados e b) no cálculo do quociente.

Page 17: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

156

Para finalizar, adicionar o seguinte bloco catch entre os dois anteriores e

considerar (uma parte da) a hierarquia das classes de exceções:

TObject-->Exception-->EExternal-->EMathError-->(EZeroDivide, EOverflow, ...)

catch (EMathError & e) { ShowMessage ("Operação inválida: " + e.Message); }

(a)

(b)

Figura 6-7 - Outra maneira de capturar overflows: a) na entrada de dados e b) no cálculo do quociente.

EEXXEERRCCÍÍCCIIOO –– UUMM RREEPPRROODDUUTTOORR DDEE SSOONNSS Neste exemplo se criará uma quadro que conterá um

componente MediaPlayer que servirá para reproduzir arquivos .WAV.

Será utilizado o gerenciamento de exceções para controlar a correta

execução do programa.

O primeiro passo é criar e configurar o projeto. Para isto usar a opção File

+ New Application. Salvar em nova pasta com a opção de menu File + Save

Project As... Salvar como UPrincipal.cpp (Unit1.cpp) e Som.bpr (Project1.bpr).

A seguir, configurar o quadro para aparecer como mostra a seguinte

figura:

Page 18: 06-Excecoes-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

157

Alterar o título do quadro (Caption) para Sons e adicionar os seguintes

componentes:

� Quatro botões normais (TButton) chamados (Name): LogoffBtn, MSSoundBtn, ErrorBtn e OutrosBtn com o texto (Caption) como indicado na figura anterior.

� Um botão BitBtn para terminar o programa.

� Um controle MediaPlayer (aba System) não-visível (Visble = false).

� Um quadro de diálogo OpenDialog (aba Dialogs).

A seguir, escreveremos os gerenciadores de eventos associados à pulsação

dos botões. O gerenciamento das interrupções capturadas (exceções) será

realizada com uma função comum cujo protótipo é:

void Erro(AnsiString & name, Exception & e);

Esta função é declarada acima de todas as funções em UPrincipal.cpp. Os

gerenciadores dos eventos OnClick associados aos botões serão os seguintes:

//--------------------------------------------------------------------------- void __fastcall TForm1::LogoffBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\Windows XP Logoff Sound.wav"; try { MediaPlayer1->Open(); MediaPlayer1->Wait = true; MediaPlayer1->Play(); MediaPlayer1->Close(); } catch (Exception & e) { Erro(MediaPlayer1->FileName, e); } } //--------------------------------------------------------------------------- void __fastcall TForm1::MSSoundBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\Windows XP Startup.wav"; try { MediaPlayer1->Open(); MediaPlayer1->Wait = true; MediaPlayer1->Play(); MediaPlayer1->Close(); } catch (Exception & e) { Erro(MediaPlayer1->FileName, e);

Page 19: 06-Excecoes-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

158

} } //--------------------------------------------------------------------------- void __fastcall TForm1::ErrorBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\NaoHa.wav"; try { MediaPlayer1->Open(); MediaPlayer1->Wait = true; MediaPlayer1->Play(); MediaPlayer1->Close(); } catch (Exception & e) { Erro(MediaPlayer1->FileName, e); } } //--------------------------------------------------------------------------- void __fastcall TForm1::OutrosBtnClick(TObject *Sender) { if (OpenDialog->Execute()){ MediaPlayer1->FileName = OpenDialog->FileName; try { MediaPlayer1->Open(); MediaPlayer1->Wait = true; MediaPlayer1->Play(); MediaPlayer1->Close(); } catch (Exception & e) { Erro(MediaPlayer1->FileName, e); } } // if (OpenDialog1->Execute()) } //--------------------------------------------------------------------------- void Erro(AnsiString & name, Exception & e){ ShowMessage ("Falha na reprodução do arquivo de som: " + name + "\nExceção: " + AnsiString(e.ClassName()) + "\nDetalhes: " + AnsiString(e.Message)); } //--------------------------------------------------------------

Quando o programa é executado e for apertado o botão Erro (supõe-se que

o arquivo não existe) aparecerá a seguinte janela de mensagem: