Квалифицированный идентификатор вызова базовой функции через указатель
Если у меня есть виртуальная функция 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()
Это просто вызов метода матери.