Function Pointer to Member Function

Function pointer to member function

The syntax is wrong. A member pointer is a different type category from a ordinary pointer. The member pointer will have to be used together with an object of its class:

class A {
public:
int f();
int (A::*x)(); // <- declare by saying what class it is a pointer to
};

int A::f() {
return 1;
}


int main() {
A a;
a.x = &A::f; // use the :: syntax
printf("%d\n",(a.*(a.x))()); // use together with an object of its class
}

a.x does not yet say on what object the function is to be called on. It just says that you want to use the pointer stored in the object a. Prepending a another time as the left operand to the .* operator will tell the compiler on what object to call the function on.

How do pointers to member functions work?

This of course depends on the compiler and the target architecture, and there is more than one single way to do it. But I'll describe how it works on the system I use most, g++ for Linux x86_64.

g++ follows the Itanium C++ ABI, which describes a lot of the details of one way various C++ features including virtual functions can be implemented behind the scenes for most architectures.

The ABI says this about pointers to member functions, in section 2.3:

A pointer to member function is a pair as follows:

   ptr:

For a non-virtual function, this field is a simple function pointer. ... For a virtual function, it is 1 plus the virtual table offset (in bytes) of the function, represented as a ptrdiff_t. The value zero represents a NULL pointer, independent of the adjustment field value below.

   adj:

The required adjustment to this, represented as a ptrdiff_t.

It has the size, data size, and alignment of a class containing those two members, in that order.

The +1 to ptr for a virtual function helps detect whether or not the function is virtual, since for most platforms all function pointer values and vtable offsets are even. It also makes sure a null member function pointer has a distinct value from any valid member function pointer.

The vtable / vptr setup for your class A will work something like this C code:

struct A__virt_funcs {
int (*func2)(A*, int);
};

struct A__vtable {
ptrdiff_t offset_to_top;
const std__typeinfo* typeinfo;
struct A__virt_funcs funcs;
};

struct A {
const struct A__virt_funcs* vptr;
};

int A__func1(struct A*, int v) {
std__operator__ltlt(&std__cout, "fun1");
return v;
}

int A__func2(struct A*, int v) {
std__operator__ltlt(&std__cout, "fun2");
return v;
}

extern const std__typeinfo A__typeinfo;

const struct A__vtable vt_for_A = { 0, &A__typeinfo, { &A__func2 } };

void A__initialize(A* a) {
a->vptr = &vt_for_A.funcs;
}

(Yes, a real name mangling scheme would need to do something with function parameter types to allow for overloading, and more things since the operator<< involved is actually a function template specialization. But that's beside the point here.)

Now let's look at the assembly I get for your main() (with options -O0 -fno-stack-protector). My comments are added.

Dump of assembler code for function main:
// Standard stack adjustment for function setup.
0x00000000004007e6 <+0>: push %rbp
0x00000000004007e7 <+1>: mov %rsp,%rbp
0x00000000004007ea <+4>: push %rbx
0x00000000004007eb <+5>: sub $0x38,%rsp
// Put argc in the stack at %rbp-0x34.
0x00000000004007ef <+9>: mov %edi,-0x34(%rbp)
// Put argv in the stack at %rbp-0x40.
0x00000000004007f2 <+12>: mov %rsi,-0x40(%rbp)
// Construct "a" on the stack at %rbp-0x20.
// 0x4009c0 is &vt_for_A.funcs.
0x00000000004007f6 <+16>: mov $0x4009c0,%esi
0x00000000004007fb <+21>: mov %rsi,-0x20(%rbp)
// Check if argc is more than 2.
// In both cases, "pf" will be on the stack at %rbp-0x30.
0x00000000004007ff <+25>: cmpl $0x2,-0x34(%rbp)
0x0000000000400803 <+29>: jle 0x400819 <main+51>
// if (argc <= 2) {
// Initialize pf to { &A__func2, 0 }.
0x0000000000400805 <+31>: mov $0x4008ce,%ecx
0x000000000040080a <+36>: mov $0x0,%ebx
0x000000000040080f <+41>: mov %rcx,-0x30(%rbp)
0x0000000000400813 <+45>: mov %rbx,-0x28(%rbp)
0x0000000000400817 <+49>: jmp 0x40082b <main+69>
// } else { [argc > 2]
// Initialize pf to { 1, 0 }.
0x0000000000400819 <+51>: mov $0x1,%eax
0x000000000040081e <+56>: mov $0x0,%edx
0x0000000000400823 <+61>: mov %rax,-0x30(%rbp)
0x0000000000400827 <+65>: mov %rdx,-0x28(%rbp)
// }
// Test whether pf.ptr is even or odd:
0x000000000040082b <+69>: mov -0x30(%rbp),%rax
0x000000000040082f <+73>: and $0x1,%eax
0x0000000000400832 <+76>: test %rax,%rax
0x0000000000400835 <+79>: jne 0x40083d <main+87>
// int (*funcaddr)(A*, int); [will be in %rax]
// if (is_even(pf.ptr)) {
// Just do:
// funcaddr = pf.ptr;
0x0000000000400837 <+81>: mov -0x30(%rbp),%rax
0x000000000040083b <+85>: jmp 0x40085c <main+118>
// } else { [is_odd(pf.ptr)]
// Compute A* a2 = (A*)((char*)&a + pf.adj); [in %rax]
0x000000000040083d <+87>: mov -0x28(%rbp),%rax
0x0000000000400841 <+91>: mov %rax,%rdx
0x0000000000400844 <+94>: lea -0x20(%rbp),%rax
0x0000000000400848 <+98>: add %rdx,%rax
// Compute funcaddr =
// (int(*)(A*,int)) (((char*)(a2->vptr))[pf.ptr-1]);
0x000000000040084b <+101>: mov (%rax),%rax
0x000000000040084e <+104>: mov -0x30(%rbp),%rdx
0x0000000000400852 <+108>: sub $0x1,%rdx
0x0000000000400856 <+112>: add %rdx,%rax
0x0000000000400859 <+115>: mov (%rax),%rax
// }
// Compute A* a3 = (A*)((char*)&a + pf.adj); [in %rcx]
0x000000000040085c <+118>: mov -0x28(%rbp),%rdx
0x0000000000400860 <+122>: mov %rdx,%rcx
0x0000000000400863 <+125>: lea -0x20(%rbp),%rdx
0x0000000000400867 <+129>: add %rdx,%rcx
// Call int r = (*funcaddr)(a3, argc);
0x000000000040086a <+132>: mov -0x34(%rbp),%edx
0x000000000040086d <+135>: mov %edx,%esi
0x000000000040086f <+137>: mov %rcx,%rdi
0x0000000000400872 <+140>: callq *%rax
// Standard stack cleanup for function exit.
0x0000000000400874 <+142>: add $0x38,%rsp
0x0000000000400878 <+146>: pop %rbx
0x0000000000400879 <+147>: pop %rbp
// Return r.
0x000000000040087a <+148>: retq
End of assembler dump.

But then what's the deal with the member function pointer's adj value? The assembly added it to the address of a before doing the vtable lookup and also before calling the function, whether the function was virtual or not. But both cases in main set it to zero, so we haven't really seen it in action.

The adj value comes in when we have multiple inheritance. So now suppose we have:

class B
{
public:
virtual void func3() {}
int n;
};

class C : public B, public A
{
public:
int func4(int v) { return v; }
int func2(int v) override { return v; }
};

The layout of an object of type C contains a B subobject (which contains another vptr and an int) and then an A subobject. So the address of the A contained in a C is not the same as the address of the C itself.

As you might be aware, any time code implicitly or explicitly converts a (non-null) C* pointer to an A* pointer, the C++ compiler accounts for this difference by adding the correct offset to the address value. C++ also allows converting from a pointer to member function of A to a pointer to member function of C (since any member of A is also a member of C), and when that happens (for a non-null member function pointer), a similar offset adjustment needs to be made. So if we have:

int (A::*pf1)(int) = &A::func1;
int (C::*pf2)(int) = pf1;

the values within the member function pointers under the hood would be pf1 = { &A__func1, 0 }; and pf2 = { &A__func1, offset_A_in_C };.

And then if we have

C c;
int n = (c.*pf2)(3);

the compiler will implement the call to the member function pointer by adding the offset pf2.adj to the address &c to find the implicit "this" parameter, which is good because then it will be a valid A* value as A__func1 expects.

The same thing goes for a virtual function call, except that as the disassembly dump showed, the offset is needed both to find the implicit "this" parameter and to find the vptr which contains the actual function code address. There's an added twist to the virtual case, but it's one which is needed for both ordinary virtual calls and calls using a pointer to member function: The virtual function func2 will be called with an A* "this" parameter since that's where the original overridden declaration is, and the compiler won't in general be able to know if the "this" argument is actually of any other type. But the definition of override C::func2 expects a C* "this" parameter. So when the most derived type is C, the vptr within the A subobject will point at a vtable which has an entry pointing not at the code for C::func2 itself, but at a tiny "thunk" function, which does nothing but subtract offset_A_in_C from the "this" parameter and then pass control to the actual C::func2.

Use pointer to member function to determine which function to call

Syntax to call a member function via member function pointer is

(this->*memf)();

You cannot magically turn the string into a member function pointer. Sloppy speaking, names of functions do not exist at runtime. If you want such mapping you need to provide it yourself. No way around that. What you can avoid is the "forest of if-else" by using a std::unordered_map:

#include <unordered_map>
#include <string>
#include <iostream>

class Karen
{
public:
void complain(std::string level) {
static const std::unordered_map<std::string, void(Karen::*)() const> m{
{"debug",&Karen::debug},
{"info",&Karen::info},
{"warning",&Karen::warning},
{"error",&Karen::error}
};
auto it = m.find(level);
if (it == m.end()) return;
(this->*(it->second))();
}

private:
void debug(void) const { std::cout << "debug\n"; }
void info(void) const { std::cout << "info\n"; }
void warning(void) const { std::cout << "warning\n"; }
void error(void) const { std::cout << "error\n"; }
};

int main() {
Karen k;
k.complain("info");
}

Live Demo

As mentioned in comments, you could use an enum in place of the string. When possible you should use the help of the compiler, which can diagnose a typo in an enum but not in a string. Alternatively you could directly pass a member function pointer to complain. Then implementation of complain would be trivial, no branching needed. Though this would require the methods to be public and the caller would have to deal with member function pointers.


If you are not allowed to use C++11 or newer you should have a serious talk with your teacher. Soon C++20 will be the de facto standard and things have changed quite a lot. I am not fluent in C++98 anymore, so here is just a quick fix of the above to get it working somehow. You cannot use std::unordered_map but there is std::map and initialization of the map is rather cumbersome:

#include <map>
#include <string>
#include <iostream>

class Karen
{
typedef void(Karen::*memf_t)() const;
typedef std::map<std::string,void(Karen::*)() const> map_t;

public:
void complain(std::string level) {
map_t::const_iterator it = get_map().find(level);
if (it == get_map().end()) return;
(this->*(it->second))();
}

private:
const map_t& get_map(){
static const map_t m = construct_map();
return m;
}
const map_t construct_map() {
map_t m;
m["debug"] = &Karen::debug;
m["info"] = &Karen::info;
m["warning"] = &Karen::warning;
m["error"] = &Karen::error;
return m;
}
void debug(void) const { std::cout << "debug\n"; }
void info(void) const { std::cout << "info\n"; }
void warning(void) const { std::cout << "warning\n"; }
void error(void) const { std::cout << "error\n"; }
};

int main() {
Karen k;
k.complain("info");
}

Live Demo

Generic member function pointer

You could create a generic templated function which accepts the signature you are interested in, pass in the instance of the object and the pointer to the member function. For example:

template<typename T>
void CallObjectMethod(int(T::*func)(int), T& obj, int val)
{
cout << (obj.*func)(val);
}

Now to call it like you mentioned in your example:

X x, x1;
CallObjectMethod(&X::echoX, x, 10);
CallObjectMethod(&X::echoX, x1, 20);

For object Y you could do something like:

Y y, y1;
CallObjectMethod(&Y::echoY, y, 10);
CallObjectMethod(&Y::echoY, y1, 20);

C++ How to make function pointer to class method [duplicate]

A member function is quite a bit different from an ordinary function, so when you want to point to a member function you need a pointer-to-member-function, not a mere pointer-to-function. The syntax for a pointer-to-member-function includes the class that the member function is a member of:

void (Game::*mptr)();

This defines a pointer-to-member-function named mptr that holds a pointer to a member function of the class Games that takes no arguments and returns nothing. Contrast that with an ordinary function pointer:

void (*ptr)();

This defined a pointer-to-function named ptr that holds a pointer to a function that takes no arguments and returns nothing.

Obtaining a function pointer to a non static member function

You need the following syntax:

std::function<void()> fnptr(std::bind(&A::myFunc, a));

You could also use a lambda expression like this:

auto fn = [a] { a->myFunc(); };

Here's a demo.

assign a member function to a function pointer

Your code looks confusing and, personally, I believe that C function pointers look ugly on C++'s OO implementation. So I would advise you to use the std::function. It only has been available since C++11. If you cannot use it, try looking on Boost's Implementation.

I can give you an example of how to use the std::function:

bool MyFunction(int i)
{
return i > 0;
}

std::function<bool(int)> funcPointer = MyFunction;

Using this you will drastically improve your code reliability. As of your problem, specifically:

class A
{
public:
std::function<int*(const int&)> fun;
A(std::function<int*(const int&)> f) : fun(f) {}
};

class B
{
private:
float r;
int *f(const int &t)
{
return new int(int(r) + t);
}
A *a;
B()
{

std::function<int*(const int&)> tempFun = std::bind(&B::f, this, _1);
a = new A(tempFun);
}
};

You have to add the following namespace:

using namespace std::placeholders;

How to use function pointers to access member functions?

Lets look at this simple example,

struct Greeting {
void SayHello() { std::cout << "Hello!\n"; }

void (Greeting::*pfHello)() = nullptr;
};

int main()
{
Greeting g;

// Lets assign the function pointer to the pfHello variable.
g.pfHello = &Greeting::SayHello;

// Now lets call it like a traditional function pointer.
g.pfHello(); // Triggers an error!

// Now lets call it by dereferencing it.
(*g.pfHello)(); // Still triggers an error..

// Okay lets call it just like g.SayHello() but by swapping the dereferenced pointer with SayHello.
(g.*(g.pfHello))(); // Works fine!
}

By looking at the example, we can see that the only way to call the member function pointer is by providing the dereferenced function pointer as the function body (in this case SayHello). And the object needs to be instantiated in order to do this, just like how we would do it if were going to call the SayHello() method directly.

Why do we need to instantiate the object before calling it?

That's because in order for the function to access other member variables and member functions, the object needs to be instantiated. This wont be an issue for static functions (because they cant access member variables and member functions).

Why dereferenced function pointer?

Well that's because your not directly storing the function pointer. Your storing the address of the function pointer (g.pfHello = &Greeting::SayHello;). This is why we need to dereference it.

That's why we have to use this: (this->*(pfSort))(); instead of this: pfSort().

Hope this would clear some doubts!

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);

How can i call a member function pointer from another member function?

You need to specify which object to call the function on:

(this->*fnPointer)();


Related Topics



Leave a reply



Submit