⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch05.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>

<HEAD>
	<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
	<META NAME="Author" Content="Steph Mineart">
	<TITLE>Ch 5 -- Exceptions</TITLE>
</HEAD>

<BODY 
BGCOLOR="#FFFFFF">

<P ALIGN="CENTER"><IMG SRC="sams.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/sams.gif" WIDTH="75" HEIGHT="24" ALIGN="BOTTOM"
BORDER="0"><BR>
<BR>
<A HREF="index-3.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/index.htm"><IMG SRC="toc.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/toc.gif" WIDTH="40" HEIGHT="40" ALIGN="BOTTOM"
ALT="TOC" BORDER="0" NAME="toc4"></A> 
<A HREF="ch04.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/ch04.htm"><IMG SRC="back-1.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/back.gif"
WIDTH="40" HEIGHT="40" ALIGN="BOTTOM" ALT="BACK" BORDER="0" NAME="toc1"></A> <A HREF="ch06.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/ch06.htm"><IMG
SRC="forward.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/forward.gif" WIDTH="40" HEIGHT="40" ALIGN="BOTTOM" ALT="FORWARD" BORDER="0"

NAME="toc2"></A> </P>
<H2 ALIGN="CENTER"><FONT COLOR="#000077">Charlie Calvert's C++ Builder Unleashed</FONT></H2>
<P>
<H2 ALIGN="CENTER"><A NAME="Heading1"></A><FONT COLOR="#000077">- 5 -</FONT></H2>
<H2 ALIGN="CENTER"><A NAME="Heading2"></A><FONT 
COLOR="#000077">Exceptions</FONT></H2>
<P>In this chapter you learn how to add error handling to your programs. This is
done almost entirely through a mechanism called exceptions.</P>
<P>In particular, the following subjects are covered:

<UL>
	
<LI>Exception-handling theory
	<P>
	<LI>Basic exception classes
	<P>
	<LI><TT>try..catch</TT> blocks
	<P>
	<LI>Raising and reraising exceptions
	<P>
	<LI>Creating your own exception classes
	<P>
	<LI>Saving error strings in resources and retrieving 
them with <TT>LoadString</TT>
	<P>
	<LI>Internationalizing your program with string tables
	<P>
	<LI>Using the destructor of an object to ensure that code is executed even after
	an exception occurs. (Delphi and Java programmers should note that this 
is how C++
	gets the functionality found in <TT>try..finally</TT> blocks.)
	<P>
	<LI>Overriding the default exception handler
</UL>

<P>To a large degree, BCB and the VCL make it possible for you to write programs
that almost entirely ignore the 
subject of error checking. This is possible because
exceptions are built into most classes and stand-alone routines and will be thrown
automatically whenever something goes wrong. Furthermore, your entire program is
automatically wrapped inside a 
<TT>try..catch</TT> block. Professional programmers,
however, will want to go beyond even this level of safety and add additional error
checking to their code, or else change the default error handling performed by BCB.
Also, your programs might need 
to throw their own errors, so you will need to add
and throw new exception classes.</P>
<P>This explanation of exceptions is not meant to replace chapters on that subject
in standard books on C++ programming. Instead, I will concentrate on handling 
exceptions
in VCL-based programs.</P>
<P>BCB does a great job of seamlessly surfacing Pascal-based VCL exceptions in your
C++ code. As far as BCB programmers are concerned, there is no difference between
an exception that occurs in a block of Pascal 
code and an exception that occurs in
C++ code.</P>
<P>I believe exceptions are the correct model for reporting errors in any application.
Because exceptions play such a big role in all VCL programs, this is a topic of which
you should have at least a 
minimal understanding.
<H3><A NAME="Heading3"></A><FONT COLOR="#000077">The Theory Behind Exceptions</FONT></H3>
<P>Exceptions enable you to designate specific areas of your code designed to handle
errors. In particular, you can &quot;guard&quot; 
whole sections of code in such a
way that if errors occur inside them, the problem will be handled in a different
area by a set of routines designed explicitly for that purpose. This technique covers
nested functions, too, so you can begin a guarded 
block, step in through six or seven
levels of function calls, and then, if something goes wrong, bounce directly back
out to a single area in your code designed to handle error conditions. The goal is
to do as much as possible to relieve the burden of 
writing error-handling routines
so that you can concentrate on other, more important, goals.

<DL>
	<DT></DT>
</DL>



<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>Right at the start, it's important
	to recognize the 
difference between BCB exceptions, which cover language issues,
	and hardware exceptions, which involve hardware and hardware interrupts. You can
	(and BCB often does) wrap a hardware exception inside a BCB exception and handle
	the event that way, 
but hardware exceptions are different than BCB exceptions. <BR>
	<BR>
	For instance, running out of paper in a printer causes a hardware exception. Your
	code doesn't get an exception in this case, but a component might throw an exception
	if the 
situation is detected. Raising the exception does not cause the hardware error;
	it already exists outside the program. 
<HR>


</BLOCKQUOTE>

<P>Traditionally, error handling has been a matter of one area of code setting flags
and then a second area 
of code responding appropriately. For instance, if you tried
to open a file that does not exist, a flag would be set and other portions of your
code could detect the condition by checking the flag. Under the new system, instead
of a flag being set, an 
exception is thrown.</P>
<P>The easiest way to start appreciating the advantages that exceptions bring to
your code is to imagine a situation in which three different levels of code are called.
Suppose, for instance, that you wanted to display data in 
a grid, where the data
in question is stored in a text file. You might have the following set of calls,
all nested inside each other:</P>
<PRE><FONT COLOR="#0066FF">int DisplayDataInGrid();

  int RetrieveData();

    int OpenFile();

    int 
ReadFile();

    int CloseFile();

</FONT></PRE>
<P>In this scenario, <TT>DisplayDataInGrid</TT> calls <TT>RetrieveData</TT> and <TT>RetrieveData</TT>
calls <TT>OpenFile</TT>, <TT>ReadFile</TT>, and <TT>CloseFile</TT>. After <TT>CloseFile</TT>
was 
called, control would return to <TT>DisplayDataInGrid</TT>, and the actual data
would be shown to the user.</P>
<P>If something went wrong during the time the file was being opened, <TT>OpenFile</TT>
would have to pass that information back to 
<TT>RetrieveData</TT>. <TT>RetrieveData</TT>
would have to include code ensuring that <TT>ReadFile</TT> and <TT>CloseFile</TT>
didn't get called; then it would have to pass the error condition back to <TT>DisplayDataInGrid</TT>.
In turn, 
<TT>DisplayDataInGrid</TT> would have to ensure that it did not try to display
data that was never retrieved correctly. This whole process of passing information
in a daisy chain forces you to write complicated, confusing, and error-prone code.</P>

<P>As a child, you might have played a game called &quot;telephone.&quot; In particular,
you might have had a teacher, camp counselor, or friend who arranged a large group
of people in a circle and then whispered something to the person on his or her 
left.
That person in turn whispered the message to someone on his left, and so on, until
the message went all the way around the circle. When the message had made the whole
trip, its meaning almost always ended up changing radically from its initial 
conception.
The same thing can happen in a program if you use the daisy chain method of conveying
error conditions. The worst case, of course, is when one link in the chain is broken
altogether and the rest of the code continues merrily on its way, 
oblivious of the
fact that something serious has gone wrong.</P>
<P>Exceptions don't use the daisy chain theory of error processing. Instead, if an
exception is thrown in the function <TT>OpenFile</TT>, the code automatically unwinds
back to 
<TT>DisplayDataInGrid</TT>, where you can write code that handles the error.
Exceptions automatically pop functions and data off the stack, and they automatically
ensure that no other routines behind or in front of it are called until the code
is 
found that is intended to handle the exception.

<DL>
	<DT></DT>
</DL>



<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>In Java and Object Pascal, when
	code is being popped off the stack during an exception, the compiler 
checks for one
	particular block of code that needs to be executed, even if an exception has occurred.
	This special code is enclosed in <TT>try..finally</TT> blocks. C++ has no support
	for <TT>try..finally</TT> blocks. Instead, you can put your 
cleanup code in the destructor
	of your local objects. The destructor will be called even if an exception has occurred.
	
<HR>


</BLOCKQUOTE>

<P>In BCB, if an exception occurs and you do not handle it explicitly, a default
exception handler will 
process the exception. Most exceptions are not handled explicitly.</P>
<P>When the VCL default exception handler is invoked, it displays a message dialog
describing the exception to the user, and then your program resumes its normal processing
of 
Windows messages. Your program does not return to the code that threw the exception.
When an exception is thrown, special compiler-generated code checks the most recently
entered <TT>try</TT> block on the call stack for a suitable exception handler. 
If
that <TT>try</TT> block has no exception handlers suitable for the current exception,
the next outward <TT>try</TT> block is checked, and so on, until an exception handler
is found or it reaches the default exception handler. Normal program 
execution resumes
at the next statement following the code that handles the exception.</P>
<P>If you have a strong background in C++, it might take a while to get used to the
idea that your VCL programs are automatically encased in exception-handling 
code.
The standard C++ code you write will not partake of this benefit, but you can easily
add exception handling to that code if you want it.

<DL>
	<DT></DT>
</DL>



<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>Both RTTI 
and exception handling
	add bulk to your code. Your code is bigger and slower because it carries this burden.
	The subject of RTTI will be dealt with later in this chapter. <BR>
	<BR>
	I personally believe that the exception-handling code is worth a 
small burden in
	terms of speed and size simply because of the degree of robustness that it adds to
	your code. Another important point to remember is that BCB's built-in exception handling
	eliminates the need for you to write a great deal of your 
own error-handling code.
	As a result, it actually produces a decrease in the size of your program. It is difficult
	to state with certainty whether the decrease in the size of your own code entirely
	offsets the increase in code size produced by 
BCB's built-in exception handling.
	In most situations, however, the two are likely to come close to canceling each other
	out. 
<HR>


</BLOCKQUOTE>

<P>I believe that if you combine the increased robustness given to you by exceptions
with the 
benefit of having to write fewer lines of code, you come up with a clear
winner. In fact, I would say that the VCL's built-in, exception-handling capabilities
are one of the great benefits of the system.</P>
<P>As stated earlier, the VCL, and any 
related Object Pascal functions supported
by BCB, are all guaranteed to be wrapped in exception handlers. This is not true
of the standard C++ routines and objects that you might call. In my mind, this is
a reason to turn to the VCL whenever possible, 
and to use other routines only when
necessary. Exception handling is part of good contemporary programming practice,
and I believe that it will remain part of it into the foreseeable future.</P>
<P>If the basic idea behind exceptions does not yet 
quite make sense to you, just
forge ahead anyway, and I think it will become clear in time. The previous few paragraphs
lay out the theory behind a fairly simple set of syntactical routines. Play with
the syntax for a while, using the following 
descriptions as a guide, and then if
you want, come back and read the theory a second time.
<H3><A NAME="Heading7"></A><FONT COLOR="#000077">Exception Classes</FONT></H3>
<P>BCB comes with a rich set of built-in exception classes meant for handling a 
wide
range of exceptions. You can easily create your own exception classes for handling
the key events in your program that might be susceptible to error. Here is the base
class for BCB exception handling, as it is declared in<TT> 
SYSUTILS.HPP</TT>:</P>
<PRE><FONT COLOR="#0066FF">class __declspec(delphiclass) Exception;

class __declspec(pascalimplementation) Exception : public System::TObject

{

  typedef System::TObject inherited;

private:

  System::AnsiString FMessage;

  
int FHelpContext;

public:

  __fastcall Exception(const System::AnsiString Msg);

  __fastcall Exception(const System::AnsiString Msg,

    const System::TVarRec *Args, const int Args_Size);

  __fastcall Exception(int Ident);

  __fastcall 
Exception(int Ident, const System::TVarRec *Args,

    const int Args_Size);

  __fastcall Exception(const System::AnsiString Msg, int AHelpContext);

  __fastcall Exception(const System::AnsiString Msg,

    const System::TVarRec *Args,

    const 
int Args_Size, int AHelpContext);

  __fastcall Exception(int Ident, int AHelpContext);

  __fastcall Exception(int Ident, const System::TVarRec *Args,

    const int Args_Size, int AHelpContext);

  __property int HelpContext = {read=FHelpContext, 
write=FHelpContext, nodefault};

  __property System::AnsiString Message =

    {read=FMessage, write=FMessage, nodefault};

public:

  /* TObject.Destroy */ __fastcall virtual ~Exception(void) { }

};

</FONT></PRE>
<P>A quick perusal of this 
declaration reveals that all exceptions have a message
that can be displayed to the user. You can pass in this message through a number
of different constructors, and you can retrieve it through the <TT>Message</TT> property.

<DL>
	<DT></DT>
</DL>




<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>On the off-chance that you are new
	to C++, I might add here that C++ classes sometimes have multiple constructors because
	you may have more than one way in which you want to 
create a class. Sometimes you
	might want to initialize a class by passing in one type of string, and another time
	you might want to pass in a second type of string or perhaps an integer. To give
	you the flexibility you need, C++ enables you to 
declare multiple constructors. Needless
	to say, you still call only one constructor when creating a class; it's just that
	you have a choice of which constructor you want to choose. Unlike Object Pascal,
	all these constructors have the same name, 
which is identical to the class name.
	
<HR>


</BLOCKQUOTE>

<P>Here are some additional built-in exceptions, all quoted directly from <TT>SYSUTILS.PAS</TT>:</P>
<PRE><FONT COLOR="#0066FF">class __declspec(delphiclass) EIntError;

class 
__declspec(delphiclass) EInOutError;

class __declspec(delphiclass) EOutOfMemory;

class __declspec(delphiclass) EDivByZero;

class __declspec(delphiclass) ERangeError;

class __declspec(delphiclass) EIntOverflow;

class __declspec(delphiclass) 
EMathError;

class __declspec(delphiclass) EInvalidOp;

class __declspec(delphiclass) EZeroDivide;

class __declspec(delphiclass) EOverflow;

class __declspec(delphiclass) EUnderflow;

class __declspec(delphiclass) EInvalidPointer;

class 
__declspec(delphiclass) EInvalidCast;

class __declspec(delphiclass) EConvertError;

class __declspec(delphiclass) EAccessViolation;

class __declspec(delphiclass) EPrivilege;

class __declspec(delphiclass) EStackOverflow;

class 
__declspec(delphiclass) EControlC;

class __declspec(delphiclass) EVariantError;

class __declspec(delphiclass) EPropReadOnly;

class __declspec(delphiclass) EPropWriteOnly;

class __declspec(delphiclass) EExternalException;

</FONT></PRE>
<P>You can 
see that there are exception classes for divide-by-zero errors, file I/O
errors, invalid type casts, and various other conditions both common and obscure.</P>
<P>The preceding list, however, is far from complete. Many other exceptions classes
are 
declared in other modules of the VCL. To get a feeling for their complete scope,
you should use the online help or browse the source files in the Include/VCL directory.
<H3><A NAME="Heading9"></A><FONT COLOR="#000077">Basic Exception 
Syntax</FONT></H3>
<P>When working with the code presented in this chapter, you will be raising a lot
of exceptions. If you set Options | Environment | Preferences | Break on Exception
to True, exceptions thrown by your program will cause the debugger 
to take you as
near as possible to the place in your code where the exception occurred. Only after
you start running again will you see the error message as it will be reported to
the user. As a result, you should probably keep Break on Exception set 
to False except
when you explicitly want to step through your code during an exception.</P>
<P>The SIMPEXP program, referenced in Listing 5.1, gives four examples of how to
throw and handle exceptions in BCB. The first two examples shown are of the 
simplest
possible kind, and are meant to get you started with the concepts involved in this
process. The latter two examples in this program are a bit more complex, but are
still relatively straightforward. The main form for the program is shown in 
Figure
5.1.
<H6></H6>
<P><A NAME="Heading10"></A><A HREF="05ebu01.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/05/05ebu01.jpg">FIGURE 5.1.</A><FONT COLOR="#000077">
</FONT><I>The main form for the SIMPEXP program. Remember to turn Optimizations off

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -