@ RocketMagnet - это ответ на ваш другой вопрос , который был назван дубликатом. Я отвечаю на этот вопрос, а не на этот.
Как правило, указатель C ++ на функции-члены нельзя переносить через иерархию классов. Тем не менее, вы часто можете сойти с рук. Например:
#include <iostream>
using std::cout;
class A { public: int x; };
class B { public: int y; };
class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
int main() {
typedef void (A::*pmf_t)();
C c; c.x = 42; c.y = -1;
pmf_t mf = static_cast<pmf_t>(&C::foo);
(c.*mf)();
}
Скомпилируйте этот код, и компилятор справедливо жалуется:
$ cl /EHsc /Zi /nologo pmf.cpp
pmf.cpp
pmf.cpp(15) : warning C4407: cast between different pointer to member representations, compiler may generate incorrect code
$
Итак, чтобы ответить "почему в C ++ нет указателя на член-функцию-на-пустом-классе?" в том, что у этого воображаемого базового класса всего нет членов, так что нет никакого значения, которое вы могли бы ему приписать! «void (C :: ) ()» и «void (void :: ) ()» являются несовместимыми типами.
Теперь, держу пари, ты думаешь: "Подожди, я уже отлично разыграл указатели на функции-члены!" Да, вы можете использовать reinterpret_cast и одиночное наследование. Это в той же категории других переосмысления приведений:
#include <iostream>
using std::cout;
class A { public: int x; };
class B { public: int y; };
class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
class D { public: int z; };
int main() {
C c; c.x = 42; c.y = -1;
// this will print -1
D& d = reinterpret_cast<D&>(c);
cout << "d.z == " << d.z << "\n";
}
Так что, если void (void::*)()
существовал, но вы ничего не могли бы безопасно / портативно присвоить ему.
Традиционно вы используете функции сигнатуры void (*)(void*)
везде, где вы хотели бы использовать void (void::*)()
, потому что, хотя указатели на функции-члены не приводят хорошо вверх и вниз по иерархии наследования, указатели void действительно работают хорошо. Вместо этого:
#include <iostream>
using std::cout;
class A { public: int x; };
class B { public: int y; };
class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
void do_foo(void* ptrToC){
C* c = static_cast<C*>(ptrToC);
c->foo();
}
int main() {
typedef void (*pf_t)(void*);
C c; c.x = 42; c.y = -1;
pf_t f = do_foo;
f(&c);
}
Так что на ваш вопрос. Почему C ++ не поддерживает такой тип приведения. Типы указателя на функцию-член уже имеют дело с виртуальными против не виртуальных базовых классов и виртуальными против не виртуальных функций-членов, все в одном типе, увеличивая их до 4 * sizeof (void *) на некоторых платформах. Я думаю, потому что это еще больше усложнит реализацию указателя на функцию-член, а необработанные указатели на функции уже так хорошо решают эту проблему.
Как прокомментировали другие, C ++ предоставляет авторам библиотек достаточно инструментов, чтобы сделать это, и тогда «нормальным» программистам, таким как вы и я, следует использовать эти библиотеки вместо того, чтобы потворствовать этим деталям.
РЕДАКТИРОВАТЬ: отмеченные сообщества вики. Пожалуйста, отредактируйте, чтобы включить соответствующие ссылки на стандарт C ++, и добавьте курсивом. (особенно добавить ссылки на стандарт, где мое понимание было неправильным! ^ _ ^)