You are on page 1of 5

The C++ Programming Pointers to Functions

Language
 Pointers to functions are a surprisingly use-
ful and frequently underutilized feature of
C and C++.
Pointers to Member Functions
 Pointers to functions provide an ecient
and e ective form of subprogram gener-
ality
Outline { , the qsort standard C library function:
e.g.

qsort (void *, int, int, int (*)(void *,void *));


Pointers to Functions static int asc cmp (void *i, void *j) f
g
return *(int *)i ; *(int *)j;
Pointers to Member Functions staticreturn
int dsc*(int
cmp (void *i, void *j) f
The Type of a Class Member *)j ; *(int *)i;
g
Declaring a Pointer to Member Function void for
print (int a[], int size) f
(int i = 0; i < size; i++)
Pointer to Class Member Function printf ("%d", a[i]);
putchar ('\n');
Using typedef to Enhance Readability g
void int
main (void) f
[] = f 9, 1, 7, 4, 5, 8, 3, 1, 2, 0g;
Function Arguments int asize = sizeof a / sizeof *a;
Using a Pointer to Class Member Function print (a, size);
qsort (a, size, sizeof *a, asc cmp);
Di erence between PTMF and PTF print (a, size);
qsort (a, size, sizeof *a, dsc cmp);
Pointer to Class Data Member print (a, size);
g
Using a Pointer to Data Member 1 2

Pointers to Member Functions The Type of a Class Member


 Pointers to member functions provide an  A pointer to a function cannot be assigned
implementation-independent way of declar- the address of a member function even
ing and using pointers to class member when the return type and signature of the
functions. two match exactly:
{ Note, this works with virtual and non-virtual class Screen f
functions! private:
short height, width;
char *screen, *cur pos;
 Earlier C++ versions required tricking the public:
C++ type system into utilizing the inter- Screen (int = 8, int = 40, char = ' ');
~Screen (void);
nal non-member function representation int get height (void) f return height; g
to achieve pointer to member function se- int get width (void) f return width; g
mantics, e.g., Screen &forward (void);
Screen &up (void);
struct X f void f (int); int i, j; g; Screen &down (void);
typedef void (*PTF) ( ); // Bad style. Screen &home (void);
:::
Screen &bottom (void);
Screen &display (void);
void f (void) f Screen &copy (Screen &);
PTF fake = (PTF) &X::f; // Assume a lot! //
X a; g;
:::

(*fake)(&a, 2); // Fake the call


g
:::

int height is (void) f /* */ g


int width is (void) f /* */ g
:::

 This approach is clearly inelegant and error- int (*pt )(void);


:::

prone. pt = &height is; // OK


{ and doesn't work at all if f is a virtual function! pt = &width is; // OK
pt = &Screen::get height; // Error
pt = &Screen::get width; // Error
3 4
Declaring a Pointer to Member Pointer to Class Member
Function Function
 A member function has an additional type
attribute absent from a non-member func-  As mentioned above, a pointer to member
tion, namely: \its class." A pointer to a
member function must match exactly in function is de ned by specifying its return
three areas: type, its signature, and its class.
{ The data types and number of its formal argu-
ments.
 Therefore,
 i.e., the function's signature.
{ A pointer to the Screen member functions
{ The function's return data type. are de ned for
Screen::get height () and
Screen::get width () as:

{ The class type of which the function is a mem- int (Screen::*)(void);


ber. { That is, a pointer to a member function of
class Screen taking no arguments and re-
turning a value of type int, ,e.g.

 The declaration of a pointer to a class int (Screen::*pmf1)(void) = 0;


member function is similar to a regular int (Screen::*pmf2)(void) = &Screen::get height;
pointer to a function.
{ However, it also requires an expanded syntax pmf1 = pmf2;
that takes the class type into account. pmf2 = &Screen::get width;
5 6

Pointers to static Class Member


Functions Using typedef to Enhance
Readability
 Note that static class member functions
behave di erently that non-static mem-
ber functions wrt pointers-to-member func-  Use of a typedef can make the pointer to
tions. member function syntax easier to read.
{ , static class member functions behave like
i.e.
regularnon-member functions.
 For example, the following typedef de-
nes ACTION to be an alternative name
{ e.g. , for:
class Foo f Screen &(Screen::*)(void);
public:
static int si (void);
int nsi (void);  That is, a pointer to a member function
g; of class Screen taking no arguments and
int (*pts ) (void); returning a reference to a class Screen ob-
int (Foo::*ptns ) (void); ject, e.g.,
pts = &Foo::si; // ok typedef Screen &(Screen::*ACTION)(void);
pts = &Foo::nsi; // Error ACTION default = &Screen::home;
ptns = &Foo::si; // Error ACTION next = &Screen::forward;
ptns = &Foo::nsi; // ok
7 8
Using a Pointer to Class Member
Function
Function Arguments
 Pointers to class members must always be
 Pointers to members may be declared as accessed through a speci c class objects.
arguments to functions, in addition, a de-
fault initializer may also be speci ed:
typedef Screen &(Screen::*ACTION)(void);  This is accomplished by using .* and ->*,
the two pointer-to-member selection op-
erators, e.g.,
Screen my screen;
ACTION default = &Screen::home; Screen my screen, *buf screen = &my screen;
int (Screen::*pm )(void) = &Screen::get height;
Screen& foo (Screen&, ACTION = &Screen::display); Screen &(Screen::*pmfs)(Screen &) = &Screen::copy;
void (void) /* ::: */
f
foo (my screen); // pass &Screen::display // Direct invocation of member functions
foo (my screen, default); if (my screen.get height () == buf screen->get height ())
foo (my screen, &Screen::bottom); buf screen->copy (my screen);
g
// Pointer to member equivalent
if ((my screen.*pm ) () == (buf screen->*pm )())
(buf screen->*pmfs)(my screen);
9 10

Using a Pointer to Class Member Using a Pointer to Class Member


Function (cont'd) Function (cont'd)
 A non-general implementation of a repeat
 A declaration wishing to provide default function, that performs some user-speci ed
arguments for member function repeat () operation n times could be done the fol-
might look as follows: lowing way:
class Screen enum Operation f UP, DOWN, /* */ g;
Screen &Screen::repeat (Operation op, int times)
:::

f f
public: switch (op)
Screen &repeat (ACTION = &Screen::forward, f
case DOWN: /* code to iterate n times */;
int = 1); break;
/* */ case UP: /* code to iterate n times */;
g;
:::
break;
g
return *this;
g
 An invocation of repeat might look as fol-
lows:  Pointers to member functions allow a more
general implementation:
Screen my screen;
typedef Screen &(Screen::*ACTION)(void);
/* ::: */ Screen &Screen::repeat (ACTION op, int times)
f
my screen.repeat (); // repeat (&Screen::forward, 1); for (int i = 0; i < times; i++)
my screen.repeat (&Screen::down, 20); (this->*op) ();
return *this;
g
11 12
Example Usage (cont'd) Di erence between PTMF and
PTF
 A table of pointers to class members can
also be de ned. In the following example, ,
menu is a table of pointers to class Screen
 e.g.

member functions that provide for cursor


movement: #include <stream.h>
ACTION menu[] = class Base 1 f
f public:
&Screen::home; void a1 (int);
&Screen::forward; static void a2 (int); // Note static :::

&Screen::back; g;
&Screen::up;
&Screen::down; // Pointer to function type
&Screen::bottom; typedef void (*F PTR)(int);
g;
enum Cursor Movements // Pointer to Base 1 member function type
f typedef void (Base 1::*MF PTR)(int);
HOME, FORWARD, BACK, UP, DOWN, BOTTOM
g; void a3 (int i); // Forward decl.
Screen &Screen::move (Cursor Movements cm) class Base 2 f
f public:
(this->*menu[cm])(); void b1 (MF PTR);
return *this; void b2 (F PTR);
g g;
13 14

Di erence between PTMF and Di erence between PTMF and


PTF (cont'd) PTF (cont'd)
 e.g.,
 main program
void Base 1::a1 (int i) f
cout << "Base 1::a1 got " << i << "\n"; int main (void) f
g cout << "base 2.b1 (base 1.a1);\n";
void Base 1::a2 (int i) f base 2.b1 (base 1.a1);
cout << "Base 1::a2 got " << i << "\n"; // Base 1::a1 got 3
g
cout << "\nbase 2.b2 (a3);\n";
void a3 (int i) f base 2.b2 (a3);
cout << "a3 got " << i << "\n"; // a3 got 5
g
cout << "\nbase 2.b2 (base 1.a2);\n";
// De ne tw objects. base 2.b2 (base 1.a2);
Base 1 base 1; // Base 1::a2 got 5
Base 2 base 2;
void Base 2::b1 (MF PTR fp) f cout << "\nbase 2.b2 (Base 1::a2);\n";
/* Note object */
::: base 2.b2 (Base 1::a2);
(base 1.*fp)(3); // Base 1::a2 got 5
g
void Base 2::b2 (F PTR fp) f (*fp)(5); g return 0;
g
15 16
Pointer to Class Data Member Using a Pointer to Data Member
 In addition to pointers to member func-  Pointers to data members are accessed in
tions, C++ also allows pointers to data a manner similar to that use for pointer
members. to class member functions, using the op-
{ Pointers to class data members serve a similar erators .* and ->*, e.g.,
purpose to the use of the ANSI C offsetof
macro for accessing structure elds. typedef short Screen::*PS SCREEN;
Screen my screen;
 The syntax is as follows: Screen *tmp screen = new Screen (10, 10);
{ The complete type of Screen::height is \short void (void)
member of class Screen." f
{ Consequently, the complete type of a pointer PS SCREEN ph = &Screen::height;
to Screen::height is \pointer to short member PS SCREEN pw = &Screen::width;
of class Screen." This is written as: tmp screen->*ph = my screen.*ph;
tmp screen->*pw = my screen.*pw;
short Screen::* g
 A de nition of a pointer to a member of Note: since height and width are private
class Screen of type short looks like this: 
members of Screen, the initialization of ph
short Screen::*ps Screen; and pw within ff () is legal only if ff () is
short Screen::*ps Screen = &Screen::height;
declared a friend to Screen!
ps Screen = &Screen::width;
17 18

Contravariance
 Just as with data members, we must be Contravariance (cont'd)
careful about contravariance with pointers
to member functions as well.
dp bp
 e.g.,
struct Base f
int i; b
i
d
i
virtual int foo (void) f return i; g
g;
struct Derived : public Base f
int j; ? j
virtual int foo (void) f return j; g
g;
void foo (void) f
Base b;
Derived d;  Problem: what happens (b.*ptmfg) () is
int (Base::*ptmfb) (void) = &Base::foo; // "ok"
int i = (b.*ptmfb) (); called?
// trouble!
ptmfb = (int (Base::*) (void)) &derived::foo;
int j = (b.*ptmfb) ();
// Tries to access non-existant j part of b!
g
19 20