Pointers to Functions

Just as an array name is a constant pointer to the first element of the array, a function name is a constant pointer to the function. It is possible to declare a pointer variable that points to a function, and to invoke the function by using that pointer. This can be very useful; it allows you to create programs that decide which functions to invoke based on user input.

The only tricky part about function pointers is understanding the type of the object being pointed to. A pointer to int points to an integer variable, and a pointer to a function must point to a function of the appropriate return type and signature.

In the declaration

long (* funcPtr) (int);

funcPtr is declared to be a pointer (note the * in front of the name) that points to a function that takes an integer parameter and returns a long. The parentheses around * funcPtr are necessary because the parentheses around int bind more tightly—that is, they have higher precedence than the indirection operator (*). Without the first parenthesis, this would declare a function that takes an integer and returns a pointer to a long. (Remember that spaces are meaningless here.)

Examine these two declarations:

long * Function (int);
long (* funcPtr) (int);

The first, Function (), is a function taking an integer and returning a pointer to a variable of type long. The second, funcPtr, is a pointer to a function taking an integer and returning a variable of type long.

The declaration of a function pointer will always include the return type and the parentheses indicating the type of the parameters, if any. Listing 20.5 illustrates the declaration and use of function pointers.

Listing 20.5. Pointers to Functions
 0:  // Listing 20.5 Using function pointers
 1:  #include <iostream>
 2:
 3:  void Square (int&,int&);
 4:  void Cube (int&, int&);
 5:  void Swap (int&, int &);
 6:  void GetVals(int&, int&);
 7:  void PrintVals(int, int);
 8:
 9:  int main()
10:  {
11:      void (* pFunc) (int &, int &);
12:      bool fQuit = false;
13:
14:      int valOne=1, valTwo=2;
15:      int choice;
16:      while (fQuit == false)
17:      {
18:          std::cout << "(0)Quit (1)Change Values "
19:              << "(2)Square (3)Cube (4)Swap: ";
20:          std::cin >> choice;
21:          switch (choice)
22:          {
23:          case 1:
24:              pFunc = GetVals;
25:              break;
26:          case 2:
27:              pFunc = Square;
28:              break;
29:          case 3:
30:              pFunc = Cube;
31:              break;
32:          case 4:
33:              pFunc = Swap;
34:              break;
35:          default :
36:              fQuit = true;
37:              break;
38:          }
39:
40:          if (fQuit)
41:              break;
42:
43:          PrintVals(valOne, valTwo);
44:          pFunc(valOne, valTwo);
45:          PrintVals(valOne, valTwo);
46:      }
47:      return 0;
48:  }
49:
50:  void PrintVals(int x, int y)
51:  {
52:      std::cout << "x: " << x << " y: " << y << std::endl;
53:  }
54:
55:  void Square (int & rX, int & rY)
56:  {
57:      rX *= rX;
58:      rY *= rY;
59:  }
60:
61:  void Cube (int & rX, int & rY)
62:  {
63:      int tmp;
64:
65:      tmp = rX;
66:      rX *= rX;
67:      rX = rX * tmp;
68:
69:      tmp = rY;
70:      rY *= rY;
71:      rY = rY * tmp;
72:  }
73:
74:  void Swap(int & rX, int & rY)
75:  {
76:      int temp;
77:      temp = rX;
78:      rX = rY;
79:      rY = temp;
80:  }
81:
82:  void GetVals (int & rValOne, int & rValTwo)
83:  {
84:      std::cout << "New value for ValOne: ";
85:      std::cin >> rValOne;
86:      std::cout << "New value for ValTwo: ";
87:      std::cin >> rValTwo;
88:  }


 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 1
x: 1 y:2
New value for ValOne: 2
New value for ValTwo: 3
x: 2 y:3
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 3
x: 2 y:3
x: 8 y: 27
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 2
x: 8 y: 27
x:64 y:729
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 4
x:64 y:729
x:729 y:64
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 0
					

On lines 3–6 four functions are declared, each with the same return type and signature, returning void and taking two references to integers.


On line 11, pFunc is declared to be a pointer to a function that returns void and takes two integer reference parameters. Any of the previous functions can be pointed to by pFunc. The user is repeatedly offered the choice of which functions to invoke, and pFunc is assigned accordingly. On lines 43–45, the current value of the two integers is printed, the currently assigned function is invoked, and then the values are printed again.

Shorthand Invocation

The pointer to a function does not need to be dereferenced, although you are free to do so. Therefore, if pFunc is a pointer to a function taking an integer and returning a variable of type long, and you assign pFunc to a matching function, you can invoke that function with either

pFunc(x);

or

(*pFunc)(x);

The two forms are identical. The former is just a shorthand version of the latter.

Arrays of Pointers to Functions

Just as you can declare an array of pointers to integers, you can declare an array of pointers to functions returning a specific value type and with a specific signature. (See Listing 20.6.)

Listing 20.6. Using an Array of Pointers to Functions
 0:  // Listing 20.6 arrays of pointers to functions
 1:  #include <iostream>
 2:
 3:  void Square (int&,int&);
 4:  void Cube (int&, int&);
 5:  void Swap (int&, int &);
 6:  void GetVals(int&, int&);
 7:  void PrintVals(int, int);
 8:
 9:  int main()
