?? ch26.htm
字號:
int Equal()
{
int equal;
if (arg1 == arg2)
equal = 1;
else
equal = 0;
return equal;
}
};
int main()
{
CCompare<int> compare1(15, 25);
CCompare<double> compare2(254.78, 12.983);
CCompare<char> compare3(`A', `Z');
cout << "THE COMPARE1 OBJECT" << endl;
cout << "Lowest: " << compare1.GetMin() << endl;
cout << "Highest: " << compare1.GetMax() << endl;
cout << "Equal: " << compare1.Equal() << endl;
cout << endl;
cout << "THE COMPARE2 OBJECT" << endl;
cout << "Lowest: " << compare2.GetMin() << endl;
cout << "Highest: " << compare2.GetMax() << endl;
cout << "Equal: " << compare2.Equal() << endl;
cout << endl;
cout << "THE COMPARE2 OBJECT" << endl;
cout << "Lowest: " << compare3.GetMin() << endl;
cout << "Highest: " << compare3.GetMax() << endl;
cout << "Equal: " << compare3.Equal() << endl;
cout << endl;
return 0;
</PRE>
<PRE>}
</PRE>
<P>The main program instantiates three objects from the class template: one that
deals with integers, one that uses floating-point values, and one that stores and
compares character values. After creating the three CCompare objects, main() calls
the objects' member functions in order to display information about the data stored
in each object. Figure 26.1 shows the program's output.</P>
<P><A HREF="javascript:popUp('26uvc01.gif')"><B>FIG. 26.1</B></A><B> </B><I>The template3
program creates three different objects from a class template.</I></P>
<P>You can pass as many parameters as you like to a class template, just like a function
template. Listing 26.12 shows a class template that uses two different types of data.</P>
<P>
<H4>Listing 26.12  Using Multiple Parameters with a Class Template</H4>
<PRE>template<class Type1, class Type2>
class CMyClass
{
protected:
Type1 data1;
Type2 data2;
public:
CMyClass(Type1 arg1, Type2 arg2)
{
data1 = arg1;
data2 = arg2;
}
~CMyClass() {}
</PRE>
<PRE>};
</PRE>
<P>To instantiate an object of the CMyClass class, you might use a line like this:</P>
<P>
<PRE>CMyClass<int, char> myClass(15, `A');
</PRE>
<P>Finally, you can use specific data types, as well as the placeholder data types,
as parameters in a class template. Just add the specific data type to the parameter
list, as you add any other parameter. Listing 26.13 is a short program that creates
an object from a class template, using two abstract parameters and one specific data
type.</P>
<P>
<H4>Listing 26.13  Using Specific Data Types as Parameters in a Class Template</H4>
<PRE>#include <iostream.h>
template<class Type1, class Type2, int num>
class CMyClass
{
protected:
Type1 data1;
Type2 data2;
int data3;
public:
CMyClass(Type1 arg1, Type2 arg2, int num)
{
data1 = arg1;
data2 = arg2;
data3 = num;
}
~CMyClass() {}
};
int main()
{
CMyClass<int, char, 0> myClass(15, `A', 10);
return 0;
</PRE>
<PRE>}
</PRE>
<H2><A NAME="Heading11"></A>The Standard Template Library</H2>
<P>Before running off to write templates that implement linked lists, binary trees,
sorting, and other common tasks, you might like to know that somebody else already
has. Visual C++ incorporates the Standard Template Library (STL), which includes
hundreds of function and class templates to tackle common tasks. Would you like a
stack of ints or a stack of floats? Don't write lots of different stack classes.
Don't even write one stack class template. Simply use the stack template included
in the STL. This applies to almost every common data structure.</P>
<P>
<H3><A NAME="Heading12"></A>Managed Pointer Templates: auto_ptr</H3>
<P>Earlier in this chapter you saw applications that use exceptions and allocate
memory on the heap (dynamic allocation with new) can run into trouble when exceptions
are thrown. If the delete statement for that memory gets bypassed, the memory will
leak. If there were an object on the stack whose destructor called delete for the
memory, you would prevent this problem. STL implements a managed pointer called auto_ptr.
Here's the declaration:</P>
<P>
<PRE>template<class T>
class auto_ptr {
public:
typedef T element_type;
explicit auto_ptr(T *p = 0) ;
auto_ptr(const auto_ptr<T>& rhs) ;
auto_ptr<T>& operator=(auto_ptr<T>& rhs);
~auto_ptr();
T& operator*() const ;
T *operator->() const;
T *get() const ;
T *release() const;
};
</PRE>
<P>After you create a pointer to an int, float, Employee, or any other type of object,
you can make an auto_ptr and use that like a pointer. For example, imagine a code
fragment like this:</P>
<P>
<PRE>// ...
Employee* emp = new Employee(stuff);
emp->ProcessEmployee;
delete emp;
// ...
</PRE>
<P>When you realize that ProcessEmployee() might throw an EmployeeException, you
can change this code to read like this:</P>
<P>
<PRE>// ...
Employee* emp = new Employee(stuff);
try
{
emp->ProcessEmployee;
}
catch (EmployeeException e)
{
delete emp;
throw;
}
delete emp;
// ...
</PRE>
<P>But you think this is ugly and hard to maintain, so you go with an auto_ptr instead:</P>
<P>
<PRE>#include <memory>
// ...
auto_ptr<Employee> emp (new Employee(stuff));
emp->ProcessEmployee;
// ...
</PRE>
<P>This looks like the first example, but it works like the second: Whether you leave
this code snippet normally or because of an exception, emp will go out of scope,
and when it does, the Employee object that was allocated on the heap will be deleted
for you automatically. No extra try or catch blocks, and as an extra bonus you don't
even have to remember to delete the memory in the routine--it's done for you.</P>
<P>Look again at the functions declared in the template: a constructor, a copy constructor,
an address-of (&) operator, a destructor, a contents of (*) operator, a dereferencing
(->) operator, and functions called get() and release(). These work together to
ensure that you can treat your pointer exactly as though it were an ordinary pointer.</P>
<P>
<H3><A NAME="Heading13"></A>Other Useful STL Templates</H3>
<P>STL is especially useful to ATL programmers, who may not be using MFC. Why drag
in all of MFC because you want to do a little string manipulation or manage a lookup
table or linked list? Use the STL versions of these common data structures instead.
The full details are in the online documentation, but be sure to look for these classes
or functions:</P>
<P>
<UL>
<LI>deque
<P>
<LI>list
<P>
<LI>map
<P>
<LI>multimap
<P>
<LI>set
<P>
<LI>multiset
<P>
<LI>vector
<P>
<LI>basic_string
<P>
<LI>stack
<P>
<LI>swap
<P>
<LI>min, max
</UL>
<P>There are many more, but these will give you an idea of the amount of work you
can save with templates, especially with templates you don't have to write.</P>
<P>
<H2><A NAME="Heading14"></A>Understanding Namespaces</H2>
<P>A <I>namespace</I> defines a scope in which duplicate identifiers cannot be used.
For example, you already know that you can have a global variable named value and
then also define a function with a local variable called value. Because the two variables
are in different namespaces, your program knows that it should use the local value
when inside the function and the global value everywhere else.</P>
<P>Namespaces, however, do not extend far enough to cover some very thorny problems.
One example is duplicate names in external classes or libraries. This issue crops
up when a programmer is using several external files within a single project. None
of the external variables and functions can have the same name as other external
variables or functions. To avoid this type of problem, third-party vendors frequently
add prefixes or suffixes to variable and function names in order to reduce the likeliness
of some other vendor using the same name.</P>
<P>Obviously, the C++ gurus have come up with a solution to such scope-resolution
problems. The solution is user-defined namespaces.</P>
<P>
<H3><A NAME="Heading15"></A>Defining a Namespace</H3>
<P>In its simplest form, a namespace is not unlike a structure or a class. You start
the namespace definition with the namespace keyword, followed by the namespace's
name and the declaration of the identifiers that will be valid within the scope of
that namespace.</P>
<P>Listing 26.16 shows a namespace definition. The namespace is called A and includes
two identifiers, i and j, and a function, Func(). Notice that the Func() function
is completely defined within the namespace definition. You can also choose to define
the function outside the namespace definition. In that case, you must preface the
function definition's name with the namespace's name, much as you would preface a
class's member-function definition with the class's name. Listing 26.17 shows this
form of namespace function definition.</P>
<P>
<H4>Listing 26.16  Defining a Namespace</H4>
<PRE>namespace A
{
int i;
int j;
int Func()
{
return 1;
}
</PRE>
<PRE>}
</PRE>
<H4>Listing 26.17  Defining a Function Outside the Namespace Definition</H4>
<PRE>namespace A
{
int i;
int j;
int Func();
}
int A::Func()
{
return 1;
</PRE>
<PRE>}
</PRE>
<BLOCKQUOTE>
<P>
<HR>
<strong>NOTE:</strong>amespaces must be defined at the file level of scope or within another
namespace definition. They cannot be defined, for example, inside a function. 
<HR>
</BLOCKQUOTE>
<H3><A NAME="Heading16"></A>Namespace Scope Resolution</H3>
<P>Namespaces add a new layer of scope to your programs, but this means that you
need some way of identifying that scope. The identification is, of course, the namespace's
name, which you must use in your programs to resolve references to identifiers. For
example, to refer to the variable i in namespace A, you'd write something like this:</P>
<P>
<PRE>A::i = 0;
</PRE>
<P>You can nest one namespace definition within another, as shown in Listing 26.18.
In that case, however, you have to use more complicated scope resolutions in order
to differentiate between the i variable declared in A and B, like this:</P>
<P>
<PRE>A::i = 0;
A::B::i = 0;
</PRE>
<H4>Listing 26.18 esting Namespace Definitions</H4>
<PRE>namespace A
{
int i;
int j;
int Func()
{
return 1;
}
namespace B
{
int i;
}
</PRE>
<PRE>}
</PRE>
<P>If you're going to frequently reference variables and functions within namespace
A, you can avoid using the A:: resolution by preceding the program statements with
a using line, as shown in Listing 26.19. This is very common in programs that use
STL templates, most of which are in the std namespace.</P>
<P>
<H4>Listing 26.19  Resolving Scope with the using Keyword</H4>
<PRE>using namespace A;
i = 0;
j = 0;
</PRE>
<PRE>int num1 = Func();
</PRE>
<H3><A NAME="Heading17"></A>Unnamed Namespaces</H3>
<P>To thoroughly confuse you, Visual C++ allows you to have unnamed namespaces. You
define an unnamed namespace exactly as you would any other namespace, without attaching
a name. Listing 26.20 shows the definition of an unnamed namespace. It lets you arrange
variables whose names are valid only within one namespace and cannot be accessed
from elsewhere because no other code can know the name of the unnamed namespace.</P>
<P>
<H4>Listing 26.20  Defining an Unnamed Namespace</H4>
<PRE>namespace
{
int i;
int j;
int Func()
{
return 1;
}
</PRE>
<PRE>}
</PRE>
<P>Refer to the identifiers in the unnamed namespace without any sort of extra scope
resolution, like this:</P>
<P>
<PRE>i = 0;
j = 0;
int num1 = Func();
</PRE>
<H3><A NAME="Heading18"></A>Namespace Aliases</H3>
<P>Often you run into namespaces that have long names. In these cases, having to
use the long name over and over in your program in order to access the identifiers
defined in the namespace can be a major chore. To solve this problem, Visual C++
enables you to create <I>namespace aliases</I>, which are just replacement names
for a namespace. You create an alias like this:</P>
<P>
<PRE>namespace A = LongName;
</PRE>
<P>LongName is the original name of the namespace, and A is the alias. After the
preceding line executes, you can access the LongName namespace, using either A or
LongName. You can think of an alias as a nickname or short form. Listing 26.21 is
a short program that demonstrates namespace aliases.</P>
<P>
<H4>Listing 26.21  Using a Namespace Alias</H4>
<PRE>namespace ThisIsANamespaceName
{
int i;
int j;
int Func()
{
return 2;
}
}
int main()
{
namespace ns = ThisIsANamespaceName;
ns::i = 0;
ns::j = 0;
int num1 = ns::Func();
return 0;
</PRE>
<PRE>}</PRE>
<H1></H1>
<CENTER>
<P>
<HR>
<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> <BR>
<BR>
</P>
<P>© <A HREF="../copy.htm">Copyright</A>, Macmillan Computer Publishing. All
rights reserved.
</CENTER>
</BODY>
</HTML>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -