1

Is it possible (and how) to obtain the index of a virtual function in the virtual method table?

class A
{
    virtual void foo();
}

I know foo is the first (0) item in the virtual method table

However can I have foo and get 0?

skypjack
  • 49,335
  • 19
  • 95
  • 187
Adam W
  • 317
  • 1
  • 3
  • 15
  • 1
    What are you trying to achieve? – DeiDei Sep 18 '16 at 08:43
  • 4
    I suspect it's implementation defined and depends on the ABI, so (theoretically) no in a portable way. – skypjack Sep 18 '16 at 08:44
  • 1
    Possible duplicate of [How to get every virtual function index just as the compiler does?](http://stackoverflow.com/questions/3062647/how-to-get-every-virtual-function-index-just-as-the-compiler-does) – DeiDei Sep 18 '16 at 08:45
  • Call virtual functions of another class without mapping every single function. (create my own class; redirect the virtual functions to the actual functions) – Adam W Sep 18 '16 at 08:46
  • 2
    Why? The C++ language has no concept of vtables at all. If you know your implementation uses vtables, you have to do implementation-specific tricks. – n. m. could be an AI Sep 18 '16 at 08:46
  • I assume I can search the VMT for the address of a function to obtain it's index? – Adam W Sep 18 '16 at 08:47
  • 1
    You may want to override `operator->` and `operator *` instead, so that `yourClassObj->func()` goes to some other class. – n. m. could be an AI Sep 18 '16 at 08:49
  • Pointers to members can and will do virtual dispatch if they hold a virtual function. You won't have to rely on it being done with vtables, and will get some static type checking. – StoryTeller - Unslander Monica Sep 18 '16 at 10:19

4 Answers4

1

As I said in the comments, I suspect it's implementation defined an implementation detail (thanks to @SteveJessop for having pointed the right terms out in the comments to the answer) and depends on the ABI, so (theoretically) it is not possible in a portable way.
As an example of a known ABI definition, see here (Itanium C++ ABI).
In other terms, that's a jargon term in the C++ standard and means - the implementation must document it.
Moreover, as @n.m. mentioned in the comments to the question, the standard doesn't contain anything like a vtable, so hardly is it ruled explicitly.
Implementations are free to use them or not, and if they use them they're free to provide a supported means for user code to access them or not.

That said, again: there is not an explicit, portable way to do that.

skypjack
  • 49,335
  • 19
  • 95
  • 187
1

Even though vtables happen to be the way most (probably all) C++ implementations implement virtual function dispatch, there's no guarantee of them even existing in the standard, much less that they're in a particular order.

In other words, the only way to know is to take your particular compiler, find out how it arranges the vtable, and then follow the same algorithm based on the class layout to find the index for the function you're interested in.

Or otherwise use incredibly platform-specific hacks to get the actual address of the member function, find the vtable in memory, and search for the address inside.

But either way, such information is specific to one platform and compiler, possibly even compiler version, depending on the ABI guarantees of that particular compiler.

As a side note, both GCC and MSVC++ have documented layout algorithms for their vtable, and documented algorithms for where the vptr sits in an object. For GCC, the documentation is the Common C++ ABI (a.k.a. Itanium C++ ABI). For MSVC++, I don't know where the documentation is or if it exists directly, but the compiler guarantees that at least classes without data members are laid out to be compatible with the COM ABI.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
0

Ideally, we can loop the functions address and compare the specified function's address, i wrote following code in g++, which could output the index of virtual function.

#include <iostream>
#include <stdio.h>
using namespace std;

class test {
public:
  virtual void foo() {
    cout << "foo" << endl;
  }
  virtual void goo() {
    cout << "goo" << endl;
  }
  virtual void hoo() {
    cout << "hoo" << endl;
  }
};

int find_function_index(test* p, void* f) {
  for(int i = 0; i < 3; ++i) {
    void* tmp = (void*)*((long*)*(int*)(p)+i);
    if(tmp == f)
      return i;
  }
  return -1;
}

int main() {
  test* p = new test();

  void* f1 = reinterpret_cast<void*>(&test::foo);
  cout << "foo: " << find_function_index(p, f1) << endl;

  void* f2 = reinterpret_cast<void*>(&test::goo);
  cout << "goo: " << find_function_index(p, f2) << endl;

  void* f3 = reinterpret_cast<void*>(&test::hoo);
  cout << "hoo: " << find_function_index(p, f3) << endl;
}

The following pic is the address of test::goo and the value of f2 (which is store the correct address of test::goo) enter image description here

Tongxuan Liu
  • 270
  • 1
  • 12
  • This code makes no sense at all. This is *not* Python; doing `p->pf1` will not resolve to a "bound" instance of the method, and _even if it did_, it could not be assigned to a `void (*func)()` type. You need to store the `test* const this` hidden argument somewhere! In the best case, a member function `void (test::*)()` _might_ be assignable to `void (*)(test*)`, but even that is not guaranteed because the way to pass the `this` pointer (the ABI) might be different between those two calls. – Javier Martín Sep 18 '16 at 17:58
  • PS: if you want to store a "bound call" to a method, you need to use either a functor or a lambda: `std::bind(std::mem_fn(&test::foo), p)` or `[p]() { p->foo(); }` would both work, but neither is assignable to `void (*)()` because both use an object to store something (a copy of the pointer p). – Javier Martín Sep 18 '16 at 18:01
  • @Javier, in skypjack's case, he just need to know the address of virtual function, then retrieve the functions address in vtable is ok. Why need a test* const this? All the object of one type should point to the same vtable, right? The code which i tried like f1(), f2(), f3(), if inside these functions using any member variable of course would undefined behavior. Don't assume, you can try the code and check the disassembly yourself. – Tongxuan Liu Sep 19 '16 at 02:36
  • as I said, your code is *not* C++. You are relying on the fact that the functions in question have a specific ABI as members, for example so that calling them _without_ the `this` pointer will not affect other arguments. This is not necessarily so; it is an implementation detail. Furthermore, even if the ABI allowed your black magic, the C++ standard _explicitly_ states that calling a member function with an invalid `this` pointer is undefined behaviour, _even if it is non-virtual and does not access other members_. How do you know the fuctions are not getting `nullptr` as `this`? – Javier Martín Sep 19 '16 at 06:24
  • We just need filter the address of member function, not the this pointer. I agree if you call the function using the function pointer would trigger undefined behavior, but why you call the member function? you just need the address, and go to find it in vtable, right? – Tongxuan Liu Sep 19 '16 at 06:41
  • As others have said, it is not even required that the implementation of virtual functions use vtables! It just is the most widely used implementation right now, but next year it could be something else entirely and it would be OK by the standard. So the whole "what is the index" question makes no sense within the standard. Furthermore, even if you simply wanted to stored the _address_ of the code of those functions and not call them, your code is still not valid. The only thing you can do with an expression of the type `(p->*pf1)` is _call it_. You cannot typecast it, not within the standard. – Javier Martín Sep 19 '16 at 06:57
  • The code is just a way to try to get the index from vtable in gcc 4.8.1, it's a practical way, not documented or standardized. Probably next version compiler would forbidden me to do this, then try to hack it another way. – Tongxuan Liu Sep 19 '16 at 07:26
0

You seem to want to do virtual dispatch in a general fashion, knowing only the functions signature, and getting that function reference in some other fashion.
While that pursuit may have merit, your question conflates it with an implementation detail (the vtable), which is not guaranteed by the C++ standard.

Fortunately for you, the standard offers a way to call a member function without knowing its name, and it even respects virtual dispatch. It's a simple pointer to member (which you can store and copy). You'd use it like this:

#include <iostream>

struct A
{
    virtual void foo() { std::cout << "A::foo\n"; } 
};

struct AA : A
{
    virtual void foo() { std::cout << "AA::foo\n"; } 
};

struct AAA : AA
{
    virtual void foo() { std::cout << "AAA::foo\n"; } 
};

void bar (A& a, void (A::* pMem)())
{
    (a.*pMem)();
}

int main() {
    A a;
    AA aa;
    AAA aaa;

    bar (a, &A::foo);
    bar (aa, &A::foo);
    bar (aaa, &A::foo);

    return 0;
}
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458