С++ Указатель на виртуальную функцию

Если у вас есть такая структура, как эта

struct A {
    void func();
};

и ссылка, подобная этой

A& a;

вы можете получить указатель на свой метод func следующим образом:

someMethod(&A::func);

Теперь, что, если этот метод является виртуальным, и вы не знаете, что это такое во время выполнения? Почему вы не можете получить такой указатель?

someMethod(&a.func);

Можно ли получить указатель на этот метод?

Ответы

Ответ 1

Указатели членов учитывают виртуальность функций, на которые они указывают. Например:

#include <iostream>
struct Base
{
    virtual void f() { std::cout << "Base::f()" << std::endl; }
};

struct Derived:Base
{
    virtual void f() { std::cout << "Derived::f()" << std::endl; }
};


void SomeMethod(Base& object, void (Base::*ptr)())
{
    (object.*ptr)();    
}


int main()
{
    Base b;
    Derived d;
    Base* p = &b;
    SomeMethod(*p, &Base::f); //calls Base::f()
    p = &d;
    SomeMethod(*p, &Base::f); //calls Derived::f()    
}

Выходы:

Base::f()
Derived::f()

Ответ 2

Способ вызова указателя функции также должен содержать указатель на экземпляр объекта. Это позаботится обо всех проблемах с виртуальностью:

struct A { void func(); };

int main()
{
  typedef void (A::*mf)();

  A x; // irrelevant if A is derived or if func is virtual

  mf f = &A::func;   // pointer-to-member-function
  A* p = &x;         // pointer-to-instance

  (p->*f)();           // invoke via pointer
  (x.*f)();            // invoke directly
}

ОК, интересный запрос синтаксиса: предположим, что у меня есть это.

struct Basil { virtual void foo(); virtual ~Basil(); };
struct Derrek : public Basil { virtual void foo(); };

Теперь, если у меня есть Derrek * p или Basil * p, я могу вызвать член Basil через p->Basil::foo(). Как я мог сделать то же самое, если мне дали void(Derrek::*q)() = &Derrek::foo?

Ответ: Это невозможно. Только PMF q не знает, указывает ли он на виртуальную функцию, не говоря уже о которой, и не может быть использована для поиска функции базового класса во время выполнения. [Спасибо Стиву и Люку!]

Ответ 3

Вы можете получить указатель на него, например:

struct A {
    virtual void foo() = 0;
};

typedef void (A::*LPFOO)();

LPFOO pFoo = &A::foo;