C ++ Указатель на виртуальную функцию - PullRequest
16 голосов
/ 20 июля 2011

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

struct A {
    void func();
};

и такая ссылка

A& a;

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

someMethod(&A::func);

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

someMethod(&a.func);

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

Ответы [ 3 ]

26 голосов
/ 20 июля 2011

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

#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()
10 голосов
/ 20 июля 2011

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

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 не знает, указывает ли он на виртуальную функцию, не говоря уже о какой, и ее нельзя использовать для поиска функции базового класса во время выполнения. [Спасибо Стиву и Люку!]

0 голосов
/ 20 июля 2011

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

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

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

LPFOO pFoo = &A::foo;
...