Function pointers vs subclasses

Feb 25, 2013 at 12:35pm
Hi Guys,

I am in a position to choose between function pointers and subclassed objects. To make it clear, say I have to notify some object of some action (a timer for example); refer to the following two choices (a very basic code for demo purposes):

Version 1
1
2
3
4
5
6
7
8
typedef void TimerCallback(void *args);
class Timer{
public:
  Timer();
  ~Timer();
  void schedule(TimerCallback *callback, void *args, long timeout)=0;
  void cancel();
};


Version 2:
1
2
3
4
5
6
7
8
9
10
11
12
13
class TimerTask{
  public:
    TimerTask();
    virtual ~TimerTask();
    void timedout()=0;
};
class Timer{
  public:
    Timer();
    virtual ~Timer();
    void schedule(TimerTask *callback, long timeout)=0;
    void cancel();
};


which one is the standard C++ way and which one is efficient?

Please let me know if I am not clear in this regard.

Thanks
Feb 25, 2013 at 2:45pm
Neither. The usual C++ way is to pass a function object (e.g. the result of a bind(), a lambda expression, or a user-defined class with an operator() to call back). They are generally more efficient than function pointers or your callback object with a virtual function call because they are much easier to inline.
Last edited on Feb 25, 2013 at 2:46pm
Feb 25, 2013 at 2:56pm
> which one is the standard C++ way

The standard C++ way would be to give the users of the timer class complete flexibility in deciding how to implement the callback.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <functional>
#include <vector>
#include <iostream>

struct timer
{
    template < typename FN, typename ... ARGS >
    void schedule( FN fn, ARGS... args )
    {
        callbacks.emplace_back( std::bind( fn, args... ) ) ;
        // ...
    }

    void notify_all() { for( const auto& fn : callbacks ) fn() ; }

    std::vector< std::function< void(void) > > callbacks ;
};

void free_fun( int a, double b ) { std::cout << "free_fun( " << a << ", " << b << " )\n" ; }

int main()
{
    timer t ;

    struct A { int mem_fun() { std::cout << "A::mem_fun()\n" ; return 7 ; } };
    A object ;
    t.schedule( &A::mem_fun, &object ) ;

    t.schedule( [](int i) { std::cout << "closure(" << i << ")\n" ; }, 70 ) ;

    t.schedule( free_fun, 23, 7.89 ) ;

    t.notify_all() ;
}
Last edited on Feb 25, 2013 at 2:58pm
Feb 25, 2013 at 3:50pm
In the case of a library that needs to be able to be compiled with one compiler and linked to code compiled in another, I don't think virtual inheritance or std::function are acceptable. Function pointers are more universal, unfortunately, but you can always restrict users of your library to compile the library with the same compiler and settings as the code they're linking to.
Feb 25, 2013 at 5:01pm
> In the case of a library that needs to be able to be compiled with one compiler
> and linked to code compiled in another, ...

Do not use C++. Any part of C++.
Feb 25, 2013 at 5:09pm
JLBorges wrote:
Do not use C++. Any part of C++.
Oh, I guess that makes sense. I've got to pick a side. I'll choose to not allow cross-linking in that case.
Feb 25, 2013 at 5:09pm
Are there C++ libraries that aren't templated on callback type? Even ACE did that.
Topic archived. No new replies allowed.