📄 ch14.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<!-- This document was created from RTF source by rtftohtml version 3.0.1 -->
<META NAME="GENERATOR" Content="Symantec Visual Page 1.0">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
<TITLE>Teach Yourself C++ in 21 Days</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">
<H1 ALIGN="CENTER"><A HREF="ch13.htm" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/htm/ch13.htm"><IMG SRC="BLANPREV.GIF" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/buttons/BLANPREV.GIF"
WIDTH="37" HEIGHT="37" ALIGN="BOTTOM" BORDER="0"></A><A HREF="tppmsgs/msgs0.htm#1" tppabs="http://www.mcp.com/sams"><IMG
SRC="BLANHOME.GIF" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/buttons/BLANHOME.GIF" WIDTH="37" HEIGHT="37" ALIGN="BOTTOM"
BORDER="0"></A><A HREF="index.htm" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/index.htm"><IMG SRC="BLANTOC.GIF" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/buttons/BLANTOC.GIF"
WIDTH="37" HEIGHT="37" ALIGN="BOTTOM" BORDER="0"></A><A HREF="ch14rv2.htm" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/htm/ch14rv2.htm"><IMG SRC="BLANNEXT.GIF" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/buttons/BLANNEXT.GIF"
WIDTH="37" HEIGHT="37" ALIGN="BOTTOM" BORDER="0"></A></H1>
<H1></H1>
<UL>
<LI><A HREF="#Heading1">Day 14</A>
<UL>
<LI><A HREF="#Heading2">Special Classes and Functions</A>
<UL>
<LI><A HREF="#Heading3">Static Member Data</A>
<LI><A HREF="#Heading4">Listing 14.1. Static member data.</A>
<LI><A HREF="#Heading5">Listing 14.2. Accessing static members without an object</A><A
HREF="#Heading6">.</A>
<LI><A HREF="#Heading7">Listing 14.3. Accessing static members using non-static member
functions</A><A HREF="#Heading8">.</A>
<LI><A HREF="#Heading9">Static Member Functions</A>
<LI><A HREF="#Heading10">Listing 14.4. Static member functions</A><A HREF="#Heading11">.</A>
<LI><A HREF="#Heading12">Static Member Functions</A>
<LI><A HREF="#Heading13">Pointers to Functions</A>
<LI><A HREF="#Heading14">Listing 14.5. Pointers to functions</A><A HREF="#Heading15">.</A>
<LI><A HREF="#Heading16">Pointer to Function</A>
<UL>
<LI><A HREF="#Heading17">Why Use Function Pointers?</A>
</UL>
<LI><A HREF="#Heading18">Listing 14.6. Rewriting Listing 14.5 without the pointer
to function</A><A HREF="#Heading19">.</A>
<LI><A HREF="#Heading20">Shorthand Invocation</A>
<UL>
<LI><A HREF="#Heading21">Arrays of Pointers to Functions</A>
</UL>
<LI><A HREF="#Heading22">Listing 14.7. Demonstrates use of an array of pointers to
functions</A><A HREF="#Heading23">.</A>
<UL>
<LI><A HREF="#Heading24">Passing Pointers to Functions to Other Functions</A>
</UL>
<LI><A HREF="#Heading25">Listing 14.8. Passing pointers to functions</A>
<LI><A HREF="#Heading26">as function arguments.</A>
<UL>
<LI><A HREF="#Heading27">Using typedef with Pointers to Functions</A>
</UL>
<LI><A HREF="#Heading28">Listing 14.9. Using typedef to make pointers to functions
more readable</A><A HREF="#Heading29">.</A>
<LI><A HREF="#Heading30">Pointers to Member Functions</A>
<LI><A HREF="#Heading31">Listing 14.10. Pointers to member functions</A><A HREF="#Heading32">.</A>
<UL>
<LI><A HREF="#Heading33">Arrays of Pointers to Member Functions</A>
</UL>
<LI><A HREF="#Heading34">Listing 14.11. Array of pointers to member functions</A><A
HREF="#Heading35">.</A>
<LI><A HREF="#Heading36">Summary</A>
<LI><A HREF="#Heading37">Q&A</A>
<LI><A HREF="#Heading38">Workshop</A>
<UL>
<LI><A HREF="#Heading39">Quiz</A>
<LI><A HREF="#Heading40">Exercises</A>
</UL>
</UL>
</UL>
</UL>
<P>
<HR SIZE="4">
<H2 ALIGN="CENTER"><BR>
<A NAME="Heading1"></A><FONT COLOR="#000077">Day 14</FONT></H2>
<H2 ALIGN="CENTER"><A NAME="Heading2"></A><FONT COLOR="#000077">Special Classes and
Functions</FONT></H2>
<P>C++ offers a number of ways to limit the scope and impact of variables and pointers.
So far you've seen how to create global variables, local function variables, pointers
to variables, and class member variables. Today you learn
<UL>
<LI>What static member variables and static member functions are.
<P>
<LI>How to use static member variables and static member functions.
<P>
<LI>How to create and manipulate pointers to functions and pointers to member functions.
<P>
<LI>How to work with arrays of pointers to functions.
</UL>
<H3 ALIGN="CENTER"><A NAME="Heading3"></A><FONT COLOR="#000077">Static Member Data</FONT></H3>
<P>Until now, you have probably thought of the data in each object as unique to that
object and not shared among objects in a class. For example, if you have five <TT>Cat</TT>
objects, each has its own age, weight, and other data. The age of one does not affect
the age of another.</P>
<P>There are times, however, when you'll want to keep track of a pool of data. For
example, you might want to know how many objects for a specific class have been created
in your program, and how many are still in existence. Static member variables are
shared among all instances of a class. They are a compromise between global data,
which is available to all parts of your program, and member data, which is usually
available only to each object.</P>
<P>You can think of a static member as belonging to the class rather than to the
object. Normal member data is one per object, but static members are one per class.
Listing 14.1 declares a <TT>Cat</TT> object with a static data member, <TT>HowManyCats</TT>.
This variable keeps track of how many <TT>Cat</TT> objects have been created. This
is done by incrementing the static variable, <TT>HowManyCats</TT>, with each construction
and decrementing it with each destruction.</P>
<P><A NAME="Heading4"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 14.1. Static
member data.</B></FONT>
<PRE><FONT COLOR="#0066FF">1: //Listing 14.1 static data members
2:
3: #include <iostream.h>
4:
5: class Cat
6: {
7: public:
8: Cat(int age):itsAge(age){HowManyCats++; }
9: virtual ~Cat() { HowManyCats--; }
10: virtual int GetAge() { return itsAge; }
11: virtual void SetAge(int age) { itsAge = age; }
12: static int HowManyCats;
13:
14: private:
15: int itsAge;
16:
17: };
18:
19: int Cat::HowManyCats = 0;
20:
21: int main()
22: {
23: const int MaxCats = 5; int i;
24: Cat *CatHouse[MaxCats];
25: for (i = 0; i<MaxCats; i++)
26: CatHouse[i] = new Cat(i);
27:
28: for (i = 0; i<MaxCats; i++)
29: {
30: cout << "There are ";
31: cout << Cat::HowManyCats;
32: cout << " cats left!\n";
33: cout << "Deleting the one which is ";
34: cout << CatHouse[i]->GetAge();
35: cout << " years old\n";
36: delete CatHouse[i];
37: CatHouse[i] = 0;
38: }
39: return 0;
<TT>40: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: There are 5 cats left!
Deleting the one which is 0 years old
There are 4 cats left!
Deleting the one which is 1 years old
There are 3 cats left!
Deleting the one which is 2 years old
There are 2 cats left!
Deleting the one which is 3 years old
There are 1 cats left!
Deleting the one which is 4 years old
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>On lines 5 to 17 the simplified
class <TT>Cat</TT> is declared. On line 12, <TT>HowManyCats</TT> is declared to be
a static member variable of type <TT>int</TT>.</P>
<P>The declaration of <TT>HowManyCats</TT> does not define an integer; no storage
space is set aside. Unlike the non-static member variables, no storage space is set
aside by instantiating a <TT>Cat</TT> object, because the <TT>HowManyCats</TT> member
variable is not in the object. Thus, on line 19 the variable is defined and initialized.</P>
<P>It is a common mistake to forget to define the static member variables of classes.
Don't let this happen to you! Of course, if it does, the linker will catch it with
a pithy error message such as the following:</P>
<PRE><FONT COLOR="#0066FF">undefined symbol Cat::HowManyCats
</FONT></PRE>
<P>You don't need to do this for <TT>itsAge</TT>, because it is a non-static member
variable and is defined each time you make a <TT>Cat</TT> object, which you do here
on line 26.</P>
<P>The constructor for <TT>Cat</TT> increments the static member variable on line
8. The destructor decrements it on line 9. Thus, at any moment, <TT>HowManyCats</TT>
has an accurate measure of how many <TT>Cat</TT> objects were created but not yet
destroyed.</P>
<P>The driver program on lines 21-40 instantiates five <TT>Cat</TT>s and puts them
in an array. This calls five <TT>Cat</TT> constructors, and thus <TT>HowManyCats</TT>
is incremented five times from its initial value of <TT>0</TT>.</P>
<P>The program then loops through each of the five positions in the array and prints
out the value of <TT>HowManyCats</TT> before deleting the current <TT>Cat</TT> pointer.
The printout reflects that the starting value is <TT>5</TT> (after all, 5 are constructed),
and that each time the loop is run, one fewer <TT>Cat</TT> remains.</P>
<P>Note that <TT>HowManyCats</TT> is public and is accessed directly by <TT>main()</TT>.
There is no reason to expose this member variable in this way. It is preferable to
make it private along with the other member variables and provide a public accessor
method, as long as you will always access the data through an instance of <TT>Cat</TT>.
On the other hand, if you'd like to access this data directly without necessarily
having a <TT>Cat</TT> object available, you have two options: keep it public, as
shown in Listing 14.2, or provide a static member function, as discussed later in
this chapter.</P>
<P><A NAME="Heading5"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 14.2. Accessing
static members without an object.</B></FONT>
<PRE><FONT COLOR="#0066FF">1: //Listing 14.2 static data members
2:
3: #include <iostream.h>
4:
5: class Cat
6: {
7: public:
8: Cat(int age):itsAge(age){HowManyCats++; }
9: virtual ~Cat() { HowManyCats--; }
10: virtual int GetAge() { return itsAge; }
11: virtual void SetAge(int age) { itsAge = age; }
12: static int HowManyCats;
13:
14: private:
15: int itsAge;
16:
17: };
18:
19: int Cat::HowManyCats = 0;
20:
21: void TelepathicFunction();
22:
23: int main()
24: {
25: const int MaxCats = 5; int i;
26: Cat *CatHouse[MaxCats];
27: for (i = 0; i<MaxCats; i++)
28: {
29: CatHouse[i] = new Cat(i);
30: TelepathicFunction();
31: }
32:
33: for ( i = 0; i<MaxCats; i++)
34: {
35: delete CatHouse[i];
36: TelepathicFunction();
37: }
38: return 0;
39: }
40:
41: void TelepathicFunction()
42: {
43: cout << "There are ";
44: cout << Cat::HowManyCats << " cats alive!\n";
<TT>45: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: There are 1 cats alive!
There are 2 cats alive!
There are 3 cats alive!
There are 4 cats alive!
There are 5 cats alive!
There are 4 cats alive!
There are 3 cats alive!
There are 2 cats alive!
There are 1 cats alive!
There are 0 cats alive!
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>Listing 14.2 is much like
Listing 14.1 except for the addition of a new function, <TT>TelepathicFunction()</TT>.
This function does not create a <TT>Cat</TT> object, nor does it take a <TT>Cat</TT>
object as a parameter, yet it can access the <TT>HowManyCats</TT> member variable.
Again, it is worth reemphasizing that this member variable is not in any particular
object; it is in the class as a whole, and, if public, can be accessed by any function
in the program.</P>
<P>The alternative to making this member variable public is to make it private. If
you do, you can access it through a member function, but then you must have an object
of that class available. Listing 14.3 shows this approach. The alternative, static
member functions, is discussed immediately after the analysis of Listing 14.3.</P>
<P><A NAME="Heading7"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 14.3. Accessing
static members using non-static member functions.</B></FONT>
<PRE><FONT COLOR="#0066FF">1: //Listing 14.3 private static data members
2:
3: #include <iostream.h>
4:
5: class Cat
6: {
7: public:
8: Cat(int age):itsAge(age){HowManyCats++; }
9: virtual ~Cat() { HowManyCats--; }
10: virtual int GetAge() { return itsAge; }
11: virtual void SetAge(int age) { itsAge = age; }
12: virtual int GetHowMany() { return HowManyCats; }
13:
14:
15: private:
16: int itsAge;
17: static int HowManyCats;
18: };
19:
20: int Cat::HowManyCats = 0;
21:
22: int main()
23: {
24: const int MaxCats = 5; int i;
25: Cat *CatHouse[MaxCats];
26: for (i = 0; i<MaxCats; i++)
27: CatHouse[i] = new Cat(i);
28:
29: for (i = 0; i<MaxCats; i++)
30: {
31: cout << "There are ";
32: cout << CatHouse[i]->GetHowMany();
33: cout << " cats left!\n";
34: cout << "Deleting the one which is ";
35: cout << CatHouse[i]->GetAge()+2;
36: cout << " years old\n";
37: delete CatHouse[i];
38: CatHouse[i] = 0;
39: }
40: return 0;
<TT>41: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: There are 5 cats left!
Deleting the one which is 2 years old
There are 4 cats left!
Deleting the one which is 3 years old
There are 3 cats left!
Deleting the one which is 4 years old
There are 2 cats left!
Deleting the one which is 5 years old
There are 1 cats left!
Deleting the one which is 6 years old
</FONT></PRE>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -