PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : DOS DATE : October 19, 1993 PAGE : 1/10 TITLE : Using Member Function Pointers. Member Function Pointers ======================== First of all, do you think you've EVER used a funcition pointer before? If you've ever used the QSORT, BSEARCH, or LSEARCH functions before you have, at least indirectly. So in our quest to understand function pointers, let's investigate a typical call to QSORT. First in C: #include int compare(const int *one, const int *two) { if (*one > *two) return -1; else return 1; } int a[3] = { 50, 10, 20 }; void main() { qsort(a, 3, sizeof(a[0]), compare); } The fourth parameter to compare is the function pointer, and here's how it's declared in stdlib.h: void qsort (void *__base, size_t __nelem, size_t __width, int _Cdecl (*__fcmp)(const void *, const void *)); However, the above program WILL NOT compile in C++, because of the Strong Type features of the C++ language. It refuses to convert the VOID parameters in the declaration to __fcmp function to INT's. Luckily C++ permits casting of function pointers, just like regular pointers. Here's how to fix the call to QSORT in C++: PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : ALL DATE : October 19, 1993 PAGE : 2/10 TITLE : Using Member Function Pointers. qsort(a, 3, sizeof(a[0]), (int (*)(const void *,const void *))compare); By casting the COMPARE function to be of the same type as the declaration in stdlib.h, C++ will accept and compile it. C++ function pointers are a way to modify the behavior of a function at runtime, specifically a member function pointer. In C++, a programmer can declare a pointer to a member function, and use that variable pointer to call a function provided the pointer has been initialized. A member function pointer must specify both the type of the class containing the member function, as well as the parameters passed to the function. The programmer can reassign a given function pointer to address several different punctions during program execution, where all the functions pointed to have the same parameter types and return type. C++ supports two pointer-to-member operators. The first, the '.*' operator signifies that the second operand is bound to the first operand, and the first operand is a non-pointer data type. The second, the '->*' operator again signifies the second operand is bound to the first operand, and the first operand is a pointer data type. First an example in C: #include void apple(void) { cout << "apple" << endl; }; void berry(void) { cout << "berry" << endl; }; void main() { --> void (*fptr)(void); fptr = apple; PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : ALL DATE : October 19, 1993 PAGE : 3/10 TITLE : Using Member Function Pointers. fptr(); fptr = berry; fptr(); } Now the same program using classes in C++. Notice how the strong typing of the C++ language makes the programmer explicitly tell the compiler exactly which function to point at, thus removing any ambiguities. #include class fruit { public: void apple() { cout << "apple" << endl; } void berry() { cout << "berry" << endl; } }; void main() { fruit x, *y; void (fruit::*f)(void); y = new fruit; f = &fruit::apple; (x.*f)(); f = &fruit::berry; (y->*f)(); delete y; } PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : ALL DATE : October 19, 1993 PAGE : 4/10 TITLE : Using Member Function Pointers. The C code looks more intimidating than the C++ portion, but it explicitly tells the language how to set things up. There is no ambiguity. How would one pass a member function to qsort()? This is a little more complex, because the this pointer has to be disabled. A non-member function must be supplied to access the member function, and qsort() will use the non-member function as follows: #include #include class fruit { public: fruit() { f = &fruit::compare; } int (fruit::*f)(const int*, const int*); int compare(const int *one, const int *two) { return ( (*one == *two) ? 0 : *one > *two ); } } apple; int funcptr(const void* one , const void* two) { return ( (apple.*apple.f)( (const int *)one, (const int *)two ) ); }; int a[3] = { 3, 2, 1 }; void main() { cout << "before "; for( int i=0; i < 3; i++ ) cout << a[i] << " "; cout << endl; qsort(a, 3, sizeof(a[0]), funcptr ); cout << "after "; for( i=0; i < 3; i++ ) cout << a[i] << " "; PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : ALL DATE : October 19, 1993 PAGE : 5/10 TITLE : Using Member Function Pointers. cout << endl; } Arrays of function pointers make programming a little simpler: #include class fruit { public: void apple() { cout << "apple" << endl; } void berry() { cout << "berry" << endl; } }; void main() { fruit x; --> void (fruit::*f[2])(void); f[0] = &fruit::apple; f[1] = &fruit::berry; (x.*f[0])(); (x.*f[1])(); } It's also possible to declare pointers to class data members: #include class fruit { public: int pie; fruit() { pie = 10; } }; void main() PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : ALL DATE : October 19, 1993 PAGE : 6/10 TITLE : Using Member Function Pointers. { fruit f; --> int fruit::*FruitPointer = &fruit::pie; cout << f.*FruitPointer << endl; } Passing function pointers is similar, however the THIS pointer is required, so the compiler will know which instance of the class it's passing to the member function: #include class fruit { public: void apple() { cout << "apple" << endl; } void berry() { cout << "berry" << endl; } void cherry(void (fruit::*func)()) { --> (this->*func)(); } }; void main() { fruit x; void (fruit::*f)(void); f = &fruit::apple; (x.*f)(); f = &fruit::berry; x.cherry(f); } Now the problem that arises is: how do friend or static functions get member function pointers, because they have no THIS PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : ALL DATE : October 19, 1993 PAGE : 7/10 TITLE : Using Member Function Pointers. pointer available? To have a friend or static member function pointer accessed from within a function, an instance of the class has to be passed in as follows: Friend Example: #include class fruit { public: void apple() { cout << "apple" << endl; } void berry() { cout << "berry" << endl; } friend void cherry(void (fruit::*func)(),fruit x) { (x.*func)(); } }; void main() { fruit x; void (fruit::*f)(void); f = &fruit::apple; (x.*f)(); f = &fruit::berry; cherry(f,x); } The static example is similar: #include class fruit { PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : ALL DATE : October 19, 1993 PAGE : 8/10 TITLE : Using Member Function Pointers. public: void apple() { cout << "apple" << endl; } void berry() { cout << "berry" << endl; } static void cherry(void (fruit::*func)(),fruit x) { (x.*func)(); } }; void main() { fruit x; void (fruit::*f)(void); f = &fruit::apple; (x.*f)(); f = &fruit::berry; x.cherry(f,x); } How do you call a function pointer embedded in a class? This one's a bit more compilcated. The instance of the class dereferences to the instance pointer as follows: #include class fruit { public: void (fruit::*ff)(void); void apple() { cout << "apple" << endl; } void berry() { PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : ALL DATE : October 19, 1993 PAGE : 9/10 TITLE : Using Member Function Pointers. cout << "berry" << endl; } }; void main() { fruit x; void (fruit::*f)(void); f = &fruit::apple; x.ff = &fruit::berry; (x.*f)(); (x.*x.ff)(); } Finally, calling member functions of other classes from another class with function pointers: class fruit { int f; public: void jello(int i=0) { f = i; } }; class basket { void (fruit::*set)(int); public: basket(int i) { fruit x; set = &fruit::jello; (x.*set)(i); } }; void main() { basket b(123); } PRODUCT : Borland C++ NUMBER : 1024 VERSION : 3.1 OS : ALL DATE : October 19, 1993 PAGE : 10/10 TITLE : Using Member Function Pointers. How about templates and function pointers?! It's can be done, but the syntax is complex, as the following example illustrates: #include template class alpha { T data; public: alpha(T x) { data = x; } T show() { cout << data << endl; } }; void main() { int (alpha::*ifunc)(); float (alpha::*ffunc)(); alpha a(123); alpha b(456.78); ifunc = &alpha::show; ffunc = &alpha::show; (a.*ifunc)(); (b.*ffunc)(); }