В MSVC вы не можете просматривать во время выполнения виртуальную таблицу и сравнивать равенство с указанным указателем на функцию-член, поскольку они не совпадают.Один - реальный указатель, другой - указатель, который перенаправляет на настоящий.
Однако с этим компилятором вы можете сделать это во время выполнения с другим обнаруженным мной хаком.
Создать класс (например, IndexFinder), внутри которого вы объявляете столько методов экземпляра, сколько максимальных виртуальных методов вы можете иметь в классе.Каждый из этих методов должен возвращать уникальное целочисленное значение, начиная с 0 до максимального значения.
Создайте поддельную таблицу виртуальных методов и сохраните ваши указатели методов так, чтобы возвращаемое ими целое число совпадало с индексом, в котором вы их храните (метод, который возвращает 0, будет первым в вашей поддельной таблице).Когда вы хотите найти индекс любого виртуального метода, вы должны выполнить грязное приведение указателя на член метода к указателю на метод IndexFinder.
Принцип прост: для виртуальных методов компилятор генерирует код, который перенаправляетк реальному методу, используя vtable с хорошим индексом.Когда вы заменили созданный компилятором vtable на поддельный, он перейдет к вашему, а не к предполагаемому.Поскольку ваш метод возвращает индекс, внутри которого он хранится, вам просто нужно получить возвращение, и у вас есть свой индекс.
Вот код, который является более явным (я повторяю, что хак зависит от компилятора, те, ктоне нравится, не читай ^^).Но я попробовал, он работает отлично, так как это просто перенаправление перенаправления (я ищу трюк с GCC, но пока не нашел).
Возможно, это зависит от соглашения о вызовах, пока я не пробовал его во всех случаях.Одним из преимуществ этого трюка является то, что вам не нужно создавать экземпляр вашего класса, чтобы найти индекс одного из его виртуальных методов.
// In the header .h
class IndexFinder
{
typedef int (IndexFinder::*method_pointer)();
public:
template<typename _MethodPtr>
int getIndexOf(_MethodPtr ptr) {
return (reinterpret_cast<IndexFinder*>(&fake_vtable_ptr)->**((IndexFinder::method_pointer*)(&ptr)))()
}
protected:
int method0() { return 0; }
int method1() { return 1; }
int method2() { return 2; }
int method3() { return 3; }
protected:
typedef method_pointer fake_vtable_t [4];
static fake_vtable_t fake_vtable;
void* fake_vtable_ptr;
};
// In the cpp file
IndexFinder::fake_vtable_t IndexFinder::fake_vtable = {
&IndexFinder::method0 ,
&IndexFinder::method1 ,
&IndexFinder::method2 ,
&IndexFinder::method3
};
void* IndexFinder::fake_vtable_ptr = &IndexFinder::fake_vtable;
// to use it :
int index = IndexFinder::getIndexOf(&YourClass::yourVirtualMethod);