Адрес печати виртуальной функции-члена
Я пытаюсь напечатать адрес виртуальной функции-члена.
Если я знаю, какой класс реализует функцию, которую я могу написать:
print("address: %p", &A::func);
Но я хочу сделать что-то вроде этого:
A *b = new B();
printf("address: %p", &b->func);
printf("address: %p", &b->A::func);
Однако это не компилируется. Возможно ли сделать что-то подобное, возможно, глядя на адрес в таблице vtable во время выполнения?
Ответы
Ответ 1
В настоящее время нет стандартного способа сделать это в С++, хотя информация должна быть доступна где-то. В противном случае, как программа могла вызвать функцию? Однако GCC предоставляет расширение, которое позволяет нам получить адрес виртуальной функции:
void (A::*mfp)() = &A::func;
printf("address: %p", (void*)(b->*mfp));
... при условии, что функция-член имеет прототип void func()
.
Это может быть очень полезно, если вы хотите кэшировать адрес виртуальной функции или использовать ее в сгенерированном коде. GCC предупредит вас об этой конструкции, если вы не укажете -Wno-pmf-conversions
. Это маловероятно, что он работает с любым другим компилятором.
Ответ 2
Указатели на функции-члены не всегда являются простыми адресами памяти. См. Таблицу в в этой статье, в которой указаны размеры указателей на функции для разных компиляторов - некоторые идут до 20 байтов.
В статье описывается, что указатель на функцию-член представляет собой блок данных, определенных для реализации, чтобы помочь разрешить вызов через указатель. Вы можете хранить и называть их ОК, но если вы хотите их распечатать, что вы печатаете? Лучше всего рассматривать его как последовательность байтов и получать его длину через sizeof
.
Ответ 3
Не имеет для меня большого смысла. Если у вас нормальная функция:
void f( int n ) {
}
то вы можете взять его адрес:
f
но вы не можете взять адрес функции вызов, что вам, похоже, нужно делать.
Ответ 4
Из того, что я могу сказать в стандарте, единственный раз, когда вы получаете динамическое связывание, - это вызов виртуальной функции. И как только вы вызвали функцию, вы выполняете инструкции внутри функции (т.е. Вы не можете "остановить на полпути" в вызове и получить адрес.)
Я думаю, что это невозможно.