📄 ch05.htm
字号:
catch(EConvertError &B)
catch(EDatabaseError &C)
catch(Exception &A)
</FONT></PRE>
<P>This code will first try to find a match in the first four <TT>catch</TT> statements,
and if that fails, it will come to rest in the <TT>Exception</TT> <TT>catch</TT>
statement, because that is a generic resting place for VCL exceptions.</P>
<P>Of
course, not all exceptions are VCL exceptions. For instance, exceptions of
type <TT>WORD</TT> or <TT>int</TT> are not VCL exceptions.</P>
<P>There are some things you can do to spread a really wide net for catching exceptions.
The following examples
show how to use the ellipses syntax in a <TT>catch</TT> expression
to trap generic exceptions of any type:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::GenericCatchBtnClick(TObject *Sender)
{
try
{
StrToInt("Sam");
}
catch (...)
{
ShowMessage("Something went wrong");
}
}
</FONT></PRE>
<P>This <TT>catch</TT> block will trap whatever exception comes its way. It is the
broadest and safest possible net, but it is also not very helpful when it
comes to
telling you exactly what went wrong. To flag down at least some additional information,
you can include <TT>except.h</TT> in your program and use the following syntax:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall
TForm1::GenericCatchBtnClick(TObject *Sender)
{
try
{
throw 12;
}
catch (...)
{
ShowMessage("Something went wrong");
ShowMessage(__throwExceptionName);
}
}
</FONT></PRE>
<P>This code uses
<TT>throwExceptionName</TT> to find the name of the type of exception
that was thrown. In this case, it will report that you have an exception of type
<TT>int</TT>. Not a great or wondrous fact, but at least it is a start if you are
trying to figure
out what went wrong. <TT>__throwExceptionName</TT> might not work
with VCL exceptions, but it will work with standard C++ exceptions.</P>
<P>Here is a VCL exception class that might be of some use when you are trying to
track down exceptions:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::GenericCatchIIBtnClick(TObject *Sender)
{
try
{
throw 12;
}
catch(EExternalException &E)
{
ShowMessage(E.Message);
}
}
</FONT></PRE>
<P>This VCL exception class will
handle the error that has occurred, even though
it is not a standard VCL error.</P>
<P>I've walked right up to the edge of the point beyond which I do not want to go
in this book. From here, keen-sighted readers can no doubt catch sight of some
generic
C++ vistas that contain innumerable questions concerning subtle matters of correct
syntactical usage. For more information, you should turn to a book on the C++ language.
My goal in this book is to stick to simple syntax that is easy to use,
and to avoid
digging into potential minefields, no matter how interesting the terrain may appear.</P>
<P>My suggestion is to not yield to the temptation to do anything fancy with exceptions.
Just use them to report errors, and do so by throwing
standard VCL exception classes
or descendants of standard VCL exception classes. If you follow these rules, you
will reap benefits and avoid trouble.
<H3><A NAME="Heading19"></A><FONT COLOR="#000077">Throwing VCL Exception Classes</FONT></H3>
<P>Here
is an example from the SimpleException program of how to throw a VCL exception:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::ThrowVCLExceptionClick(TObject *Sender)
{
try
{
throw Exception("VCL class");
}
catch(Exception &E)
{
ShowMessage(AnsiString(E.ClassName()) + " " + E.Message);
}
}
</FONT></PRE>
<P>The <TT>throw</TT> statement in this method automatically creates an instance
of the <TT>Exception</TT> class and calls its
constructor with a simple string. You
can, depending on your needs, place anything in this string.</P>
<P>Notice that there are other constructors for automatically formatting strings
and for retrieving strings that are stored in the program's
executable. For instance,
if you have a string table, you can automatically retrieve an item from that table
by number using the following constructor of the <TT>Exception</TT> class:</P>
<PRE><FONT COLOR="#0066FF">__fastcall Exception(int Ident);
</FONT></PRE>
<P>In this code, <TT>Ident</TT> is the ID of a string in a resource linked into your
application.</P>
<P>Here is a constructor designed to enable you to format input with a string stored
in a resource:</P>
<PRE><FONT
COLOR="#0066FF">__fastcall Exception(int Ident, const System::TVarRec * Args, const int Args_Size);
</FONT></PRE>
<P>For instance, here is an example of using a string from a string table in conjunction
with a <TT>format</TT> statement:</P>
<PRE><FONT COLOR="#0066FF">throw Exception(12, OPENARRAY(TVarRec, (12, "Value out of range!")));
</FONT></PRE>
<P>If the string stored in the resource table looked like this</P>
<PRE><FONT COLOR="#0066FF">Custom Error %d: %s
</FONT></PRE>
<P>then the string shown to the user would be</P>
<PRE><FONT COLOR="#0066FF">Custom Error 12: Value out of range!
</FONT></PRE>
<P>An example of raising this kind of error is found in the ResError program, discussed
later in this chapter. The source
for the program is found in the <TT>ResError</TT>
directory of the CD-ROM that accompanies this book.
<H3><A NAME="Heading20"></A><FONT COLOR="#000077">Understanding the VCL Exception
Classes</FONT></H3>
<P>In the section of this chapter called
"Exception Classes," I showed
you a long, but not exhaustive, list featuring the names of a number of VCL exception
classes. Here, to refresh your memory, are some of the declarations from that list:</P>
<PRE><FONT COLOR="#0066FF">class
__declspec(delphiclass) EIntError;
class __declspec(delphiclass) EInOutError;
class __declspec(delphiclass) EOutOfMemory;
class __declspec(delphiclass) EDivByZero;
</FONT></PRE>
<P>The interesting thing about all these classes is that they descend
from a single
root class called <TT>Exception</TT>. The declaration for class <TT>Exception</TT>
was quoted in full in the section of this chapter called "Exception Classes."</P>
<P>I've already said that one of the great things BCB does for
you is wrap your whole
program in a <TT>try..catch</TT> block. A second great BCB benefit, of almost equal
importance, is this class hierarchy. Of course, none of this would matter if C++
was not such a strong language with the capability to support a
wide range of powerful
features.</P>
<P>As you have seen, it's possible to create exceptions that pass nothing but an
integer to a <TT>catch</TT> block:</P>
<PRE><FONT COLOR="#0066FF">catch (int)
{
}
</FONT></PRE>
<P>This syntax can be useful under
certain circumstances, but you are much better
off if you receive an entire exception class inside a <TT>catch</TT> block. That
way you can call the methods of that class in order to find out exactly what is wrong,
or to perform other tasks that might
be helpful to you.</P>
<P>For instance, if you are not sure of the exact name of the error class which is
being thrown, you can always throw the error intentionally and check its <TT>ClassName</TT>
inside a <TT>catch</TT> block that catches all VCL
exceptions:</P>
<PRE><FONT COLOR="#0066FF">catch(Exception &E)
{
AnsiString S(this->ClassName());
AnsiString S1(E.ClassName());
MessageDlg(S + `\r' + S1, mtError, TMsgDlgButtons() << mbOK, 0);
}
</FONT></PRE>
<P>This code reports
the class in which the exception occurred, and then on the next
line, the class that threw the exception. For instance, it might post the following
lines inside the <TT>MessageDlg</TT>:</P>
<PRE><FONT COLOR="#0066FF">TForm1
EConvertError
</FONT></PRE>
<P>The key point here is that polymorphism is being put to work to the programmer's
great benefit. All VCL exception classes descend from class <TT>Exception</TT>, so
the rules of polymorphism dictate that you can pass them to a
<TT>catch</TT> block
that takes a parameter of type <TT>Exception</TT>. Furthermore, when you call the
methods of the class passed to you, polymorphism will ensure that the method called
is not necessarily of type <TT>Exception</TT>, but of the type
passed to you.</P>
<P>The previous code correctly reports that the class name of the exception is <TT>EConvertError</TT>,
even though the type of the class is declared to be of type <TT>Exception</TT>. In
other words, due to the wondrous rules of
polymorphism, an exception of type <TT>EConvertError</TT>
could be passed to you through a variable of type <TT>Exception</TT>.
<H3><A NAME="Heading21"></A><FONT COLOR="#000077">Creating and Raising Your Own Exceptions</FONT></H3>
<P>In this section,
I show how you can create your own exceptions and how to throw
exceptions when errors occur. The code explored in this section is from the MyExcept
program shown in Listing 5.3. The form for the program has three buttons and an edit
control. The main
form for the MyExcept program is shown in Figure 5.5.<BR>
<BR>
<A NAME="Heading22"></A><A HREF="05ebu05.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/05/05ebu05.jpg">FIGURE 5.5.</A><FONT COLOR="#000077">
</FONT><I>The main form for the MyExcept program.</I>
<H3 ALIGN="CENTER"></H3>
<P><A
NAME="Heading23"></A><FONT COLOR="#000077"><B>Listing 5.3. The header for the
MyExcept program shows how to create a custom exception.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// Main.h
// Project: MyExcept
// Copyright (c) 1997 by Charlie Calvert
//
#ifndef MainH
#define MainH
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Buttons.hpp>
class
ESillySpellingError: public Exception
{
public:
__fastcall ESillySpellingError(const AnsiString Msg)
:Exception(Msg) {}
};
class TForm1 : public TForm
{
__published:
TLabel *Label1;
TBitBtn *ERead;
TBitBtn *EReadAddr;
TBitBtn *RaiseException;
TEdit *Edit1;
void __fastcall RaiseExceptionClick(
TObject *Sender);
void __fastcall EReadClick(
TObject *Sender);
void __fastcall EReadAddrClick(
TObject *Sender);
private:
public:
virtual __fastcall
TForm1(TComponent* Owner);
};
extern TForm1 *Form1;
#endif
</FONT></PRE>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P><A NAME="Heading24"></A><FONT COLOR="#000077"><B>Listing 5.4. The MyExcept program
shows how to throw standard and custom
exceptions.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// Main.cpp
// Project: MyExcept
// Copyright (c) 1997 by Charlie Calvert
//
#include <vcl.h>
#pragma hdrstop
#include "Main.h"
#include "codebox.h"
#pragma resource "*.dfm"
TForm1 *Form1;
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
void __fastcall TForm1::RaiseExceptionClick(
TObject *Sender)
{
StrToInt("23a");
}
void __fastcall TForm1::EReadClick(
TObject *Sender)
{
throw EReadError("EReadError has occurred");
}
AnsiString GetAddr()
{
void *P;
P = Form1->MethodAddress("EReadAddrClick");
return Address2Str(P);
}
void __fastcall TForm1::EReadAddrClick(TObject *Sender)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -