A pointer to a function contains the address of the function in memory. In Chapter 7, we saw that the name of an array is actually the address in memory of the first element of the array. Similarly, the name of a function is actually the starting address in memory of the code that performs the function's task. Pointers to functions can be passed to functions, returned from functions, stored in arrays and assigned to other function pointers.
Multipurpose Selection Sort Using Function Pointers
To illustrate the use of pointers to functions, Fig. 8.28 modifies the selection sort program of Fig. 8.15. Figure 8.28 consists of main (lines 1755) and the functions selectionSort (lines 5976), swap (lines 8085), ascending (lines 8992) and descending (lines 9699). Function selectionSort receives a pointer to a functioneither function ascending or function descendingas an argument in addition to the integer array to sort and the size of the array. Functions ascending and descending determine the sorting order. The program prompts the user to choose whether the array should be sorted in ascending order or in descending order (lines 2426). If the user enters 1, a pointer to function ascending is passed to function selectionSort (line 37), causing the array to be sorted into increasing order. If the user enters 2, a pointer to function descending is passed to function selectionSort (line 45), causing the array to be sorted into decreasing order.
Figure 8.28. Multipurpose sorting program using function pointers.
(This item is displayed on pages 439 - 441 in the print version)
1 // Fig. 8.28: fig08_28.cpp 2 // Multipurpose sorting program using function pointers. 3 #include 4 using std::cout; 5 using std::cin; 6 using std::endl; 7 8 #include 9 using std::setw; 10 11 // prototypes 12 void selectionSort( int [], const int, bool (*)( int, int ) ); 13 void swap( int * const, int * const ); 14 bool ascending( int, int ); // implements ascending order 15 bool descending( int, int ); // implements descending order 16 17 int main() 18 { 19 const int arraySize = 10; 20 int order; // 1 = ascending, 2 = descending 21 int counter; // array index 22 int a[ arraySize ] = { 2, 6, 4, 8, 10, 12, 89, 68, 45, 37 }; 23 24 cout << "Enter 1 to sort in ascending order, " 25 << "Enter 2 to sort in descending order: "; 26 cin >> order; 27 cout << " Data items in original order "; 28 29 // output original array 30 for ( counter = 0; counter < arraySize; counter++ ) 31 cout << setw( 4 ) << a[ counter ]; 32 33 // sort array in ascending order; pass function ascending 34 // as an argument to specify ascending sorting order 35 if ( order == 1 ) 36 { 37 selectionSort( a, arraySize, ascending ); 38 cout << " Data items in ascending order "; 39 } // end if 40 41 // sort array in descending order; pass function descending 42 // as an argument to specify descending sorting order 43 else 44 { 45 selectionSort( a, arraySize, descending ); 46 cout << " Data items in descending order "; 47 } // end else part of if...else 48 49 // output sorted array 50 for ( counter = 0; counter < arraySize; counter++ ) 51 cout << setw( 4 ) << a[ counter ]; 52 53 cout << endl; 54 return 0; // indicates successful termination 55 } // end main 56 57 // multipurpose selection sort; the parameter compare is a pointer to 58 // the comparison function that determines the sorting order 59 void selectionSort( int work[], const int size, 60 bool (*compare)( int, int ) ) 61 { 62 int smallestOrLargest; // index of smallest (or largest) element 63 64 // loop over size - 1 elements 65 for ( int i = 0; i < size - 1; i++ ) 66 { 67 smallestOrLargest = i; // first index of remaining vector 68 69 // loop to find index of smallest (or largest) element 70 for ( int index = i + 1; index < size; index++ ) 71 if ( !(*compare)( work[ smallestOrLargest ], work[ index ] ) ) 72 smallestOrLargest = index; 73 74 swap( &work[ smallestOrLargest ], &work[ i ] ); 75 } // end if 76 } // end function selectionSort 77 78 // swap values at memory locations to which 79 // element1Ptr and element2Ptr point 80 void swap( int * const element1Ptr, int * const element2Ptr ) 81 { 82 int hold = *element1Ptr; 83 *element1Ptr = *element2Ptr; 84 *element2Ptr = hold; 85 } // end function swap 86 87 // determine whether element a is less than 88 // element b for an ascending order sort 89 bool ascending( int a, int b ) 90 { 91 return a < b; // returns true if a is less than b 92 } // end function ascending 93 94 // determine whether element a is greater than 95 // element b for a descending order sort 96 bool descending( int a, int b ) 97 { 98 return a > b; // returns true if a is greater than b 99 } // end function descending
|
The following parameter appears in line 60 of selectionSort's function header:
bool ( *compare )( int, int )
This parameter specifies a pointer to a function. The keyword bool indicates that the function being pointed to returns a bool value. The text ( *compare ) indicates the name of the pointer to the function (the * indicates that parameter compare is a pointer). The text ( int, int ) indicates that the function pointed to by compare takes two integer arguments. Parentheses are needed around *compare to indicate that compare is a pointer to a function. If we had not included the parentheses, the declaration would have been
bool *compare( int, int )
which declares a function that receives two integers as parameters and returns a pointer to a bool value.
The corresponding parameter in the function prototype of selectionSort is
bool (*)( int, int )
Note that only types have been included. As always, for documentation purposes, the programmer can include names that the compiler will ignore.
The function passed to selectionSort is called in line 71 as follows:
( *compare )( work[ smallestOrLargest ], work[ index ] )
Just as a pointer to a variable is dereferenced to access the value of the variable, a pointer to a function is dereferenced to execute the function. The parentheses around *compare are again necessaryif they were left out, the * operator would attempt to dereference the value returned from the function call. The call to the function could have been made without dereferencing the pointer, as in
compare( work[ smallestOrLargest ], work[ index ] )
which uses the pointer directly as the function name. We prefer the first method of calling a function through a pointer, because it explicitly illustrates that compare is a pointer to a function that is dereferenced to call the function. The second method of calling a function through a pointer makes it appear as though compare is the name of an actual function in the program. This may be confusing to a user of the program who would like to see the definition of function compare and finds that it is not defined in the file.
Arrays of Pointers to Functions
One use of function pointers is in menu-driven systems. For example, a program might prompt a user to select an option from a menu by entering an integer values. The user's choice can be used as a subscript into an array of function pointers, and the pointer in the array can be used to call the function.
Figure 8.29 provides a mechanical example that demonstrates declaring and using an array of pointers to functions. The program defines three functionsfunction0, function1 and function2that each take an integer argument and do not return a value. Line 17 stores pointers to these three functions in array f. In this case, all the functions to which the array points must have the same return type and same parameter types. The declaration in line 17 is read beginning in the leftmost set of parentheses as, "f is an array of three pointers to functions that each take an int as an argument and return void." The array is initialized with the names of the three functions (which, again, are pointers). The program prompts the user to enter a number between 0 and 2, or 3 to terminate. When the user enters a value between 0 and 2, the value is used as the subscript into the array of pointers to functions. Line 29 invokes one of the functions in array f. In the call, f[ choice ] selects the pointer at location choice in the array. The pointer is dereferenced to call the function, and choice is passed as the argument to the function. Each function prints its argument's value and its function name to indicate that the function is called correctly. In the exercises, you will develop a menu-driven system. We will see in Chapter 13, Object-Oriented Programming: Polymorphism, that arrays of pointers to functions are used by compiler developers to implement the mechanisms that support virtual functionsthe key technology behind polymorphism.
Figure 8.29. Array of pointers to functions.
(This item is displayed on pages 442 - 443 in the print version)
1 // Fig. 8.29: fig08_29.cpp 2 // Demonstrating an array of pointers to functions. 3 #include 4 using std::cout; 5 using std::cin; 6 using std::endl; 7 8 // function prototypes -- each function performs similar actions 9 void function0( int ); 10 void function1( int ); 11 void function2( int ); 12 13 int main() 14 { 15 // initialize array of 3 pointers to functions that each 16 // take an int argument and return void 17 void (*f[ 3 ])( int ) = { function0, function1, function2 }; 18 19 int choice; 20 21 cout << "Enter a number between 0 and 2, 3 to end: "; 22 cin >> choice; 23 24 // process user's choice 25 while ( ( choice >= 0 ) && ( choice < 3 ) ) 26 { 27 // invoke the function at location choice in 28 // the array f and pass choice as an argument 29 (*f[ choice ])( choice ); 30 31 cout << "Enter a number between 0 and 2, 3 to end: "; 32 cin >> choice; 33 } // end while 34 35 cout << "Program execution completed." << endl; 36 return 0; // indicates successful termination 37 } // end main 38 39 void function0( int a ) 40 { 41 cout << "You entered " << a << " so function0 was called "; 42 } // end function function0 43 44 void function1( int b ) 45 { 46 cout << "You entered " << b << " so function1 was called "; 47 } // end function function1 48 49 void function2( int c ) 50 { 51 cout << "You entered " << c << " so function2 was called "; 52 } // end function function2
|
Introduction to Computers, the Internet and World Wide Web
Introduction to C++ Programming
Introduction to Classes and Objects
Control Statements: Part 1
Control Statements: Part 2
Functions and an Introduction to Recursion
Arrays and Vectors
Pointers and Pointer-Based Strings
Classes: A Deeper Look, Part 1
Classes: A Deeper Look, Part 2
Operator Overloading; String and Array Objects
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
Templates
Stream Input/Output
Exception Handling
File Processing
Class string and String Stream Processing
Web Programming
Searching and Sorting
Data Structures
Bits, Characters, C-Strings and structs
Standard Template Library (STL)
Other Topics
Appendix A. Operator Precedence and Associativity Chart
Appendix B. ASCII Character Set
Appendix C. Fundamental Types
Appendix D. Number Systems
Appendix E. C Legacy Code Topics
Appendix F. Preprocessor
Appendix G. ATM Case Study Code
Appendix H. UML 2: Additional Diagram Types
Appendix I. C++ Internet and Web Resources
Appendix J. Introduction to XHTML
Appendix K. XHTML Special Characters
Appendix L. Using the Visual Studio .NET Debugger
Appendix M. Using the GNU C++ Debugger
Bibliography