?? ch26.htm
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!--
function popUp(pPage) {
var fullURL = document.location;
var textURL = fullURL.toString();
var URLlen = textURL.length;
var lenMinusPage = textURL.lastIndexOf("/");
lenMinusPage += 1;
var fullPath = textURL.substring(0,lenMinusPage);
popUpWin = window.open('','popWin','resizable=yes,scrollbars=no,width=525,height=394');
figDoc= popUpWin.document;
zhtm= '<HTML><HEAD><TITLE>' + pPage + '</TITLE>';
zhtm += '<link rel="stylesheet" href="/includes/stylesheets/ebooks.css"></head>';
zhtm += '<BODY bgcolor="#FFFFFF">';
zhtm += '<IMG SRC="' + fullPath + pPage + '">';
zhtm += '<P><B>' + pPage + '</B>';
zhtm += '</BODY></HTML>';
window.popUpWin.document.write(zhtm);
window.popUpWin.document.close();
// Johnny Jackson 4/28/98
}
//-->
</SCRIPT>
<link rel="stylesheet" href="/includes/stylesheets/ebooks.css">
<TITLE>Special Edition Using Visual C++ 6 -- Ch 26 -- Exceptions and Templates</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">
<CENTER>
<H1><IMG SRC="../button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>
Special Edition Using Visual C++ 6</H1>
</CENTER>
<CENTER>
<P><A HREF="../ch25/ch25.htm"><IMG SRC="../button/previous.gif" WIDTH="128" HEIGHT="28"
ALIGN="BOTTOM" ALT="Previous chapter" BORDER="0"></A><A HREF="../ch27/ch27.htm"><IMG
SRC="../button/next.gif" WIDTH="128" HEIGHT="28" ALIGN="BOTTOM" ALT="Next chapter"
BORDER="0"></A><A HREF="../index.htm"><IMG SRC="../button/contents.gif" WIDTH="128"
HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A>
<HR>
</CENTER>
<CENTER>
<H1>- 26 -</H1>
<H1>Exceptions and Templates</H1>
</CENTER>
<UL>
<LI><A HREF="#Heading1">Understanding Exceptions</A>
<UL>
<LI><A HREF="#Heading2">Simple Exception Handling</A>
<LI><A HREF="#Heading3">Exception Objects</A>
<LI><A HREF="#Heading4">Placing the catch Block</A>
<LI><A HREF="#Heading5">Handling Multiple Types of Exceptions</A>
<LI><A HREF="#Heading6">The Old Exception Mechanism</A>
</UL>
<LI><A HREF="#Heading7">Exploring Templates</A>
<UL>
<LI><A HREF="#Heading8">Introducing Templates</A>
<LI><A HREF="#Heading9">Creating Function Templates</A>
<LI><A HREF="#Heading10">Creating Class Templates</A>
</UL>
<LI><A HREF="#Heading11">The Standard Template Library</A>
<UL>
<LI><A HREF="#Heading12">Managed Pointer Templates: auto_ptr</A>
<LI><A HREF="#Heading13">Other Useful STL Templates</A>
</UL>
<LI><A HREF="#Heading14">Understanding Namespaces</A>
<UL>
<LI><A HREF="#Heading15">Defining a Namespace</A>
<LI><A HREF="#Heading16">Namespace Scope Resolution</A>
<LI><A HREF="#Heading17">Unnamed Namespaces</A>
<LI><A HREF="#Heading18">Namespace Aliases</A>
</UL>
</UL>
<P>
<HR SIZE="4">
<CENTER>
<H1></H1>
</CENTER>
<P>C++ is an evolving language and frequently undergoes review and improvement. Two
important features that were added to C++ after many developers had already learned
the language are exceptions and templates. Although most programmers delay learning
these concepts until they have six months to a year of Visual C++ programming experience,
you should consider learning them now. These concepts are not much more difficult
than the ones covered earlier in this book and can add extra power to your programs.</P>
<P>
<H2><A NAME="Heading1"></A>Understanding Exceptions</H2>
<P>When writing applications using Visual C++, sooner or later you're going to run
into error-handling situations that don't seem to have a solution. Perhaps you are
writing a function that returns a numeric value and need a way to send back an error
response. Sometimes you can come up with one special return value, perhaps 0 or -1,
that indicates a problem. Other times there doesn't seem to be a way to signal trouble.
Perhaps you use special return values but find yourself writing code that starts
out like this:</P>
<P>
<PRE>while (somefunction(x))
{
for (int i=0; i<limit; i++)
{
y = someotherfunction(i);
}
}
</PRE>
<P>After writing that, perhaps you realize that if someotherfunction() returns -1,
you should not move on to the next i, and you should leave the while loop. Your code
becomes the following:</P>
<P>
<PRE>int timetostop = 0;
while (somefunction(x) && !timetostop)
{
for (int i=0; i<limit && !timetostop; i++)
{
if ( (y = someotherfunction(i)) == -1)
timetostop = 1;
}
}
</PRE>
<P>This isn't bad, but it is hard to read. If there are two or three things that
could go wrong, your code becomes unmanageably complex.</P>
<P>Exceptions are designed to handle these sorts of problems. The exception mechanism
allows programs to signal each other about serious and unexpected problems. Three
places in your code participate in most exceptions:</P>
<P>
<UL>
<LI>The try<I> block</I> marks the code you believe might run into difficulty.
<P>
<LI>The catch<I> block</I> immediately follows the try block and holds the code that
deals with the problem.
<P>
<LI>The throw<I> statement</I> is how the code with a problem notifies the calling
code.
</UL>
<H3><A NAME="Heading2"></A>Simple Exception Handling</H3>
<P>The mechanism used by exception-handling code is simple. Place the source code
that you want guarded against errors inside a try block. Then construct a catch program
block that acts as the error handler. If the code in the try block (or any code called
from the try block) throws an exception, the try block immediately ceases execution,
and the program continues inside the catch block.</P>
<P>For example, memory allocation is one place in a program where you might expect
to run into trouble. Listing 26.1 shows a nonsensical little program that allocates
some memory and then immediately deletes it. Because memory allocation could fail,
the code that allocates the memory is enclosed in a try program block. If the pointer
returned from the memory allocation is NULL, the try block throws an exception. In
this case, the exception object is a string.</P>
<BLOCKQUOTE>
<P>
<HR>
<strong>NOTE:</strong> The sample applications in this chapter are console applications,
which can run from a DOS prompt and don't have a graphical interface. This keeps
them small enough to be shown in their entirety in the listings. To try them, create
a console application as discussed in Chapter 28, "Future Explorations,"
add a file to the project, and add the code shown here. 
<HR>
</BLOCKQUOTE>
<H4>Listing 26.1  EXCEPTION1.CPP--Simple Exception Handling</H4>
<PRE>#include <iostream.h>
int main()
{
int* buffer;
try
{
buffer = new int[256];
if (buffer == NULL)
throw "Memory allocation failed!";
else
delete buffer;
}
catch(char* exception)
{
cout << exception << endl;
}
return 0;
</PRE>
<PRE>}
</PRE>
<P>When the program throws the exception, program execution jumps to the first line
of the catch program block. (The remainder of the code inside the try block is not
executed.) In the case of Listing 26.1, this line prints out a message, after which
the function's return line is executed and the program ends.</P>
<P>If the memory allocation is successful, the program executes the entire try block,
deleting the buffer. Then program execution skips over the catch block completely,
in this case going directly to the return statement.</P>
<BLOCKQUOTE>
<P>
<HR>
<strong>NOTE:</strong> The catch program block does more than direct program execution.
It actually catches the exception object thrown by the program. For example, in Listing
26.1, you can see the exception object being caught inside the parentheses following
the catch keyword. This is very similar to a parameter being received by a method.
In this case, the type of the "parameter" is char* and the name of the
parameter is exception. 
<HR>
</BLOCKQUOTE>
<H3><A NAME="Heading3"></A>Exception Objects</H3>
<P>The beauty of C++ exceptions is that the exception object thrown can be just about
any kind of data structure you like. For example, you might want to create an exception
class for certain kinds of exceptions that occur in your programs. Listing 26.2 shows
a program that defines a general-purpose exception class called MyException. In the
case of a memory-allocation failure, the main program creates an object of the class
and throws it. The catch block catches the MyException object, calls the object's
GetError() member function to get the object's error string, and then displays the
string on the screen.</P>
<P>
<H4>Listing 26.2  EXCEPTION2.CPP--Creating an Exception Class</H4>
<PRE>#include <iostream.h>
class MyException
{
protected:
char* m_msg;
public:
MyException(char *msg) { m_msg = msg; }
~MyException(){}
char* GetError() {return m_msg; };
};
int main()
{
int* buffer;
try
{
buffer = new int[256];
if (buffer == NULL)
{
MyException* exception =
new MyException("Memory allocation failed!");
throw exception;
}
else
delete buffer;
}
catch(MyException* exception)
{
char* msg = exception->GetError();
cout << msg << endl;
}
return 0;
</PRE>
<PRE>}
</PRE>
<P>An exception object can be as simple as an integer error code or as complex as
a fully developed class. MFC provides a number of exception classes, including CException
and several classes derived from it. The abstract class CException has a constructor
and three member functions: Delete(), which deletes the exception, GetErrorMessage(),
which returns a string describing the exception, and ReportError(), which reports
the error in a message box.</P>
<P>
<H3><A NAME="Heading4"></A>Placing the catch Block</H3>
<P>The catch program block doesn't have to be in the same function as the one in
which the exception is thrown. When an exception is thrown, the system starts "unwinding
the stack," looking for the nearest catch block. If the catch block is not found
in the function that threw the exception, the system looks in the function that called
the throwing function. This search continues up the function-call stack. If the exception
is never caught, the program halts.</P>
<P>Listing 26.3 is a short program that demonstrates this concept. The program throws
the exception from the AllocateBuffer() function but catches the exception in main(),
which is the function from which AllocateBuffer() is called.</P>
<P>
<H4>Listing 26.3  EXCEPTION3.CPP--Catching Exceptions Outside the <BR>
Throwing Function</H4>
<PRE>#include <iostream.h>
class MyException
{
protected:
char* m_msg;
public:
MyException(char *msg) { m_msg = msg;}
~MyException(){}
char* GetError() {return m_msg;}
};
class BigObject
{
private:
int* intarray;
public:
BigObject() {intarray = new int[1000];}
~BigObject() {delete intarray;}
};
int* AllocateBuffer();
int main()
{
int* buffer;
try
{
buffer = AllocateBuffer();
delete buffer;
}
catch (MyException* exception)
{
char* msg = exception->GetError();
cout << msg << endl;
}
return 0;
}
int* AllocateBuffer()
{
BigObject bigarray;
float* floatarray = new float[1000];
int* buffer = new int[256];
if (buffer == NULL)
{
MyException* exception =
new MyException("Memory allocation failed!");
throw exception;
}
delete floatarray;
return buffer;
</PRE>
<PRE>}
</PRE>
<P>When the exception is thrown in AllocateBuffer(), the remainder of the function
is not executed. The dynamically allocated floatarray will not be deleted. The BigObject
that was allocated on the stack will go out of scope, and its destructor will be
executed, deleting the intarray member variable that was allocated with new in the
constructor. This is an important concept to grasp: Objects created on the stack
will be destructed as the stack unwinds. Objects created on the heap will not. Your
code must take care of these. For example, AllocateBuffer() should include code to
delete floatarray before throwing the exception, like this:</P>
<P>
<PRE>if (buffer == NULL)
{
MyException* exception =
new MyException("Memory allocation failed!");
delete floatarray;
throw exception;
}
</PRE>
<P>In many cases, using an object with a carefully written destructor can save significant
code duplication when you are using exceptions. If you are using objects allocated
on the heap, you may need to catch and rethrow exceptions so that you can delete
them. Consider the code in Listing 26.4, in which the exception is thrown right past
an intermediate function up to the catching function.</P>
<P>
<H4>Listing 26.4  EXCEPTION4.CPP--Unwinding the Stack</H4>
<PRE>#include <iostream.h>
class MyException
{
protected:
char* m_msg;
public:
MyException(char *msg) { m_msg = msg;}
~MyException(){}
char* GetError() {return m_msg;}
};
class BigObject
{
private:
int* intarray;
public:
BigObject() {intarray = new int[1000];}
~BigObject() {delete intarray;}
};
int* AllocateBuffer();
int* Intermediate();
int main()
{
int* buffer;
try
{
buffer = Intermediate();
delete buffer;
}
catch (MyException* exception)
{
char* msg = exception->GetError();
cout << msg << endl;
}
return 0;
}
int* Intermediate()
{
BigObject bigarray;
float* floatarray = new float[1000];
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -