2

I'm trying to implement an observer pattern (of sorts) with C++ and I want to use function pointer to do so, but I keep getting an error when trying to cast a function pointer from class B to a typedef function pointer:

#include <map>

typedef int (*OutputEvent)(const char*, const char*, int);

class A
{
private:
    int nextListenerId;
    std::map<int, OutputEvent> listenerMap;
public:
    A(){ nextListenerId = 0;}
    ~A(){}
    inline int RegisterListener(OutputEvent callback)
    {
        nextListenerId++;
        listenerMap[nextListenerId] = callback;
        return nextListenerId;
    }
};

class B
{
private:
    int listenerId;
public:
    B(const A& a)
    {
        OutputEvent e = &B::CallMeBack;
        listenerId = a.RegisterListener(e);
    }
    ~B(){}

    int CallMeBack(const char* x, const char* y, int z)
    {
        return 0;
    }
};

I created this example and I've pasted it into codepad.org, but when I it fails to compile (it doesn't compile in codepad.org nor in Visual Studio 2010):

Output:

t.cpp: In constructor 'B::B(const A&)':
Line 28: error: cannot convert 'int (B::*)(const char*, const char*, int)' to 'int (*)(const char*, const char*, int)' in initialization
compilation terminated due to -Wfatal-errors.

I don't understand why it can't convert the function pointers. Could anybody help me please?

Kiril
  • 39,672
  • 31
  • 167
  • 226
  • 1
    This has been asked many times before: http://stackoverflow.com/questions/4210710/cast-pointer-to-member-function-to-normal-pointer and more. See also http://www.parashift.com/c++-faq-lite/pointers-to-members.html . – Adam Rosenfield Jul 27 '11 at 15:40
  • See also http://stackoverflow.com/questions/1151582/pthread-function-from-a-class . – Adam Rosenfield Jul 27 '11 at 15:44

3 Answers3

1

The function you are trying to cast to OutputEvent is a member function. This is represented clearly in the error message by this:

'int (B::*)(const char*, const char*, int)'

which is a different type than

 int (*OutputEvent)(const char*, const char*, int)

because of the B:: part (that means that the function has an invisible this parameter).

If you define your member function as static, then you will be able to cast it to OutputEvent:

class B
{
   ....
   static int CallMeBack(const char* x, const char* y, int z);
   ...
 };
sergio
  • 68,819
  • 11
  • 102
  • 123
  • OK, then I'm thinking that my solution to this would be to really implement the observer pattern and have two types of observers: `B` would implement the `Observer` interface and if somebody else wants to use the OutputEvent function pointer, then they'll use a class `C` which takes that OutputEvent function pointer in the constructor (`C` would also implement the `Observer` interface). This way I can callback to a member function, static function, or a global (???) function. – Kiril Jul 27 '11 at 15:55
0

The member function doesn't match the typedef'd prototype because member functions have an invisible 'this' parameter. Make it a static function and it should work.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0

The class member function has got a hidden parameter, the object, which the global function does not have.

Do something like this:-

B*pB;

int CallMeBack(const char* x, const char* y, int z)
{
    return pB->CallMeBack(x,y,z);
}

More difficult if you have several callbacks on the go at the same time. But if there is only one you can have a pointer to the object and call via this.

QuentinUK
  • 2,997
  • 21
  • 20