Pointers to Functions
The C++ Programming
Language
Pointers to functions are a surprisingly use-
ful and frequently underutilized feature of
C and C++.
Pointers to Memb er Functions
Pointers to functions provide an ecient
and e ective form of subprogram gener-
ality
Outline
{ e.g., the qsort standard C library function:
qsort (void *, int, int, int (*)(void *,void *));
static int asc cmp (void *i, void *j) f
Pointers to Functions
return *(int *)i *(int *)j;
g
Pointers to Memb er Functions
static int dsc cmp (void *i, void *j) f
return *(int *)j *(int *)i;
The Typ e of a Class Memb er
g
void print (int a[], int size) f
Declaring a Pointer to Memb er Function
for (int i = 0; i < size; i++)
printf ("%d", a[i]);
Pointer to Class Memb er Function
putchar('\n');
g
Using typ edef to Enhance Readability
void main (void) f
int a[] = f 9, 1, 7, 4, 5, 8, 3, 1, 2, 0g;
Function Arguments
int size = sizeof a/ sizeof *a;
print (a, size);
Using a Pointer to Class Memb er Function
cmp); qsort (a, size, sizeof *a, asc
print (a, size);
Di erence between PTMF and PTF
cmp); qsort (a, size, sizeof *a, dsc
print (a, size);
Pointer to Class Data Memb er
g
Using a Pointer to Data Memb er
1 2
Pointers to Memb er Functions The Typ e of a Class Memb er
Pointers to memb er functions provide an
A p ointer to a function cannot b e assigned
implementation-i ndep endent way of declar-
the address of a memb er function even
ing and using p ointers to class memb er
when the return typ e 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;
public:
Earlier C++ versions required tricking the
Screen (int = 8, int = 40, char = '');
C++ typ e system into utilizi ng the inter-
~Screen (void);
nal non-memb er function representation
int get height (void) f return height; g
to achieve p ointer to memb er function se-
int get width (void) f return width; g
mantics, e.g.,
Screen &forward (void);
Screen &up (void);
Screen &down (void);
struct X f void f(int); int i, j; g;
Screen &home (void);
typ edef void (*PTF) (:::); // Bad style.
Screen &b ottom (void);
Screen &display(void);
void f(void) f
Screen © (Screen &);
PTF fake = (PTF) &X::f; // Assume a lot!
// :::
Xa;
g;
(*fake)(&a, 2); // Fakethecall:: :
g
int height is (void) f /* :::*/ g
int width is (void) f /* :::*/ g
This approach is clearly inelegant and error-
int (*pt )(void);
prone.
is; // OK pt = &height
pt = &width is; // OK
{ and do esn't work at all if f is a virtual function!
pt = &Screen::get height; // Error
pt = &Screen::get width; // Error
3 4
Declaring a Pointer to Memb er
Pointer to Class Memb er
Function
Function
A memb er function has an additional typ e
attribute absent from a non-memb er func-
As mentioned ab ove, a p ointer to memb er
tion, namely: \its class." A p ointer to a
function is de ned by sp ecifying its return
memb er function must match exactly in
three areas:
typ e, its signature, and its class.
{ The data typ es and numb er of its formal argu-
ments.
Therefore,
i.e., the function's signature.
{ A p ointer to the Screen memb er functions
are de ned for Screen::get height () and
{ The function's return data typ e.
width () as: Screen::get
{ The class typ e of which the function is a mem-
int (Screen::*)(void);
ber.
{ That is, a p ointer to a memb er function of
class Screen taking no arguments and re-
turning a value of typ e int, e.g.,
The declaration of a p ointer to a class
int (Screen::*pmf1)(void) = 0;
memb er function is similar to a regular
height; int (Screen::*pmf2)(void) = &Screen::get
p ointer to a function.
{ However, it also requires an expanded syntax
pmf1 = pmf2;
that takes the class typ e into account.
pmf2 = &Screen::get width;
5 6
Pointers to static Class Memb er
Using typ edef to Enhance
Functions
Readability
Note that static class memb er functions
behave di erently that non-static mem-
Use of a typ edef can make the p ointer to
b er functions wrt p ointers-to-memb er func-
tions.
memb er function syntax easier to read.
{ i.e., static class memb er functions b ehave like
regularnon-memb er functions.
For example, the following typ edef 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 p ointer to a memb er function
of class Screen taking no arguments and
g;
returning a reference to a class Screen ob-
int (*pts ) (void);
ject, e.g.,
int (Fo o::*ptns ) (void);
typ edef Screen &(Screen::*ACTION)(void);
pts = &Fo o::si; // ok
pts = &Fo o::nsi; // Error ACTION default = &Screen::home;
ptns = &Fo o::si; // Error
ACTION next = &Screen::forward;
ptns = &Fo o::nsi; // ok
7 8
Using a Pointer to Class Memb er
Function
Function Arguments
Pointers to class memb ers must always b e
Pointers to memb ers may be declared as
accessed through a sp eci c class objects.
arguments to functions, in addition, ade-
fault initiali z er may also be sp eci ed:
This is accomplished by using .* and ->*,
typ edef Screen &(Screen::*ACTION)(void);
the two p ointer-to-memb er selection op-
erators, e.g.,
screen; Screen my
ACTION default = &Screen::home;
Screen my screen, *buf screen = &my screen;
height; int (Screen::*pm )(void) = &Screen::get
Screen &(Screen::*pmfs)(Screen &) = &Screen::copy;
Screen& fo o (Screen&, ACTION = &Screen::display);
/* :::*/
void (void)
f
fo o (my screen); // pass &Screen::display
// Direct invo cation of memb er functions
screen, default); fo o (my
if (my screen.get height () == buf screen->get height ())
fo o (my screen, &Screen::b ottom);
buf screen->copy(my screen);
g
// Pointer to memb er equivalent
screen.*pm ) () == (buf screen->*pm )()) if ((my
(buf screen->*pmfs)(my screen);
9 10
Using a Pointer to Class Memb er
Using a Pointer to Class Memb er
Function (cont'd)
Function (cont'd)
A non-general implementation of a rep eat
function, that p erforms some user-sp eci ed
A declaration wishing to provide default
op eration n times could be done the fol-
arguments for memb er function repeat ()
lowing way:
might lo ok as follows:
enum Op eration f UP,DOWN, /* :::*/ g;
class Screen
Screen &Screen::rep eat (Op eration op, int times)
f
f
switch (op)
public:
f
Screen &rep eat (ACTION = &Screen::forward,
case DOWN: /* co de to iterate n times */;
break;
int = 1);
case UP: /* co de to iterate n times */;
/* :::*/
break;
g;
g
return *this;
g
An invo cation of rep eat might lo ok as fol-
lows:
Pointers to memb er functions allowamore
general implementation:
Screen my screen;
typ edef Screen &(Screen::*ACTION)(void);
/* :::*/
Screen &Screen::rep eat (ACTION op, int times)
f
for (int i = 0; i < times; i++)
my screen.rep eat (); // rep eat (&Screen::forward, 1);
(this->*op) ();
screen.rep eat (&Screen::down, 20); my
return *this;
g
12 11
Di erence between PTMF and
Example Usage (cont'd)
PTF
A table of p ointers to class memb ers can
also b e de ned. In the following example,
e.g.,
menu is a table of p ointers to class Screen
memb er functions that provide for cursor
movement:
#include
class Base 1 f
ACTION menu[] =
public:
f
void a1 (int);
&Screen::home;
static void a2 (int); // Note static:::
&Screen::forward;
g;
&Screen::back;
&Screen::up;
&Screen::down;
// Pointer to function typ e
&Screen::b ottom;
PTR)(int); typ edef void (*F
g;
enum Cursor Movements
// Pointer to Base 1 memb er function typ e
f
1::*MF PTR)(int); typ edef void (Base
HOME, FORWARD, BACK, UP,DOWN, BOTTOM
g;
void a3 (int i); // Forward decl.
Movements cm) Screen &Screen::move (Cursor
class Base 2 f
f
public:
(this->*menu[cm])();
void b1 (MF PTR);
return *this;
PTR); void b2 (F
g
g;
14 13
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";
base 2.b1 (base 1.a1);
void Base 1::a2 (int i) f
// Base 1::a1 got 3
cout << "Base 1::a2 got " << i << "\n";
g
2.b2 (a3);\n"; cout << "\nbase
base 2.b2 (a3);
void a3 (int i) f
cout << "a3 got " << i << "\n";
// a3 got 5
g
cout << "\nbase 2.b2 (base 1.a2);\n";
// De ne tw objects.
2.b2 (base 1.a2); base
1base 1; Base
// Base 1::a2 got 5
Base 2base 2;
cout << "\nbase 2.b2 (Base 1::a2);\n";
2::b1 (MF PTR fp) f void Base
2.b2 (Base 1::a2); base
/* Note object:::*/
(base 1.*fp)(3);
1::a2 got 5 // Base
g
return 0;
2::b2 (F PTR fp) f (*fp)(5); g void Base
g
15 16
Pointer to Class Data Memb er
Using a Pointer to Data Memb er
In addition to p ointers to memb er func-
Pointers to data memb ers are accessed in
tions, C++ also allows p ointers to data
a manner similar to that use for p ointer
memb ers.
to class memb er functions, using the op-
erators .* and ->*, e.g.,
{ Pointers to class data memb ers serve a similar
purp ose to the use of the ANSI C offsetof
macro for accessing structure elds.
SCREEN; typ edef short Screen::*PS
screen; Screen my
screen = new Screen (10, 10); Screen *tmp
The syntax is as follows:
{ The complete typ e of Screen::height is \short
void (void)
memb er of class Screen."
f
PS SCREEN ph = &Screen::height;
{ Consequently, the complete typ e of a p ointer
SCREEN pw = &Screen::width; PS
to Screen::height is \p ointer to short memb er
tmp screen->*ph = my screen.*ph;
of class Screen." This is written as:
screen->*pw = my screen.*pw; tmp
g
short Screen::*
A de nition of a p ointer to a memb er of
Note: since height and width are private
class Screen of typ e short lo oks like this:
memb ers of Screen, the initial i zati on 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!
Screen = &Screen::width; ps
17 18
Contravariance
Just as with data memb ers, we must be
Contravariance (cont'd)
careful ab out contravariance with p ointers
to memb er functions as well.
dp bp
e.g.,
struct Base f
b d
int i;
i i
virtual int fo o (void) f return i; g
g;
struct Derived : public Base f
? j
int j;
virtual int fo o (void) f return j; g
g;
void fo o (void) f
Base b;
Derived d;
Problem: what happ ens (b.*ptmfg) () is
int (Base::*ptmfb) (void) = &Base::fo o; // "ok"
int i = (b.*ptmfb) ();
called?
// trouble!
ptmfb = (int (Base::*) (void)) &derived::fo o;
int j = (b.*ptmfb) ();
// Tries to access non-existant j part of b!
g
19 20