C++ ordinary function pointer and member function pointer instance resolution

  • 2020-04-02 02:36:35
  • OfStack

The function pointer in C++ is a function called indirectly by a pointer to a function. I believe that many people to point to the general function of the function pointer to use more, but to point to the class member function of the function pointer is relatively unfamiliar. This article is to C++ ordinary function pointer and member function pointer for instance resolution.

One, ordinary function pointer

In general, when we talk about function Pointers, we mean Pointers to ordinary functions. Like any other pointer, a function pointer points to a specific type, and all functions used by the same pointer must have the same parameter type and return type.


int (*pf)(int, int);  //Declared function pointer

In this case, pf refers to an int (int, int), which means that the function takes two ints and returns an int.

Note: *pf is a function that returns an int pointer if you do not write this pair of parentheses, which are necessary.


#include<iostream> 
#include<string> 
using namespace std; 
 
typedef int (*pFun)(int, int); //A typedef is a type
 
int add(int a, int b){ 
  return a+b; 
} 
 
int mns(int a, int b){ 
  return a-b; 
} 
 
string merge(const string& s1, const string& s2){ 
  return s1+s2; 
} 
 
int main() 
{ 
  pFun pf1 = add;  
  cout << (*pf1)(2,3) << endl; //Call the add function
  pf1 = mns; 
  cout << (*pf1)(8,1) << endl; //Call the MNS function
  string (*pf2)(const string&, const string&) = merge; 
  cout << (*pf2)("hello ", "world") << endl; //Call the merge function
  return 0; 
}

For example, declaring a function pointer variable directly is verbose and cumbersome, so we can use typedefs to define our own function pointer type. In addition, the function pointer can also be used as the parameter type of the function, the argument can be directly used by the function name.

Member function pointer

A member function pointer is a pointer to a nonstatic member function of a class. Static members of the class do not belong to any object, so there is no need for special Pointers to static members, Pointers to static members and ordinary Pointers are no different. Unlike normal function Pointers, member function Pointers must specify not only the parameter list and return type of the target function, but also the class to which the member function belongs. Therefore, we must add classname:: before * to indicate that the currently defined pointer points to a member function of classname:


int (A::*pf)(int, int);  //Declare a pointer to a member function

By the same token, the parentheses at both ends of A::*pf are necessary. If they are not present, pf is A function that returns an A class data member (int) pointer. Note: unlike normal function Pointers, there is no automatic conversion rule between a member function and a pointer to that member.


pf = &A::add;  //Correct: the addressing operator (&) must be used explicitly
pf = A::add;  //error

When we initialize a member function pointer, it points to a member function of the class, but we don't specify the object to which the member belongs -- we don't provide the object to which the member belongs until we use the member function pointer. Here is an example of using a pointer to a member function:


class A; 
typedef int (A::*pClassFun)(int, int); //Member function pointer type
 
class A{ 
public: 
  int add(int m, int n){ 
    cout << m << " + " << n << " = " << m+n << endl; 
    return m+n; 
  } 
  int mns(int m, int n){ 
    cout << m << " - " << n << " = " << m-n << endl; 
    return m-n; 
  } 
  int mul(int m, int n){ 
    cout << m << " * " << n << " = " << m*n << endl; 
    return m*n; 
  } 
  int dev(int m, int n){ 
    cout << m << " / " << n << " = " << m/n << endl; 
    return m/n; 
  } 
 
  int call(pClassFun fun, int m, int n){  //Class internal interface
    return (this->*fun)(m, n); 
  } 
}; 
 
int call(A obj, pClassFun fun, int m, int n){  //Class external interface
  return (obj.*fun)(m, n); 
} 
 
int main() 
{ 
  A a; 
  cout << "member function 'call':" << endl; 
  a.call(&A::add, 8, 4); 
  a.call(&A::mns, 8, 4); 
  a.call(&A::mul, 8, 4); 
  a.call(&A::dev, 8, 4); 
  cout << "external function 'call':" << endl; 
  call(a, &A::add, 9, 3); 
  call(a, &A::mns, 9, 3); 
  call(a, &A::mul, 9, 3); 
  call(a, &A::dev, 9, 3); 
  return 0; 
}

As the example shows, we can also use a typedef to define a type alias for a pointer to a member function. In addition, we need to pay attention to how function Pointers are used: for normal function Pointers, we use (*pf)(arguments) like this, because to call a function, you must first unreference the function pointer, and the function call operator () has a higher priority, so (*pf) parentheses are necessary; For a pointer to a member function, the only difference is that the function needs to be called on an object, so just add a member accessor:


(obj.*pf)(arguments)     //Obj is an object
(objptr->*pf)(arguments)   //Objptr is an object pointer

Three, the function table driver

A common use for regular function Pointers and Pointers to member functions is to store them in a function table. When the program needs to execute a specific function, from the table to find the corresponding function pointer, the pointer to call the corresponding program code, this is the application of the function pointer in the table-driven method.

A table-driven Approach is to obtain information by looking up a Table. In general, a logical judgment statement (if... The else or switch... To obtain information; But as the data increases, the logical statements get longer and longer, and the advantages of the table-driven approach become apparent.


#include<iostream> 
#include<string> 
#include<map> 
using namespace std; 
 
class A; 
typedef int (A::*pClassFun)(int, int); 
 
class A{ 
public: 
  A(){  //Constructor to initialize the table
    table["+"] = &A::add; 
    table["-"] = &A::mns; 
    table["*"] = &A::mul; 
    table["/"] = &A::dev; 
  } 
  int add(int m, int n){ 
    cout << m << " + " << n << " = " << m+n << endl; 
    return m+n; 
  } 
  int mns(int m, int n){ 
    cout << m << " - " << n << " = " << m-n << endl; 
    return m-n; 
  } 
  int mul(int m, int n){ 
    cout << m << " * " << n << " = " << m*n << endl; 
    return m*n; 
  } 
  int dev(int m, int n){ 
    cout << m << " / " << n << " = " << m/n << endl; 
    return m/n; 
  } 
  //Look up the table and call the corresponding function
  int call(string s, int m, int n){ 
    return (this->*table[s])(m, n); 
  } 
private: 
  map<string, pClassFun> table; //Function table
}; 
 
//test
int main() 
{ 
  A a; 
  a.call("+", 8, 2); 
  a.call("-", 8, 2); 
  a.call("*", 8, 2); 
  a.call("/", 8, 2); 
  return 0; 
}

The above is an example where the "table" is implemented by map (you can also use arrays, of course). The use of the table driver method needs to pay attention to: one is how to look up the table, read the correct data from the table; The second is what is in the table, such as a numerical value or function pointer.


Related articles: