Passing a Pointer to a Class Member Function as a Parameter

How can I pass a member function where a free function is expected?

There isn't anything wrong with using function pointers. However, pointers to non-static member functions are not like normal function pointers: member functions need to be called on an object which is passed as an implicit argument to the function. The signature of your member function above is, thus

void (aClass::*)(int, int)

rather than the type you try to use

void (*)(int, int)

One approach could consist in making the member function static in which case it doesn't require any object to be called on and you can use it with the type void (*)(int, int).

If you need to access any non-static member of your class and you need to stick with function pointers, e.g., because the function is part of a C interface, your best option is to always pass a void* to your function taking function pointers and call your member through a forwarding function which obtains an object from the void* and then calls the member function.

In a proper C++ interface you might want to have a look at having your function take templated argument for function objects to use arbitrary class types. If using a templated interface is undesirable you should use something like std::function<void(int, int)>: you can create a suitably callable function object for these, e.g., using std::bind().

The type-safe approaches using a template argument for the class type or a suitable std::function<...> are preferable than using a void* interface as they remove the potential for errors due to a cast to the wrong type.

To clarify how to use a function pointer to call a member function, here is an example:

// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}

void non_member(void*, int i0, int i1) {
std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}

struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
}
};

void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}

int main() {
somefunction(&non_member, nullptr);
foo object;
somefunction(&forwarder, &object);
}

Passing a pointer to a member function as argument for a void* function

I want to able to pass it any function/method that receives no parameters and returns void. Not just member methods of A or just global functions.

Is this possible in C++?

Yes, it is possible, but you need to use a more flexible type. The way to achieve this is to specify the PerformAction function with a different type. You want to use a type that is callable with zero arguments and returns void, std::function<void ()>. For example change the PerformAction function to be: void PerformAction(std::function<void ()> fn);. This version will allow you to accept anything that's callable with zero arguments and returns void, see the following code for an example.

Example Code

#include <functional>
#include <iostream>

class Foo
{
public:
void bar() { std::cout << "Member function: Foo::bar()\n"; }
};

void bar()
{
std::cout << "Free function: bar()\n";
}

class Functor
{
public:
void operator()() { std::cout << "Functor object\n"; }
};

auto lambda = []() { std::cout << "Lambda expression\n"; };

void doSomething(std::function<void ()> fn)
{
fn();
}

int main()
{
doSomething(bar);
doSomething(Functor());
doSomething(lambda);

Foo foo;
doSomething(std::bind(&Foo::bar, &foo));

return 0;
}

Live Example

Example Output

Free function: bar()
Functor object
Lambda expression
Member function: Foo::bar()

Difficulty in passing function pointer of a class member function

You can't pass a non-static member function pointer as a regular function pointer. Member functions have access to the this pointer, and the way they get that is via an invisible implicit function parameter. You need to have the object on which to call the function, and the function itself, be bound together, which a function pointer simply can't do.

What we can do is make print_array_of_length5 a function template, and allow it to take any type of callable. That would give you something like this:

template <typename Function>
void print_array_of_length5(Function func){
for (int i = 0; i < 5; i++)
printf("%d ", func(i));
}

To call it with a non-static member function, you can use a lambda expression, or std::bind(), like this:

SIMPLE smpl;
print_array_of_length5([&smpl](int foo){ return smpl.retval(foo); });
using namespace std::placeholders;
SIMPLE smpl;
auto func = std::bind(&SIMPLE::retval, &smpl, _1);
print_array_of_length5(func);

Pass a class member function as a function parameter

Static member functions of classes are ultimately no different than regular functions. They're really just syntactic sugar; the function is simply has a name that include Classname::.

Non-static members are another matter altogether. There are two important things to remember about non-static member functions (NSMF).

First, every non-static member function has access to the non-static members of the class that they are a member of. This is possible even though you can have two objects of the same class that happen to store different data. If you have two std::string objects, they each store different strings. Executing a find on one string can return a found result in one but not the other.

This is because every NSMF has an implicit this pointer. this refers to, not merely a class, but the actual object upon which that NSMF operates. When you do this:

std::string aString("data");
aString.find("da");

The find function takes a string argument, but it also gets aString as its this. Every time find looks for the members of its class, it will be looking at aString's data.

So let's look at your prospective call of an NSMF:

((*)nMemberFunction())

Where is the object that it gets its this pointer from? Without an object, the NSMF could not access the non-static members of the object, since there is no object for it to find them in. This is not legal.

So, rule #1 about NSMFs: You must call them with an actual instance of the class that the NSMF is a member of (or a derived class thereof). You cannot just take an NSMF pointer and call it like a function pointer; you have to call it on a live object of that type.

Rule #2: the syntax for NSMF pointers is really ugly.

To define a variable (or argument) named arg of NSMF pointer type, you do this:

ReturnType (ClassName::*arg)(ParameterList);

Where ReturnType is the return type of the function, ParameterList is the list of arguments taken by the function, and ClassName is the name of the class to which the NSMF pointer belongs.

Given the ugliness, it is usually best to wrap it in a typedef:

typedef ReturnType (ClassName::*MemberPointerType)(ParameterList);

Thus creating the typedef MemberPointerType, which is a NSMF pointer.

Given an object named object, which is of type ClassName, you would call the member pointer arg as follows:

ReturnType value = (object.*arg)(Params);

Where Params are the arguments you wish to pass. If object is a pointer to a ClassName instead of a reference or a value, then you use object->*arg instead.

One more thing: you must use & to get the member pointer name. Unlike function pointers, NSMF pointers do not automatically convert to member pointers. You have to ask for them directly. So if ClassName has a member called Function that fit the above ReturnType and ParameterList, you would fill arg as follows:

arg = &ClassName::Function;

Rule #3: non-static member pointers are not pointers. Yes, they can be set to NULL (technically, they can be set to 0), but they are not the same thing as a pointer.

Most real C and C++ compilers will allow you to cast a function pointer to a void* and back. The standards consider this undefined behavior, but it's not-entirely-unknown to do this. You absolutely cannot do this with a NSMF pointer, on virtually all C++ compilers. Indeed, the sizeof(MemberPointerType) will likely not be the same size as void*.

So, NSMF pointers are not regular pointers. Do not treat them as such.

C++ How to pass member function pointer to another class?

In order to call a member function, you need both pointer to member function and the object. However, given that member function type actually includes the class containting the function (in your example, it would be void (Test:: *mEventFunction)(); and would work with Test members only, the better solution is to use std::function. This is how it would look like:

class Delegate {
public:
void SetFunction(std::function<void ()> fn) { mEventFunction = fn);
private:
std::function<void ()> fn;
}

Test::Test() {
Delegate testClass; // No need for dynamic allocation
testClass->SetFunction(std::bind(&Test::OnEventStarted, this));
}

Pass Member Function as Parameter to other Member Function (C++ 11 function)

ClassName::add is a non-static member function, an instance of ClassName is needed for it to be called on; it can't be used as the argument for std::function<double (double,double)> directly.

You can use lambda and capture this (as @Igor Tandetnik commented):

return intermediate(a, b, [this](double x, double y) { return add(x, y); } );

or use std::bind and bind this pointer:

return intermediate(a, b, std::bind(&ClassName::add, this, _1, _2));

or make ClassName::add a static member function or a non-member function (it could be because it doesn't use any members of ClassName). e.g.

class ClassName
{
public:
static double add(double a, double b);
...
};


Related Topics



Leave a reply



Submit