Are Dynamic / Generic Function Pointers Possible?

Is the following possible, and if so, how would I accomplish it?

//Event - Click////////////////////////////////
class EveCli
{
public:
virtual void Eve(Cli *cli) = 0;
};

//Widget////////////////////////////////////////
class Wid : public EveCli
{
public:
Wid() : EveCli();

~Wid(){};

virtual void Eve(Cli *cli);

WCheckBox* WidCheBox(..., void (EveCli::*)(Cli *cli), ...);
}

//Main////////////////////////////////////////////
int main(int argc, char **argv)
{
Wid *wid = new Wid();

wid->WidCheBox(..., &Wid::Eve, ...); //Results in an error

return 0;
}

The error I receive is of the following sort:

...no known conversion for argument 3 from ‘void (Wid::*)(Cli*)’ to ‘void (EveCli::*)(Cli*)’

The rational for this type of coding was to create something of a generic function pointer (EveCli) which all classes could inherit from (such as Wid) in order to better facilitate the passing of function pointers.

But so far, all my attempts to get it to work have been in vain and I'm at a loss for a solution.

Any help / suggestion would be much appreciated.

Thank you,
Nelson
Last edited on
EveCli::Eve() is a virtual function, so &EveCli::Eve will be polymorphic.

1
2
// wid->WidCheBox(..., &Wid::Eve, ...); //Results in an error
wid->WidCheBox(..., &EveCli::Eve, ...); // this is fine; polymorphic 


An example:
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
35
#include <iostream>

struct base
{
    virtual ~base() {}
    virtual void foo( int arg ) = 0 ;
    virtual void bar( int arg ) = 0 ;
};

void call_it( base* p, void (base::*fn)(int), int a ) { (p->*fn)(a) ; }

struct derived : base
{
    virtual void foo( int arg ) override
    { std::cout << "derived::foo(" << arg << ")\n" ; }

    virtual void bar( int arg ) override
    { std::cout << "derived::bar(" << arg << ")\n" ; }
};

struct more_derived : derived
{
    virtual void foo( int arg ) override
    { std::cout << "more_derived::foo(" << arg << ")\n" ; }
};

int main()
{
    base* p1 = new derived() ;
    call_it( p1, &base::foo, 1234 ) ; // derived::foo(1234)

    base* p2 = new more_derived() ;
    call_it( p2, &base::foo, 567 ) ; // more_derived::foo(567)
    call_it( p2, &base::bar, 89 ) ; // derived::bar(89)
}

http://liveworkspace.org/code/2cSuNM$0
Last edited on
@JLBorges
is this really possible? how does virtual function pointer work?
On line 10: how does p know that fn is foo or bar and that the derived function has to be called?
> how does p know that fn is foo or bar and that the derived function has to be called?

A typical implementation is for the pointer to contain sufficient information to tell the compiler:
a. Is this a pointer to a virtual function?
b. If it is, what is its offset into the vtable?
c. If it is, does the this pointer need adjustment? If it does need adjustment, how is it to be adjusted?

How implementations achieve this vary. For a scholarly discussion, see Lippman's 'Inside the C++ Object Model'
http://www.amazon.com/Inside-Object-Model-Stanley-Lippman/dp/0201834545

A fair amount of information is also there in the fast delegate article:
http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
Thank you for all your help.

Nelson
Of course... if you're using C++11... the easier way to do this is with std::function and std::bind. That way the function can be anywhere and doesn't need to be limited to any one class.

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
35
36
37
38
39
40
41
#include <functional>

typedef std::function<void (int)> Callback;  // void (int); is the callback signature

void call_it( Callback func, int param )
{
  func( param );  // <- very natural calling syntax
}

// some functions we can use to callback.  First, a member of any class/struct
struct SomeStruct
{
  void someFunc(int param)
  {
     //...
  }
};

// and also a global
void someGlobalFunc(int param)
{
  //...
}


int main()
{
  SomeStruct s;
  Callback member = std::bind( &SomeStruct::someFunc, &s );  // bind to a member
     // the 2nd param to bind is the 'this' pointer for someFunc.  In this case, it would be
     //  like calling s.someFunc

  call_it(member,5);  // works as you'd expect:  calls s.someFunc(5)



  // binding to a global var is just as easy
  Callback global = std::bind( &someGlobalFunc );

  call_it(global,5);  // also works as you'd expect:  calls someGlobalFunc(5)
}



You can also use bind to rearrange/supply parameters if the function signature differs. But I'll wait on giving examples of that unless you're really interested.
Topic archived. No new replies allowed.