?? 014.htm
字號:
and takes two parameters, both integer references."</P>
<P>On line 10, the function <TT>PrintVals()</TT> is declared to take three parameters:
a <TT>VPF</TT> and two integer references. On line 19, <TT>pFunc</TT> is now declared
to be of type <TT>VPF</TT>.</P>
<P>Once the type <TT>VPF</TT> is defined, all subsequent uses to declare <TT>pFunc</TT>
and <TT>PrintVals()</TT> are much cleaner. As you can see, the output is identical.
<H3 ALIGN="CENTER"><A NAME="Heading30"></A><FONT COLOR="#000077">Pointers to Member
Functions</FONT></H3>
<P>Up until this point, all of the function pointers you've created have been for
general, non-class functions. It is also possible to create pointers to functions
that are members of classes.</P>
<P>To create a pointer to member function, use the same syntax as with a pointer
to function, but include the class name and the scoping operator (<TT>::</TT>). Thus,
if <TT>pFunc</TT> points to a member function of the class <TT>Shape</TT>, which
takes two integers and returns <TT>void</TT>, the declaration for <TT>pFunc</TT>
is the following:</P>
<PRE><FONT COLOR="#0066FF" font style="font-size:10pt">void (Shape::*pFunc) (int, int);
</FONT></PRE>
<P>Pointers to member functions are used in exactly the same way as pointers to functions,
except that they require an object of the correct class on which to invoke them.
Listing 14.10 illustrates the use of pointers to member functions.</P>
<BR>
<P><A NAME="Heading31"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 14.10. Pointers
to member functions.</B></FONT>
<PRE><FONT COLOR="#0066FF" font style="font-size:10pt">1: //Listing 14.10 Pointers to member functions using virtual methods
2:
3: #include <iostream.h>
4:
5: enum BOOL {FALSE, TRUE};
6: class Mammal
7: {
8: public:
9: Mammal():itsAge(1) { }
10: ~Mammal() { }
11: virtual void Speak() const = 0;
12: virtual void Move() const = 0;
13: protected:
14: int itsAge;
15: };
16:
17: class Dog : public Mammal
18: {
19: public:
20: void Speak()const { cout << "Woof!\n"; }
21: void Move() const { cout << "Walking to heel...\n"; }
22: };
23:
24:
25: class Cat : public Mammal
26: {
27: public:
28: void Speak()const { cout << "Meow!\n"; }
29: void Move() const { cout << "slinking...\n"; }
30: };
31:
32:
33: class Horse : public Mammal
34: {
35: public:
36: void Speak()const { cout << "Winnie!\n"; }
37: void Move() const { cout << "Galloping...\n"; }
38: };
39:
40:
41: int main()
42: {
43: void (Mammal::*pFunc)() const =0;
44: Mammal* ptr =0;
45: int Animal;
46: int Method;
47: BOOL fQuit = FALSE;
48:
49: while (fQuit == FALSE)
50: {
51: cout << "(0)Quit (1)dog (2)cat (3)horse: ";
52: cin >> Animal;
53: switch (Animal)
54: {
55: case 1: ptr = new Dog; break;
56: case 2: ptr = new Cat; break;
57: case 3: ptr = new Horse; break;
58: default: fQuit = TRUE; break;
59: }
60: if (fQuit)
61: break;
62:
63: cout << "(1)Speak (2)Move: ";
64: cin >> Method;
65: switch (Method)
66: {
67: case 1: pFunc = Mammal::Speak; break;
68: default: pFunc = Mammal::Move; break;
69: }
70:
71: (ptr->*pFunc)();
72: delete ptr;
73: }
74: return 0;
<TT>75: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: (0)Quit (1)dog (2)cat (3)horse: 1
(1)Speak (2)Move: 1
Woof!
(0)Quit (1)dog (2)cat (3)horse: 2
(1)Speak (2)Move: 1
Meow!
(0)Quit (1)dog (2)cat (3)horse: 3
(1)Speak (2)Move: 2
Galloping
(0)Quit (1)dog (2)cat (3)horse: 0
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>On lines 6-15, the abstract
data type <TT>Mammal</TT> is declared with two pure virtual methods, <TT>Speak()</TT>
and <TT>Move()</TT>. <TT>Mammal</TT> is subclassed into <TT>Dog</TT>, <TT>Cat</TT>,
and <TT>Horse</TT>, each of which overrides <TT>Speak()</TT> and <TT>Move()</TT>.</P>
<P>The driver program in <TT>main()</TT> asks the user to choose which type of animal
to create, and then a new subclass of <TT>Animal</TT> is created on the free store
and assigned to <TT>ptr</TT> on lines 55-57.</P>
<P>The user is then prompted for which method to invoke, and that method is assigned
to the pointer <TT>pFunc</TT>. On line 71, the method chosen is invoked by the object
created, by using the pointer <TT>ptr</TT> to access the object and <TT>pFunc</TT>
to access the function.</P>
<P>Finally, on line 72, <TT>delete</TT> is called on the pointer <TT>ptr</TT> to
return the memory set aside for the object to the free store. Note that there is
no reason to call <TT>delete</TT> on <TT>pFunc</TT> because this is a pointer to
code, not to an object on the free store. In fact, attempting to do so will generate
a compile-time error.
<H4 ALIGN="CENTER"><A NAME="Heading33"></A><FONT COLOR="#000077">Arrays of Pointers
to Member Functions</FONT></H4>
<P>As with pointers to functions, pointers to member functions can be stored in an
array. The array can be initialized with the addresses of various member functions,
and these can be invoked by offsets into the array. Listing 14.11 illustrates this
technique.</P>
<BR>
<P><A NAME="Heading34"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 14.11. Array
of pointers to member functions.</B></FONT>
<PRE><FONT COLOR="#0066FF" font style="font-size:10pt">1: //Listing 14.11 Array of pointers to member functions
2:
3: #include <iostream.h>
4:
5: enum BOOL {FALSE, TRUE};
6:
7: class Dog
8: {
9: public:
10: void Speak()const { cout << "Woof!\n"; }
11: void Move() const { cout << "Walking to heel...\n"; }
12: void Eat() const { cout << "Gobbling food...\n"; }
13: void Growl() const { cout << "Grrrrr\n"; }
14: void Whimper() const { cout << "Whining noises...\n"; }
15: void RollOver() const { cout << "Rolling over...\n"; }
16: void PlayDead() const { cout << "Is this the end of Little Caeser?\n"; }
17: };
18:
19: typedef void (Dog::*PDF)()const ;
20: int main()
21: {
22: const int MaxFuncs = 7;
23: PDF DogFunctions[MaxFuncs] =
24: { Dog::Speak,
25: Dog::Move,
26: Dog::Eat,
27: Dog::Growl,
28: Dog::Whimper,
29: Dog::RollOver,
30: Dog::PlayDead };
31:
32: Dog* pDog =0;
33: int Method;
34: BOOL fQuit = FALSE;
35:
36: while (!fQuit)
37: {
38: cout << "(0)Quit (1)Speak (2)Move (3)Eat (4)Growl";
39: cout << " (5)Whimper (6)Roll Over (7)Play Dead: ";
40: cin >> Method;
41: if (Method == 0)
42: {
43: fQuit = TRUE;
44: break;
45: }
46: else
47: {
48: pDog = new Dog;
49: (pDog->*DogFunctions[Method-1])();
50: delete pDog;
51: }
52: }
53: return 0;
<TT>54: }</TT></FONT>
<FONT COLOR="#0066FF" font style="font-size:10pt">
Output: (0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll Over (7)Play Dead: 1
Woof!
(0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll Over (7)Play Dead: 4
Grrr
(0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll Over (7)Play Dead: 7
Is this the end of Little Caeser?
(0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll Over (7)Play Dead: 0
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis: </B></FONT>On lines 7-17, the class <TT>Dog</TT>
is created, with 7 member functions all sharing the same return type and signature.
On line 19, a <TT>typedef</TT> declares <TT>PDF</TT> to be a pointer to a member
function of <TT>Dog</TT> that takes no parameters and returns no values, and that
is <TT>const</TT>: the signature of the 7 member functions of <TT>Dog</TT>.</P>
<P>On lines 23-30, the array <TT>DogFunctions</TT> is declared to hold 7 such member
functions, and it is initialized with the addresses of these functions.</P>
<P>On lines 38 and 39, the user is prompted to pick a method. Unless they pick <TT>Quit</TT>,
a new <TT>Dog</TT> is created on the heap, and then the correct method is invoked
on the array on line 49. Here's another good line to show to the hotshot C++ programmers
in your company; ask them what this does:</P>
<PRE><FONT COLOR="#0066FF" font style="font-size:10pt">(pDog->*DogFunctions[Method-1])();
</FONT></PRE>
<P>Once again, this is a bit esoteric, but when you need a table built from member
functions, it can make your program far easier to read and understand.
<BR>
<BR>
<BLOCKQUOTE>
<P>
<HR>
<B>DO</B> invoke pointers to member functions on a specific object of a class.<B>
DO </B>use <TT>typedef</TT> to make pointer to member function declarations easier
to read. <B>DON'T </B>use pointer to member functions when there are simpler solutions.
<HR>
<BR>
<BR>
</BLOCKQUOTE>
<BR>
<H3 ALIGN="CENTER"><A NAME="Heading36"></A><FONT COLOR="#000077">Summary</FONT></H3>
<P>Today you learned how to create static member variables in your class. Each class,
rather than each object, has one instance of the static member variable. It is possible
to access this member variable without an object of the class type by fully qualifying
the name, assuming you've declared the static member to have public access.</P>
<P>Static member variables can be used as counters across instances of the class.
Because they are not part of the object, the declaration of static member variables
does not allocate memory, and static member variables must be defined and initialized
outside the declaration of the class.</P>
<P>Static member functions are part of the class in the same way that static member
variables are. They can be accessed without a particular object of the class, and
can be used to access static member data. Static member functions cannot be used
to access non-static member data because they do not have a this pointer.</P>
<P>Because static member functions do not have a <TT>this</TT> pointer, they also
cannot be made <TT>const</TT>. <TT>const</TT> in a member function indicates that
the <TT>this</TT> pointer is <TT>const</TT>.</P>
<P>You also learned how to declare and use pointers to functions and pointers to
member functions. You saw how to create arrays of these pointers and how to pass
them to functions.</P>
<P>Pointers to functions and pointers to member functions can be used to create tables
of functions that can be selected from at runtime. This can give your program flexibility
that is not easily achieved without these pointers.
<H3 ALIGN="CENTER"><A NAME="Heading37"></A><FONT COLOR="#000077">Q&A</FONT></H3>
<BR>
<DL>
<DD><B>Q. Why use static data when you can use global data?<BR>
</B><BR>
<B>A</B>. Static data is scoped to the class. In this manner, static data are available
only through an object of the class, through an explicit call using the class name
if they are public, or by using a static member function. Static data are typed to
the class type, however, and the restricted access and strong typing makes static
data safer than global data.<BR>
<BR>
<B>Q. Why use static member functions when you can use global functions?<BR>
</B><BR>
<B>A.</B> Static member functions are scoped to the class, and can be called only
by using an object of the class or an explicit full specification (such as <TT>ClassName::FunctionName()</TT>).<BR>
<BR>
<B>Q. Is it common to use many pointers to functions and pointers to member functions?<BR>
</B><BR>
<B>A.</B> No, these have their special uses, but are not common constructs. Many
complex and powerful programs have neither.
</DL>
<BR>
<H3 ALIGN="CENTER"><A NAME="Heading38"></A><FONT COLOR="#000077">Workshop</FONT></H3>
<P>The Workshop contains quiz questions to help solidify your understanding of the
material covered and exercises to provide you with experience in using what you've
learned. Try to answer the quiz and exercise questions before checking the answers
in Appendix D, and make sure you understand the answers before going to the next
chapter.
<H4 ALIGN="CENTER"><A NAME="Heading39"></A><FONT COLOR="#000077">Quiz</FONT></H4>
<BR>
<DL>
<DD><B>1.</B> Can static member variables be private?<BR>
<B><BR>
2.</B> Show the declaration for a static member variable.<BR>
<B><BR>
3.</B> Show the declaration for a static function pointer.<BR>
<B><BR>
4.</B> Show the declaration for a pointer to function returning <TT>long</TT> and
taking an integer parameter.<BR>
<B><BR>
5.</B> Modify the pointer in Question 4 so it's a pointer to member function of class
<TT>Car</TT>.<BR>
<B><BR>
6.</B> Show the declaration for an array of 10 pointers as defined in Question 5.
</DL>
<BR>
<H4 ALIGN="CENTER"><A NAME="Heading40"></A><FONT COLOR="#000077">Exercises</FONT></H4>
<BR>
<DL>
<DD><B>1.</B> Write a short program declaring a class with one member variable and
one static member variable. Have the constructor initialize the member variable and
increment the static member variable. Have the destructor decrement the member variable.<BR>
<B><BR>
2.</B> Using the program from Exercise 1, write a short driver program that makes
three objects and then displays their member variables and the static member variable.
Then <BR>
destroy each object and show the effect on the static member variable.<BR>
<B><BR>
3.</B> Modify the program from Exercise 2 to use a static member function to access
the static member variable. Make the static member variable private.<BR>
<B><BR>
4.</B> Write a pointer to member function to access the non-static member data in
the program in Exercise 3, and use that pointer to print the value of that data.<BR>
<B><BR>
5.</B> Add two more member variables to the class from the previous questions. Add
accessor functions that get the value of these values, and give all the member functions
the same return values and signatures. Use the pointer to member function to access
these functions.
</DL>
</ul>
</TD>
<TD CLASS="tt3" VALIGN="bottom" width="8%" bgcolor="#ffffff"><strong><A HREF="015.htm"><FONT style="FONT-SIZE: 9pt">后一頁</font></A><BR>
<A HREF="013.htm"><FONT style="FONT-SIZE: 9pt">前一頁</font></A></tr>
</table>
<p align="center"><script src="../../../2.js"></script> </p>
</body>
</html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -