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

📄 ch05.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
  AnsiString S = Edit1->Text;

  if (UpperCase(S) == "OCCURED")

  {

    S = "A Silly Spelling error has occured! "

        "The 
correct spelling is occuRRed, not occuRed! ";

    throw ESillySpellingError(S + "\rAddress: " +GetAddr());

  }

}

</FONT></PRE>
<PRE><FONT COLOR="#0066FF"></FONT></PRE>
<P>To use this program, just press any of the three buttons on 
the form. The third
button won't throw an exception unless the edit control is set to the misspelled
string <TT>occured</TT>.</P>
<P>Exceptions occur because they are explicitly thrown. For instance, here is another
version of the <TT>StrToInt</TT> 
routine:</P>
<PRE><FONT COLOR="#0066FF">int Str2Int(AnsiString S)

{

  int i = atoi(S.c_str());

  if (i == 0)

    throw EConvertError(&quot;Cannot convert &quot; + S + &quot; to an int&quot;);

  return i;

}

</FONT></PRE>
<P>This function uses 
the <TT>atoi</TT> function to convert a string into an integer.
If all is successful, the function result is set equal to the transmuted string.
If there is a problem, the value returned from <TT>atoi</TT> is zero. When an error
condition exists, the 
<TT>Str2Int</TT> routine throws an <TT>EConvertError</TT> and
passes in a string that explains what has gone wrong.

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



<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>TIP:</B></FONT><B> </B>Obviously, the previous function
	
would not work correctly if you passed in <TT>&quot;0&quot;</TT> or <TT>&quot;00&quot;</TT>,
	and so on, as a string. If you need a secure function, use <TT>StrToInt</TT>. 
<HR>


</BLOCKQUOTE>

<P><TT>EConvertError</TT> is a built-in BCB type meant 
to be used in situations where
an error occurs in a conversion routine. If you look in <TT>SYSUTILS.HPP</TT>, you
will find that BCB uses this exception quite a bit, but tends to throw it through
the good graces of the <TT>ConvertError</TT> 
routine.</P>
<P>There is nothing in BCB that forces you to use a particular class of exceptions
in a particular situation. For instance, in the following method I throw an <TT>EReadError</TT>,
even though nothing has gone wrong in the program:</P>

<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::EReadClick(TObject *Sender)

{

  throw EReadError(&quot;EReadError has occurred&quot;);

}

</FONT></PRE>
<P>As you saw earlier, exceptions are triggered when you use the reserved word <TT>throw</TT>

and then construct an instance of a particular type of exception. In and of themselves,
exceptions have nothing to do with errors, and indeed you could use them for some
entirely different purpose. In other words, exceptions are a good means of 
reporting
errors, but they do not occur because an error occurs; they occur because you use
the reserved word <TT>throw</TT>!</P>
<P>Many of the exception classes that are built into BCB may be useful to you at
times. For instance, you might need to 
convert some variable from one type to another;
or there may be an occasion when you need to read some value. If errors occur during
such tasks, it would make sense to throw an <TT>EConvertError</TT> or an <TT>EReadError</TT>.
That way, the code that 
depends upon your conversion routines doesn't have to worry
about what to do when the conversion routines fail. On failure, they will throw an
exception and will never return bad data or error codes to the caller. That can go
a long way toward 
simplifying your code.</P>
<P>Despite the usefulness of many of BCB's built-in exception classes, there are
many occasions when you are going to need to create exception classes of your own.
To do so, you should first declare a new class:</P>

<PRE><FONT COLOR="#0066FF">class ESillySpellingError: public Exception

{

  public:

  __fastcall ESillySpellingError(const AnsiString Msg)

    :Exception(Msg) {}

};

</FONT></PRE>
<P>This code states that class <TT>ESillySpellingError</TT> is a 
descendant of type
<TT>Exception</TT>. You can create as many constructors for your class as you think
you need, or you can simply copy the constructors from one of the classes in the
<TT>SYSUTILS.HPP</TT> file and do a search and replace on the class 
name.</P>
<P>I created <TT>ESillySpellingError</TT> for the quixotic reason of desiring to
finally squelch permanently a spelling error that I have made many times in my life.
In particular, I tend to misspell the past tense of the word occur:</P>

<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::EReadAddrClick(TObject *Sender)

{

  AnsiString S = Edit1-&gt;Text;

  if (UpperCase(S) == &quot;OCCURED&quot;)

  {

    S = &quot;A Silly Spelling error has occured! &quot;

        &quot;The 
correct spelling is occuRRed, not occuRed! &quot;;

    throw ESillySpellingError(S + &quot;\rAddress: &quot; +GetAddr());

  }

}

</FONT></PRE>
<P>Hopefully, writing about the error in this book will help me remember that there
are two Rs in the 
word--not just one! (My plan seems to have worked, but alas, there
are so many other words that I misspell!)</P>
<P>At any rate, you can see that it is easy to create your own exceptions and to
throw them. Whenever you feel that you need to describe a 
new type of error, you
can do so by just creating the simple type shown in the preceding code. If you want,
you can create more complex exception types. For instance, the BCB <TT>EInOutError</TT>
adds an <TT>ErrorCode</TT> to its object declaration. 
You can then reference this
error code in a <TT>catch</TT> block:</P>
<PRE><FONT COLOR="#0066FF">try

  ..

catch(EInOutError &amp;E)

{

  Code = E.ErrorCode;

}

</FONT></PRE>
<P>Remember that the need for different types of errors becomes evident 
not when
you are raising them, but in the <TT>catch</TT> portion of <TT>try..catch</TT> blocks.
You might want to handle a particular type of error explicitly and let other errors
be handled by the default handler. To do this, you must have a variety 
of different
exception classes to throw so that your exception handlers can be set up to distinguish
between the different error situations.</P>
<P>The lazy man's way to raise an exception is simply to write</P>
<PRE><FONT COLOR="#0066FF">throw 
Exception(&quot;Another lazy man error has occured!&quot;);

</FONT></PRE>
<P>This technique works fine in many cases. However, it is best to create your own
exception classes so that you can create <TT>try..catch</TT> blocks that work only
with a 
specific type of error.</P>
<P>For more on creating your own exception classes, see the ResError program shown
later in this chapter. ResError has an example in it of using a constructor for a
custom <TT>Exception</TT> class that grabs a string from a 
string table and uses
the <TT>format</TT> function to customize the string when displaying it to the user.
<H3><A NAME="Heading26"></A><FONT COLOR="#000077">Rethrowing an Exception</FONT></H3>
<P>The <TT>AutoThrowClick</TT> method from the ThrowAgain 
program shows how to rethrow
an exception:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::ThrowItAgainSamClick(TObject *Sender)

{

  int k;

  try

  {

    k = StrToInt(&quot;Sam&quot;);

    ShowMessage(k);

  }

  catch(...)

  {

    
ShowMessage(&quot;Something went wrong&quot;);

    throw;

  }

}

</FONT></PRE>
<P>Rethrowing an exception involves nothing more than using the <TT>throw</TT> keyword.
The preceding example intentionally creates an <TT>EConvertError</TT> 
<TT>error</TT>,
shows a message to the user, and rethrows the exception. If you run the program,
you will first see the custom error message I have devised and then the standard
<TT>EConvert</TT> error message. Most of the time you would not want to 
show two
error messages, and I have written this kind of code only so you can see exactly
what is happening when you run the program.</P>
<P>Rethrowing an exception enables you to get the best of both worlds. You get to
perform some custom handling 
and allow BCB to automatically inform the user exactly
what has gone wrong.</P>
<P>In many cases, it is a good idea to rethrow an exception, because you cannot be
sure that all the handling necessary for dealing with the error is complete. In fact,
it 
is often a good idea to let the system handle exceptions automatically without
interfering in any way. If you do need to step into the process by writing a <TT>try..catch</TT>
block, you should give serious thought to rethrowing the exception in case 
some other
routine needs to know about it. The great beauty of exceptions is that things often
work best if you just forget about handling errors altogether!
<H3><A NAME="Heading27"></A><FONT COLOR="#000077">Exceptions and Destructors</FONT></H3>

<P>Despite the note on which I ended the last section, there are certain types of
situations in which you need to ensure that a particular block of code is executed
even if something goes wrong in the code that precedes it. For instance, you may

allocate memory, perform several actions, and finally intend to deallocate the memory.
However, if an exception is thrown between the time you allocate memory and the time
you want to deallocate the memory, the code that deallocates the memory might 
never
get executed. In Java and Object Pascal, this situation is handled with <TT>try..finally</TT>
blocks. C++ does not support that syntax, but it has another technique you can use
instead.</P>
<P>Here is a second way to think about this whole 
situation. As you know, a <TT>try..catch</TT>
block can cause the execution pointer for your program to jump from the place that
an error occurs directly to the place where you handle that error. That is all well
and good under most circumstances, and 
indeed, as I said at the end of the last section,
it is usually best to let this process occur unattended. However, there are times
when you want to make sure that some code between the error and the exception handler
is executed regardless of 
circumstances. The code shown in Listings 5.5 through 5.7
shows how to proceed. The program is run in a simple form that contains a button
and an edit control.<BR>
<BR>
<A NAME="Heading28"></A><FONT COLOR="#000077"><B>Listing 5.5. The AllObjects 
program
shows how to handle memory allocations.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////

// Copyright (c) 1997 by Charlie Calvert

//

#ifndef MainH

#define MainH

#include &lt;Classes.hpp&gt;

#include 
&lt;Controls.hpp&gt;

#include &lt;StdCtrls.hpp&gt;

#include &lt;Forms.hpp&gt;

class TMyObject

{

public:

  TMyObject(void);

  ~TMyObject(void);

  void SayHello(void);

  void BlowUp(void);

};

class TForm1 : public TForm

{

__published:

  
TButton *NoCareTaker;

  TButton *CareTaker;

  TButton *CareTakeWithTryExcept;

  void __fastcall NoCareTakerClick(

  TObject *Sender);

  void __fastcall CareTakerClick(

  TObject *Sender);

  void __fastcall CareTakeWithTryExceptClick(

  TObject 
*Sender);

private:

public:

  virtual __fastcall TForm1(TComponent* Owner);

};

extern TForm1 *Form1;

#endif

</FONT></PRE>
<P><A NAME="Heading29"></A><FONT COLOR="#000077"><B>Listing 5.6. The AllObjects program
shows how to handle memory 
allocations (continued).</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////

// Copyright (c) 1997 by Charlie Calvert

//

#include &lt;vcl.h&gt;

#pragma hdrstop

#include &quot;Main.h&quot;

#include 
&quot;CareTaker1.h&quot;

#pragma resource &quot;*.dfm&quot;

TForm1 *Form1;

TMyObject::TMyObject(void)

{

  ShowMessage(&quot;TMyObject constructor called&quot;);

}

TMyObject::~TMyObject(void)

{

  ShowMessage(&quot;TMyobject destructor 
called!&quot;);

}

void TMyObject::BlowUp(void)

{

  throw(42);

}

void TMyObject::SayHello(void)

{

  ShowMessage(&quot;MyObject says hello&quot;);

}

__fastcall TForm1::TForm1(TComponent* Owner)

  : TForm(Owner)

{

}

// In this method the 
destructor for TMyObject is NOT called

void __fastcall TForm1::NoCareTakerClick(TObject *Sender)

{

  TMyObject *MyObject = new TMyObject;

  MyObject-&gt;SayHello();

  MyObject-&gt;BlowUp();

  delete MyObject;

}

// In this method the destructor 
for TMyObject is called

void __fastcall TForm1::CareTakerClick(

  TObject *Sender)

{

  TCareTaker&lt;TMyObject&gt; MyCareTaker;

  TMyObject *MyObject = MyCareTaker.GetObject();

  MyObject-&gt;SayHello();

  MyObject-&gt;BlowUp()

⌨️ 快捷键说明

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