10:  {
11:      int valOne=1, valTwo=2;
12:      int choice,i;
13:      const int MaxArray = 5;
14:      void (*pFuncArray[MaxArray])(int&, int&);
15:
16:      for (i=0;i<MaxArray;i++)
17:      {
18:          std::cout << "(1)Change Values "
19:              << "(2)Square (3)Cube (4)Swap: ";
20:          std::cin >> choice;
21:          switch (choice)
22:          {
23:          case 1:
24:              pFuncArray[i] = GetVals;
25:              break;
26:          case 2:
27:              pFuncArray[i] = Square;
28:              break;
29:          case 3:
30:              pFuncArray[i] = Cube;
31:              break;
32:          case 4:
33:              pFuncArray[i] = Swap;
34:              break;
35:          default:
36:              pFuncArray[i] = 0;
37:          }
38:      }
39:
40:      for (i=0;i<MaxArray; i++)
41:      {
42:          pFuncArray[i](valOne,valTwo);
43:          PrintVals(valOne,valTwo);
44:      }
45:      return 0;
46:  }
47:
48:  void PrintVals(int x, int y)
49:  {
50:      std::cout << "x: " << x << " y: " << y << std::endl;
51:  }
52:
53:  void Square (int & rX, int & rY)
54:  {
55:      rX *= rX;
56:      rY *= rY;
57:  }
58:
59:  void Cube (int & rX, int & rY)
60:  {
61:      int tmp;
62:
63:      tmp = rX;
64:      rX *= rX;
65:      rX = rX * tmp;
66:
67:      tmp = rY;
68:      rY *= rY;
69:      rY = rY * tmp;
70:  }
71:
72:  void Swap(int & rX, int & rY)
73:  {
74:      int temp;
75:      temp = rX;
76:      rX = rY;
77:      rY = temp;
78:  }
79:
80:  void GetVals (int & rValOne, int & rValTwo)
81:  {
82:      std::cout << "New value for ValOne: ";
83:      std::cin >> rValOne;
84:      std::cout << "New value for ValTwo: ";
85:      std::cin >> rValTwo;
86:  }


(1)Change Values (2)Square (3)Cube (4)Swap: 1
(1)Change Values (2)Square (3)Cube (4)Swap: 2
(1)Change Values (2)Square (3)Cube (4)Swap: 3
(1)Change Values (2)Square (3)Cube (4)Swap: 4
(1)Change Values (2)Square (3)Cube (4)Swap: 2
New Value for ValOne: 2
New Value for ValTwo: 3
x: 2 y: 3
x: 4 y: 9
x: 64 y: 729
x: 729 y: 64
x: 531441 y:4096
						

On lines 16–37, the user is asked to pick the functions to invoke, and each member of the array is assigned the address of the appropriate function. On lines 40–44, each function is invoked in turn. The result is printed after each invocation.


Passing Pointers to Functions to Other Functions

The pointers to functions (and arrays of pointers to functions, for that matter) can be passed to other functions that may take action and then call the right function using the pointer.

For example, you might improve Listing 20.6 by passing the chosen function pointer to another function (outside of main()) that will print the values, invoke the function, and then print the values again. Listing 20.7 illustrates this variation.

Listing 20.7. Passing Pointers to Functions as Function Arguments
 0:  // Listing 20.7 Without function pointers
 1:  #include <iostream>
 2:  using namespace std; // this file uses std:: objects
 3:
 4:  void Square (int&,int&);
 5:  void Cube (int&, int&);
 6:  void Swap (int&, int &);
 7:  void GetVals(int&, int&);
 8:  void PrintVals(void (*)(int&, int&),int&, int&);
 9:
10:  int main()
11:  {
12:      int valOne=1, valTwo=2;
13:      int choice;
14:      bool fQuit = false;
15:
16:      void (*pFunc)(int&, int&);
17:
18:      while (fQuit == false)
19:      {
20:          cout << "(0)Quit (1)Change Values "
21:              << "(2)Square (3)Cube (4)Swap: ";
22:          cin >> choice;
23:          switch (choice)
24:          {
25:          case 1:
26:              pFunc = GetVals;
27:              break;
28:          case 2:
29:              pFunc = Square;
30:              break;
31:          case 3:
32:              pFunc = Cube;
33:              break;
34:          case 4:
35:              pFunc = Swap;
36:              break;
37:          default:
38:              fQuit = true;
39:              break;
40:          }
41:          if (fQuit == true)
42:              break;
43:          PrintVals ( pFunc, valOne, valTwo);
44:      }
45:
46:      return 0;
47:  }
48:
49:  void PrintVals( void (*pFunc)(int&, int&),int& x, int& y)
50:  {
51:      cout << "x: " << x << " y: " << y << endl;
52:      pFunc(x,y);
53:      cout << "x: " << x << " y: " << y << endl;
54:  }
55:
56:  void Square (int & rX, int & rY)
57:  {
58:      rX *= rX;
59:      rY *= rY;
60:  }
61:
62:  void Cube (int & rX, int & rY)
63:  {
64:      int tmp;
65:
66:      tmp = rX;
67:      rX *= rX;
68:      rX = rX * tmp;
69:
70:      tmp = rY;
71:      rY *= rY;
72:      rY = rY * tmp;
73:  }
74:
75:  void Swap(int & rX, int & rY)
76:  {
77:      int temp;
78:      temp = rX;
79:      rX = rY;
80:      rY = temp;
81:  }
82:
83:  void GetVals (int & rValOne, int & rValTwo)
84:  {
85:      cout << "New value for ValOne: ";
86:      cin >> rValOne;
87:      cout << "New value for ValTwo: ";
88:      cin >> rValTwo;
89:  }


 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 1
x: 1 y:2
New value for ValOne: 2
New value for ValTwo: 3
x: 2 y:3
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 3
x: 2 y:3
x: 8 y: 27
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 2
x: 8 y: 27
x:64 y:729
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 4
x:64 y:729
x:729 y:64
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 0
						

On line 16, pFunc is declared to be a pointer to a function returning void and taking two parameters, both of which are integer references. On line 8, PrintVals is declared to be a function taking three parameters. The first is a pointer to a function that returns void but takes two integer reference parameters, and the second and third arguments to PrintVals are integer references. The user is again prompted which functions to call, and then on line 43 PrintVals is called.


Go find a C++ programmer and ask him what this declaration means:

void PrintVals(void (*)(int&, int&),int&, int&);

This is the kind of declaration that you will use infrequently and will probably look up in the book each time you need it, but it will save your program on those rare occasions when it is exactly the required construct.

Using typedef with Pointers to Functions

The construct void (*)(int&, int&) is cumbersome, at best. You can use typedef to simplify this, by declaring a type VPF as a pointer to a function returning void and taking two integer references. Listing 20.8 rewrites the beginning of Listing 20.7 using this typedef statement.

Listing 20.8. Using typedef to Make Pointers to Functions More Readable
 0:  // Listing 20.8. using typedef
 1:  #include <iostream>
 2:  using namespace std; // this file uses std:: objects
 3:
 4:  void Square (int&,int&);
 5:  void Cube (int&, int&);
 6:  void Swap (int&, int &);
 7:  void GetVals(int&, int&);
 8:  typedef  void (*VPF) (int&, int&);
 9:  void PrintVals(VPF,int&, int&);
10:
11:  int main()
12:  {
13:      int valOne=1, valTwo=2;
14:      int choice;
15:      bool fQuit = false;
16:
17:      VPF pFunc;
18:
19:      while (fQuit == false)
20:      {
21:          cout << "(0)Quit (1)Change Values"
22:              << "(2)Square (3)Cube (4)Swap: ";
23:          cin >> choice;
24:          switch (choice)
25:          {
26:          case 1:
27:              pFunc = GetVals;
28:              break;
29:          case 2:
30:              pFunc = Square;
31:              break;
32:          case 3:
33:              pFunc = Cube;
34:              break;
35:          case 4:
36:              pFunc = Swap;
37:              break;
38:          default:
39:              fQuit = true;
40:              break;
41:          }
42:          if (fQuit == true)
43:              break;
44:          PrintVals ( pFunc, valOne, valTwo);
45:      }
46:      return 0;
47:  }
48:
49:  void PrintVals( VPF pFunc,int& x, int& y)
50:  {
51:      cout << "x: " << x << " y: " << y << endl;
52:      pFunc(x,y);
53:      cout << "x: " << x << " y: " << y << endl;
54:  }
55:
56:  void Square (int & rX, int & rY)
57:  {
58:      rX *= rX;
59:      rY *= rY;
60:  }
61:
62:  void Cube (int & rX, int & rY)
63:  {
64:      int tmp;
65:
66:      tmp = rX;
67:      rX *= rX;
68:      rX = rX * tmp;
69:
70:      tmp = rY;
71:      rY *= rY;
72:      rY = rY * tmp;
73:  }
74:
75:  void Swap(int & rX, int & rY)
76:  {
77:      int temp;
78:      temp = rX;
79:      rX = rY;
80:      rY = temp;
81:  }
82:
83:  void GetVals (int & rValOne, int & rValTwo)
84:  {
85:      cout << "New value for ValOne: ";
86:      cin >> rValOne;
87:      cout << "New value for ValTwo: ";
88:      cin >> rValTwo;
89:  }


 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 1
x: 1 y:2
New value for ValOne: 2
New value for ValTwo: 3
x: 2 y:3
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 3
x: 2 y:3
x: 8 y: 27
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 2
x: 8 y: 27
x:64 y:729
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 4
x:64 y:729
x:729 y:64
 (0)Quit (1)Change Values (2)Square (3)Cube (4)Swap: 0
						

On line 8, typedef is used to declare VPF to be of the type function that returns void and takes two parameters, both integer references.


On line 9, the function PrintVals() is declared to take three parameters, a VPF and two integer references. On line 17, pFunc is now declared to be of type VPF.

Once the type VPF is defined, all subsequent uses, to declare pFunc and PrintVals(), are much cleaner.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.184.21