Sefu
Sefu

Reputation: 2494

How to use a class function pointer in another class or struct?

I need to use a function defined in one class in another class. Instead of rewriting the whole function, I tried to pass the function as a pointer, as below:

class C {
  public:
    int get(int x) { return x*x; }
};

struct S {
    int (*func) (int x);
};

int main() {
    C c;
    S s;

    cout << c.get(3) << endl;

    s.func = &C::get;
    cout << s.func(3) << endl;

    return 0;
}

This doesn't work and gives the following error:

func_ptr.cpp: In function ‘int main()’:
func_ptr.cpp:42:18: error: cannot convert ‘int (C::*)(int)’ to ‘int (*)(int)’ in assignment

Is it possible to do something like this, and if so, how can I fix it? Moreover, if it is possible, can I use the pointer from an object instance instead of the class? That is, to possibly use variables defined in a specific class instance. Thanks.

Upvotes: 0

Views: 1681

Answers (3)

tsragravorogh
tsragravorogh

Reputation: 3153

If you're OK with using STL then you can utilize std::function to hold a pointer to a function and std::bind to bind that particular pointer to a particular function. It makes your code look much more cleaner. std::bind looks for both static and non-static member functions. For non-static member function would need to pass the object reference so it will be able to point to the correct address.

Here is a code snippet to show how to use it:

std::bind(ClassName::MemberFunctionName, object, std::placeholders::_1)

std::placeholders::_1 means that ::MemberFunctionName accepts one parameter.

Upvotes: 1

Praetorian
Praetorian

Reputation: 109089

C::get() is a non-static member function, which means it must be invoked on an instance of C. It has an implicit first argument, the this pointer, that must be passed to it when calling the function.

Since your C::get() doesn't seem to need access to any data members of C, you could make it a static member function.

static int get(int x) { return x*x; }

Now your code will work as is.


Another option is to change func so that it is a pointer to a member function of C

struct S {
    int (C::*func) (int x);
};

And invoke it as

s.func = &C::get;
std::cout << (c.*(s.func))(3) << std::endl;

Yet another option would be to change the type of S::func to std::function<int(int)>. Now it can hold any callable (function pointer, functor, lambda) that takes a single int as an argument, and returns an int.

struct S {
    std::function<int(int)> func;
};

s.func = std::bind(&C::get, &c, std::placeholders::_1);
std::cout << s.func(3) << std::endl;

Upvotes: 7

Zsolt
Zsolt

Reputation: 582

A regular function and a member function are a bit different. To use a member function, you'll need an object to call it on (i.e. the this pointer in a member function body).

Take a look at std::function and std::bind, they are used to handle function like (callable) entities in a uniform way. They can manage global functions, static member functions, lambdas, regular member functions, functors, whatever that can be called like a function.

e.g.:

struct S
{
    std::function<int(int)> func;
};
C c;
S s;
s.func = std::bind( &C::get, &c, std::placeholders::_1 );

Upvotes: 1

Related Questions