Extracted from my edit of the Wikipedia article
Introduction
The C and C++ syntax for pointers to functions used in all the textbooks is difficult to read and explain, even when typedef
s are used to help make the definitions more readable. However, every C and C++ compiler supports a more clear and concise mechanism to declare function pointers: use typedef
, but don’t store the pointer as part of the definition. Note that the only way this kind of typedef
can actually be used is with a pointer – but that highlights the pointer-ness of it.
C and C++ syntax
// This declares 'F': // a function that accepts a 'char' and returns an 'int'. // Note that the definition is elsewhere. int F(char c); // This defines 'Fn': // a type of function that accepts a 'char' and returns an 'int'. typedef int Fn(char c); // This defines 'fn': // a variable of type pointer-to-'Fn'; // and then assigns the address of 'F' to it. Fn *fn = &F; // '&' is not required - but it highlights what is being done. // This calls 'F' using 'fn'; // and then assigns the result to the variable 'a'. int a = fn('A'); // This defines 'Call': // a function that accepts a pointer-to-'Fn'; // calls that function; // and returns the result. int Call(Fn *fn, char c) { return fn(c); } // Call(fn, c) // This calls function 'Call()', passing in 'F'. // It then assigns the result to the variable 'call'. int call = Call(&F, 'A'); // Again, '&' is not required // LEGACY: Note that to maintain existing code bases, // the above definition style can still be used first; // then the original type can be defined in terms of it // using the new style. // This defines 'PFn': // a type of pointer-to-type-Fn. typedef Fn *PFn; // 'PFn' can be used wherever 'Fn *' can PFn pfn = F; int CallP(PFn fn, char c);
C++ specific syntax
These examples use the above definitions. In particular, note that the above definition for Fn
can be used in pointer-to-member-function definitions. Also note that C++ defines the precedence of the two “pointer to member” operators (.*
and ->*
) as lower than ordinary member access operators (.
and *
) and the function call operator (()
), thus to use them requires extra parentheses:
// This defines 'C': // a class with similar static and member functions; // and then creates an instance called 'c'. class C { public: static int Static(char c); int Member(char c); } c; // C // This defines 'p': // a pointer to 'C'; // and assigns the address of 'c' to it C *p = &c; // This assigns a pointer-to-'Static' to 'fn'. // Since there is no 'this', 'Fn' is the correct type; // and 'fn' can be used as above. fn = &C::Static; // This defines 'm': // a pointer-to-member-of-'C' with type 'Fn'; // and assigns the address of 'C::Member' to it. // You can read it right-to-left like all pointers: // "'m' is a pointer to member of class 'C' of type 'Fn'." Fn C::*m = &C::Member; // This uses 'm' to call 'Member' in 'c'; // assigning the result to 'cA'. int cA = (c.*m)('A'); // This uses 'm' to call 'Member' in 'p'; // assigning the result to 'pA'. int pA = (p->*m)('A'); // This defines 'Ref': // a function that accepts a reference-to-'C'; // a pointer-to-member-of-'C' of type 'Fn'; // and a 'char'; // calls the function, and returns the result. int Ref(C &r, Fn C::*m, char c) { return (r.*m)(c); } // Ref(r, m, c) // This defines 'Ptr': // a function that accepts a pointer-to-'C'; // a pointer-to-member-of-'C' of type 'Fn'; // and a 'char'; // calls the function and returns the result int Ptr(C *p, Fn C::*m, char c) { return (p->*m)(c); } // Ptr(p, m, c) // LEGACY: Note that to maintain existing code bases, the above definition // style can still be used first; // then the original type can be defined in terms of it using the new style. // This defines 'FnC': // a type of pointer-to-member-of-class-'C' of type 'Fn'. typedef Fn C::*FnC; // 'FnC' can be used wherever 'Fn C::*' can. FnC fnC = &C::Member; int RefP(C &p, FnC m, char c);