Квалифицированный идентификатор вызова базовой функции через указатель

Если у меня есть виртуальная функция foo(), сначала определенная в базовом классе B, а затем переопределенная в производном классе D, как я могу сохранить адрес B::foo в указателе на элемент- так, что при вызове он будет вести себя как вызов с квалифицированным идентификатором (например, pd->B::foo())?

Пример:

struct B {
    virtual int foo() { return 1; }
};

struct D: public B {
    virtual int foo() { return 2; }
};

int main(int argc, char * argv[]) {
    D* pd = new D();
    int (B::*pf)() = &B::foo;
    int r = (pd->*pf)();
    return 0; 
}

Это вызовет D::foo(). Можно ли инициализировать pf таким образом, чтобы (pd->*pf)() вызывал B::foo(), даже если pd dynamic type - класс, который переопределяет foo()?

(Прежде чем кто-нибудь спросит, я действительно не хочу этого делать, мне просто интересно, если это возможно.)

Ответ 1

Я согласен с StoryTeller, я не думаю, что это возможно любым стандартным образом. Если вы действительно хотите добиться того, чтобы иметь возможность вызывать либо реализацию базового класса, либо реализацию производного класса с использованием одного и того же указателя функции, я могу порекомендовать следующее:

struct B {
    virtual int foo() { return fooB(); }
    int fooB() { return 1; }
};

struct D: public B {
    virtual int foo() { return 2; }
};

int main(int argc, char * argv[]) {
    D* pd = new D();
    int (B::*pf)() = &B::fooB;
    int r = (pd->*pf)();
    return 0; 
}

Так как тип указателя функции тот же, независимо от того, является ли функция виртуальной или нет, то создание не виртуальной функции в базовом классе позволяет напрямую принимать адрес.

Ответ 2

Почему бы просто не сделать:

pd->B::foo() 

Ответ 3

Я не верю, что ты можешь. У меня нет моего стандарта со мной, но с помощью vararg hack для печати значений указателя на функции-члены http://ideone.com/bRk7mG:

#include <iostream>
#include <cstdarg>
using namespace std;

struct Test
{
    void foo() {};
    virtual void bar() {}; 
    virtual void bar2() {};
    virtual void bar3() {};
};

void print_hack(int dummy, ...)
{
    va_list argp;
    va_start(argp, dummy);
    long val = va_arg(argp, long);
    cout << val << endl;
    va_end(argp);
}

int main() {
    print_hack (0, &Test::foo);
    print_hack (0, &Test::bar);
    print_hack (0, &Test::bar2);
    print_hack (0, &Test::bar3);
    return 0;
}

Кажется, что значение, хранящееся в указателе (по крайней мере для GCC), является индексом в виртуальной таблице объектов.
Для не виртуальных функций он выглядит как обычный указатель функции.

В основном вы вынуждены выполнять динамическую отправку при использовании функции-указателя на элемент, которая содержит виртуальную функцию, по крайней мере, насколько я знаю.

Ответ 4

Я согласен с snakedoctor, вы должны сделать:

int r = pd->B::foo()

Это просто вызов метода матери.