📄 ch14.htm
字号:
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 MemberFunctions</FONT></H3><P>Up until this point, all of the function pointers you've created have been forgeneral, non-class functions. It is also possible to create pointers to functionsthat are members of classes.</P><P>To create a pointer to member function, use the same syntax as with a pointerto 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>, whichtakes two integers and returns <TT>void</TT>, the declaration for <TT>pFunc</TT>is the following:</P><PRE><FONT COLOR="#0066FF">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><P><A NAME="Heading31"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 14.10. Pointersto member functions.</B></FONT><PRE><FONT COLOR="#0066FF">1: //Listing 14.10 Pointers to member functions using virtual methods2:3: #include <iostream.h>4:5: enum BOOL {FALSE, TRUE};6: class Mammal7: {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 Mammal18: {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 Mammal26: {27: public:28: void Speak()const { cout << "Meow!\n"; }29: void Move() const { cout << "slinking...\n"; }30: };31:32:33: class Horse : public Mammal34: {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: 1Woof!(0)Quit (1)dog (2)cat (3)horse: 2(1)Speak (2)Move: 1Meow!(0)Quit (1)dog (2)cat (3)horse: 3(1)Speak (2)Move: 2Galloping(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 abstractdata 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 animalto create, and then a new subclass of <TT>Animal</TT> is created on the free storeand 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 assignedto the pointer <TT>pFunc</TT>. On line 71, the method chosen is invoked by the objectcreated, 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> toreturn the memory set aside for the object to the free store. Note that there isno reason to call <TT>delete</TT> on <TT>pFunc</TT> because this is a pointer tocode, not to an object on the free store. In fact, attempting to do so will generatea compile-time error.<H4 ALIGN="CENTER"><A NAME="Heading33"></A><FONT COLOR="#000077">Arrays of Pointersto Member Functions</FONT></H4><P>As with pointers to functions, pointers to member functions can be stored in anarray. 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 thistechnique.</P><P><A NAME="Heading34"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 14.11. Arrayof pointers to member functions.</B></FONT><PRE><FONT COLOR="#0066FF">1: //Listing 14.11 Array of pointers to member functions2:3: #include <iostream.h>4:5: enum BOOL {FALSE, TRUE};6:7: class Dog8: {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: else47: {48: pDog = new Dog;49: (pDog->*DogFunctions[Method-1])();50: delete pDog;51: }52: }53: return 0;<TT>54: }</TT></FONT><FONT COLOR="#0066FF"> Output: (0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll Over (7)Play Dead: 1Woof! (0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll Over (7)Play Dead: 4Grrr (0)Quit (1)Speak (2)Move (3)Eat (4)Growl (5)Whimper (6)Roll Over (7)Play Dead: 7Is 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 memberfunction of <TT>Dog</TT> that takes no parameters and returns no values, and thatis <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 memberfunctions, 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 invokedon the array on line 49. Here's another good line to show to the hotshot C++ programmersin your company; ask them what this does:</P><PRE><FONT COLOR="#0066FF">(pDog->*DogFunctions[Method-1])();</FONT></PRE><P>Once again, this is a bit esoteric, but when you need a table built from memberfunctions, it can make your program far easier to read and understand.<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></BLOCKQUOTE><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 possibleto access this member variable without an object of the class type by fully qualifyingthe 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 variablesdoes not allocate memory, and static member variables must be defined and initializedoutside the declaration of the class.</P><P>Static member functions are part of the class in the same way that static membervariables are. They can be accessed without a particular object of the class, andcan be used to access static member data. Static member functions cannot be usedto 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 alsocannot be made <TT>const</TT>. <TT>const</TT> in a member function indicates thatthe <TT>this</TT> pointer is <TT>const</TT>.</P><P>You also learned how to declare and use pointers to functions and pointers tomember functions. You saw how to create arrays of these pointers and how to passthem to functions.</P><P>Pointers to functions and pointers to member functions can be used to create tablesof functions that can be selected from at runtime. This can give your program flexibilitythat is not easily achieved without these pointers.<H3 ALIGN="CENTER"><A NAME="Heading37"></A><FONT COLOR="#000077">Q&A</FONT></H3><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><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 thematerial covered and exercises to provide you with experience in using what you'velearned. Try to answer the quiz and exercise questions before checking the answersin Appendix D, and make sure you understand the answers before going to the nextchapter.<H4 ALIGN="CENTER"><A NAME="Heading39"></A><FONT COLOR="#000077">Quiz</FONT></H4><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><H4 ALIGN="CENTER"><A NAME="Heading40"></A><FONT COLOR="#000077">Exercises</FONT></H4><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><P 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"><IMGSRC="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><A HREF="#heading1"><IMG SRC="BLANTOP.GIF" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/buttons/BLANTOP.GIF"WIDTH="37" HEIGHT="37" ALIGN="BOTTOM" BORDER="0"></A></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -