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
Does Try-Catch Block Decrease Performance
Add External Libraries to Cmakelist.Txt C++
Allocating Vectors (Or Vectors of Vectors) Dynamically
Reading an Application's Manifest File
Is Wchar_T Needed for Unicode Support
Vary Range of Uniform_Int_Distribution
Deciphering C++ Template Error Messages
What Are Use Cases for Structured Bindings
Acquire/Release Semantics with 4 Threads
When Should Functions Be Member Functions
Clang C++ Cross Compiler - Generating Windows Executable from MAC Os X
Does an R Compiler to C/C++ Exist
How to Effectively Kill a Process in C++ (Win32)
Why Isn't There an Operator[] for a Std::List
How to Check If a Function Exists in C/C++
C++ Memory Barriers for Atomics