<<

Pointers to Functions

The ++ 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 ("%", 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