📄 ch05.htm
字号:
are really simple. They do two wonderful things:
<DL>
<DD><B>1.</B> Pop up error messages automatically.<BR>
<BR>
<B>2.</B> Help you avoid accidentally executing any sensitive code after an error
occurs.
</DL>
<P>If you
are confused by an exception, try asking these two questions:
<DL>
<DD><B>1.</B> What error is being reported for me automatically?<BR>
<BR>
<B>2.</B> What sensitive code is or can be protected by this exception?
</DL>
<P>In the preceding
examples, the answer to the first question is this: either an
<TT>EDivByZero</TT> or <TT>EConvertError</TT> message is being reported automatically,
without my necessarily having to do any work. The answer to the second question is
that a call to
<TT>ShowMessage</TT> is being protected. Therefore, <TT>ShowMessage</TT>
will only be called when it has valid data to show the user.</P>
<P>That's it! If you can grasp those two simple concepts, you know the most important
facts about exceptions. At
their core, exceptions are very simple and very useful.</P>
<P>Given the extreme simplicity and extraordinary benefits associated with this subject,
there is only one big question left: Why doesn't everyone use exceptions all the
time? Why do so many
people regard this simple and helpful tool as something rather
advanced and murky?</P>
<P>The biggest impediment to the acceptance of exceptions is simply that people haven't
yet gotten in the habit of wrapping their entire program inside a
<TT>try..catch</TT>
block. If you don't take that one step, exceptions can be a minefield that might
cause your program to shut down unexpectedly. However, if you do wrap your whole
program in a well-constructed <TT>try..catch</TT> block, this tool
will do an incredible
amount of good work for you with little effort on your part.</P>
<P>One of the great benefits of BCB is that all standard BCB programs automatically
exist inside a well-constructed <TT>try..catch</TT> block. (Console applications
don't necessarily have this same benefit.) Furthermore, the entire VCL, and most
of the routines that support it, also make good use of exceptions. For instance,
the <TT>StrToInt</TT> function you saw earlier throws its own exceptions. But I am
getting ahead of myself, because there is more territory to cover before talking
about raising your own exceptions.
<DL>
<DT></DT>
</DL>
<BLOCKQUOTE>
<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>It's important to understand that
you should not use exceptions indiscriminately. There is a difference between wrapping
a program in a <TT>try..catch</TT> block and filling it up with thousands of <TT>try..catch</TT>
blocks. There is some overhead involved in this process, so you
should use it with
a degree of discretion.
<HR>
</BLOCKQUOTE>
<P>The main point is to understand that exceptions are at heart very simple. Furthermore,
they exist primarily to make your life as a programmer considerably simpler.
<H3><A
NAME="Heading16"></A><FONT COLOR="#000077">Throwing Exceptions</FONT></H3>
<P>I want this part of the book to focus primarily on what BCB and the VCL bring
to standard exception-handling practice. However, it might be helpful to show a few
bits of
syntax that highlight some of the particular features of C++ exception handling.</P>
<P>Consider the SimpleExcept program (distinct from the SIMPEXP program shown previously)
found in Listing 5.2. This program highlights some of the basic facts about
exceptions
in C++. For an in-depth discussion of this subject, you should turn to a book on
the C++ language. The main form for the SimpleExcept program is shown in Figure 5.4.<BR>
<BR>
<A NAME="Heading17"></A><A HREF="05ebu04.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/05/05ebu04.jpg">FIGURE
5.4.</A><FONT COLOR="#000077">
</FONT><I>The SimpleExcept program raises many different kinds of exceptions.</I>
<H3 ALIGN="CENTER"></H3>
<P><A NAME="Heading18"></A><FONT COLOR="#000077"><B>Listing 5.2. The SimpleExcept
program shows a few basic
features of C++ exception-handling syntax.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// File: Main.cpp
// Project: SimpleExcept
// Copyright (c) 1997 by Charlie Calvert
/*
This code provides a few very
simple examples of basic
exception syntax.
*/
#include <vcl\vcl.h>
#pragma hdrstop
#include "Main.h"
#pragma resource "*.dfm"
TForm1 *Form1;
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
void
__fastcall TForm1::IntegerExecptBtnClick(TObject *Sender)
{
try
{
throw 23;
}
catch(int ErrorCode)
{
ShowMessage(ErrorCode);
}
}
void __fastcall TForm1::ExceptionClassBtnClick(TObject *Sender)
{
try
{
int i =
StrToInt("Sam");
}
catch(Exception &A)
{
ShowMessage("Info: " + A.Message);
}
}
void __fastcall TForm1::MultiCatchBtnClick(TObject *Sender)
{
try
{
int i = StrToInt("Sam");
}
catch(int ErrorCode)
{
ShowMessage("int: " + ErrorCode);
}
catch (WORD Sam)
{
ShowMessage("WORD: " + AnsiString(Sam));
}
catch(Exception &A)
{
ShowMessage("Exception: " +
A.Message);
}
catch(EConvertError &B)
{
ShowMessage("EConvertError: " + B.Message);
}
catch(EDatabaseError &C)
{
ShowMessage(C.Message);
}
}
void __fastcall TForm1::GenericCatchBtnClick(TObject
*Sender)
{
try
{
StrToInt("Sam");
}
catch (...)
{
ShowMessage("Something went wrong");
}
}
void __fastcall TForm1::GenericCatchIIBtnClick(TObject *Sender)
{
try
{
throw 12;
}
catch(EExternalException &E)
{
ShowMessage(E.Message);
}
}
</FONT></PRE>
<P>This very simple-minded program shows some of the things you can do with exceptions
in C++.</P>
<P>Here is a very simple-minded way to throw an exception:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::IntegerExecptBtnClick(TObject *Sender)
{
try
{
throw 23;
}
catch(int ErrorCode)
{
ShowMessage(ErrorCode);
}
}
</FONT></PRE>
<P>The <TT>throw</TT> statement shown here
causes an exception to be thrown. The
<TT>catch</TT> statement catches the error. Needless to say, the variable <TT>ErrorCode</TT>
will be set to the integer value thrown during the exception, which is <TT>23</TT>.</P>
<P>The problem with this example
is that it is so stripped-down as to appear a bit
mysterious. The first point to grasp when looking at this code is that exceptions
are not caused by errors--they are caused by using the <TT>throw</TT> keyword. When
you use exceptions, the errors that
occur are still the same old boring errors that
C++ programmers have been looking at for years. The only difference here is that
after the exception occurs, you can notify the user of your routine or object that
something has gone wrong by using the
keyword <TT>throw</TT>.</P>
<P>The simplest type of object you can throw is of type <TT>int</TT>, as shown here.
Of course, as you have already seen, it is usually more helpful to throw an object
rather than a simple integer. The advantage, of course,
is that objects can speak
to you and can be queried, while integers are a bit mute and faceless.</P>
<P>Compare the previous <TT>IntegerExceptionButtonClick</TT> with this method:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall
TForm1::ExceptionClassBtnClick(TObject *Sender)
{
try
{
int i = StrToInt("Sam");
}
catch(Exception &A)
{
ShowMessage("Info: " + A.Message);
}
}
</FONT></PRE>
<P>Code inside of <TT>StrToInt</TT>
throws an exception if an error occurs. If it
did not explicitly use the <TT>throw</TT> keyword (or at least its Pascal equivalent),
the exception would not occur. There is nothing mysterious about exceptions; they
occur because someone used a
<TT>throw</TT> expression in their code.</P>
<P>You have seen that you can pass different types of variables to a <TT>catch</TT>
statement:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::MultiCatchBtnClick(TObject *Sender)
{
try
{
int i = StrToInt("Sam");
}
catch(int ErrorCode)
{
ShowMessage("int: " + ErrorCode);
}
catch (WORD Sam)
{
ShowMessage("WORD: " + AnsiString("Sam"));
}
catch(Exception &A)
{
ShowMessage("Exception: " + A.Message);
}
catch(EConvertError &B)
{
ShowMessage("EConvertError: " + B.Message);
}
catch(EDatabaseError &C)
{
ShowMessage(C.Message);
}
}
</FONT></PRE>
<P>This code is loaded down with a series of <TT>catch</TT> statements:</P>
<PRE><FONT COLOR="#0066FF">catch(int ErrorCode)
catch (WORD Sam)
catch(Exception &A)
catch(EConvertError &B)
catch(EDatabaseError &C)
</FONT></PRE>
<P>The
question is which statement, or statements, will be called?</P>
<P>The first part of the answer is that only one <TT>catch</TT> statement will be
called unless you rethrow the error. I will talk about reraising errors later in
the chapter. The second
half of the question, however, still remains. Which statement
will execute?</P>
<P>As you know, the error which occurs in this program is of type <TT>EConvertError</TT>:</P>
<PRE><FONT COLOR="#0066FF">int i = StrToInt("Sam");
</FONT></PRE>
<P>Given the nature of the error, it should be obvious that neither of the first
two options will be executed. The object thrown is not of type <TT>int</TT>, and
it is not of type <TT>WORD</TT>. It therefore will bypass these two <TT>catch</TT>
statements with nary a nod.</P>
<P>You might think, however, that the code would also skip the <TT>Exception</TT>
<TT>catch</TT> block and go directly to the <TT>EConvertError</TT> exception. This
is not what happens. Instead, the <TT>Exception</TT>
<TT>catch</TT> block is executed
because the rules of polymorphism dictate that an <TT>EConvertError</TT> can be assigned
to one of its parent objects. As you saw earlier, <TT>EConvertError</TT> is a child
of <TT>Exception</TT>.</P>
<P>Given this
information, the logical way to arrange the code in this method is
as follows:</P>
<PRE><FONT COLOR="#0066FF">catch(int ErrorCode)
catch (WORD Sam)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -