Lecture Notes for Advanced Programming II

5 March 2002 - Function Pointers


  1. a c more than a c++ feature, but useful none the less

    1. parameter functions - stl

    2. basis for implementing virtual functions

    3. used heavily in gui programming - callbacks

  2. declarations - can be hairy, but follows logically (sorta)

    1. T (* fp)(arg list) - bool (* comp)(int, int)

    2. watch those parenthesis - all must appear; it's a precedence thing

      1. bool (* comp)(int, int); is not the same as bool * comp(int, int);

      2. the first declares a function-pointer variable, the second a constant (an extern declaration for a function returning a pointer to a boolean)

      3. similar to int pointers and int array names

    3. typedefs are a help, but are not universally applicable

  3. operations

    1. call () - it's an operator(!)

      1. second highest precedence (:: is highest) - watch those parenthesis

      2. (* comp)(1, 2) is not the same as * comp(1, 2).

      3. the procedure call operator () can be overloaded(!) - used heavily in the stl (function objects or functors).

    2. address of & - not really necessary; a function name is a function pointer - similar to array names

      1. bool (*comp)(int, int) = &less; is the same as bool (*comp)(int, int) = less;

    3. pointer follow * - not really necessary for calls; compilers automatically follow function pointers when necessary

      1. (* comp)(3, 4) is the same as comp(3, 4).

      2. this is not true for declarations - * must appear

  4. uses

    1. generalize procedures with respect to behavior

      1. find the minimum value over an interval

        1. double find_min(double, double, double (* fp)(double)

      2. many stl generic algorithms (the _if ones, in particular)

      3. custom error handling - got an error? call a function

        1. widget::widget(void (* efp)(args), args)

    2. quick 'n' dirty (sometimes very dirty) oo programming

      1. a struct of function pointers looks like an object

        1. operating system device-driver interfaces

          struct device_driver {
            int (* open)(const char * name, mode_t mode);
            int (* close)(void);
            int (* read)(char * data, unsigned size);
            int (* write)(const char * data, unsigned size);
            }
          
          device_driver disk_device_driver =
            { disk_open, disk_close, disk_read, disk_write };
          device_driver tty_device_driver =
            { tty_open, tty_close, tty_read, tty_write };
          
          void t(void) {
            device_driver dd = disk_device_driver;
            (dd.open)("/dev/null", R_ONLY);
            }  
          

      2. finite-state machine simulators

        1. a matrix next-state representation can be sparse and wasteful

        2. represent each state (row) as a function

          1. typedef int (* next_state)(input);

          2. next_state fsm[] = { r1, r2, ... };

          3. current_state = fsm[current_state](input);

    3. simulated quasi-concurrency - callback functions.

      1. coordinating two or more independent but related program parts - how do the parts coordinate

      2. callbacks - each part gives the other functions to call when coordinate in necessary

      3. gui programming - the front-end interacts, the back-end reacts

        1. the back-end gives the front-end functions to call when buttons are pushed

      4. discrete event simulators - an event occurs, a function happens

        1. each event includes a function pointer when the event occurs

        2. the simulator calls the event's function

  5. c++ function call features

    1. function pointers are less useful in c++

      1. objects are safer, easier to use (but possibly more expensive)

    2. what about member functions?

      1. a member function needs its context

      2. the arcane .* and ->* syntax (neither overloadable)

    3. overloading operator () is much more fun, though


This page last modified on 5 March 2002.