tags:

views:

476

answers:

9

I'm attempting to pass a pointer to a function that is defined in one class into another class. After much research, I believe my syntax is correct, but I am still getting compiler errors. Here is some code which demonstrates my issue:

class Base
{
public:
    BaseClass();
    virtual ~BaseClass();
};

class Derived : public Base
{
public:
    // assign strFunction to the function pointer passed in
    Derived(string (*funPtr)(int)) : strFunction(funPtr);
    ~Derived();

private:
    // pointer to the function that is passed in
    string (*strFunction)(int value);
};

class MainClass
{
public:
    MainClass()
    {
     // allocate a new Derived class and pass it a pointer to myFunction
     Base* myClass = new Derived(&MainClass::myFunction); 
    }

    string myFunction(int value)
    {
     // return a string
    }
};

When I try to compile this code, the error I get is

error: no matching function for call to 'Derived::Derived(string (MainClass::*)(int))'

followed by

note: candidates are: Derived::Derived(string (*)(int))

Any idea what I might be doing wrong?

A: 

Object methods have a hidden "this" argument. If you pass the method to another class, what gets filled into the "this" argument? You might be able to do it with static (Class) methods.

Paul Tomblin
+2  A: 

Function pointers (that is pointers to unbound functions) and pointers-to-methods (that is pointers to non-static functions bound to a class definition), are different in c++. This is because non-static methods have an implicit this argument which requires that they always be called in the context of a instance of their class.

You're trying to pass a method-pointer to a constructor that takes a function-pointer. Which won't work.

dmckee
That makes sense.
Chris
+4  A: 

Yes, the type of &MainClass::myFunction is a pointer-to-member type whereas string(*)(int) is a pointer-to-function type. They are not compatible as you have to use a reference or pointer to a class instance and use the .* or ->* operators to use a pointer-to-member, whereas a pointer to a function is not attached to a class and can be called directly.

Charles Bailey
+8  A: 

your syntax is correct for a C style function pointer. Change it to this:

Derived(string (MainClass::*funPtr)(int)) : strFunction(funPtr) {}

and

string (MainClass::*strFunction)(int value);

remember to call strFunction, you will need an instance of a MainClass object. Often I find it useful to use typedefs.

typedef string (MainClass::*func_t)(int);
func_t strFunction;

and

Derived(func_t funPtr) : strFunction(funPtr) {}
Evan Teran
+4  A: 

You are trying to pass a pointer to a member function of the class MainClass, but the function expects a pointer to an ordinary, ie non-member, function. A good summary is here

The difference is important because member functions have a hidden extra parameter which tells the function which "this" pointer to apply the function to. So the pointer types aren't interchangeable.

Tom Smith
A: 

As the compiler warning is indicating, member function pointers are completely different from regular function pointers.

Eclipse
+5  A: 

You can learn more about the grave wickedness that is C++ member function pointer syntax here.

Crashworks
+1 for the link to the Clugston article. Good stuff.
Michael Burr
+2  A: 

Another syntax issue :


    // assign strFunction to the function pointer passed in
    Derived(string (*funPtr)(int)) : strFunction(funPtr);

replace for :


    // assign strFunction to the function pointer passed in
    Derived(string (*funPtr)(int)) : strFunction(funPtr) {};
lsalamon
+1  A: 

You may want to look into using std::tr1::bind and std::tr1::function similar to this (untested) code:

class Derived: public Base
{
  public:
    typedef std::tr1::function<string(int)> StringFunc;

    Derived(StringFunc);

  ...

  private:
    StringFunc strFunction;
}

and in MainClass constructor:

myBase = new Derived(std::tr1::bind(&MainClass::myFunction, *this, _1);

The bind function basically binds the member function to a particular object. Which takes care of the this pointer that is inserted by the compiler.

bsruth