There is nothing portable. Your attempt to use &cls::fn2 cannot work, since the results should work in cases like (pCls->*fn)() , even if pCls points to a derived class that overrides the function. (Pointers to member functions are complex beasts that determine whether this function is virtual or not, and provide different information depending on this. And if you are experimenting with MSC, keep in mind that you must specify /vmg for function pointers members to work correctly.)
Even for this implementation, you need an instance of the correct type. Given this, if you know the layout of the class and the location of the virtual function table, you can track it. Typically, a pointer to a virtual function table is the first word in a class, although this is not guaranteed. And also usually functions will be displayed in the order in which they are declared. Together with additional information, for example, pointers to RTTI and, possibly, the shift of the necessary information to fix the this pointer when calling the function (although many compilers will use a trampoline for this). For 64 bit g ++ on Windows (CygWin version):
struct C { virtual ~C() {} virtual void fn1() const { std::cout << "In C::fn1\n"; } virtual void fn2() const {} }; void const* fn1ToAddr( C const* pC ) { void const* const* vPtr = *reinterpret_cast<void const* const* const*>(pC); return vPtr[2]; }
fn1ToAddr returns the address fn1 for the passed object to it; if the object is of type C , it returns the address C::fn1 , and if it has a derived type that overrides fn1 , it returns the address of the overriding function.
Whether it is all the time or not, I cannot say; I think g ++ uses trampolines in cases of multiple inheritance, for example (in this case, the trampoline address will be the return address). And this may not work for the main release of g ++. (For the MSC version that I have on hand, replacing the 2 by 1 index seems to work. But then again, I just tried very simple cases. There is absolutely no guarantee.)
Basically, you will never want to do anything like this in production code. However, it can be useful if you are trying to understand how the compiler works.
EDIT:
Repeat your editing with what? Just because you have an address (possibly) does not mean that you can call a function. You cannot call a member function without an object, and depending on any number of things, you cannot pass an object function. (For example, with MSC, the object will usually be transferred to ECX.)