Вместо создания оболочки для каждого обработчика во всех производных классах (конечно, даже без удаленного подхода), вы можете просто использовать static_cast
для преобразования DEH::func_t
в EH::func_t
. Указатели-члены контравариантны : они естественным образом преобразуются вниз по иерархии, и их можно вручную преобразовать вверх по иерархии, используя static_cast
(в отличие от обычных указателей объектов, которые ковариантны ).
Ситуация, с которой вы имеете дело, является именно той причиной, по которой функциональность static_cast
была расширена, чтобы разрешить передачу указателя на член. Более того, нетривиальная внутренняя структура указателя на функцию-член также реализована именно таким образом, чтобы правильно обрабатывать такие ситуации.
Итак, вы можете просто сделать
DEH() {
func_t f5 = &DEH::handle_event_5;
register_handler(5, static_cast<EH::func_t>(f5));
........
}
Я бы сказал, что в этом случае нет смысла определять имя typedef DEH::func_t
- это довольно бесполезно. Если вы удалите определение DEH::func_t
, типичный регистрационный код будет выглядеть следующим образом
DEH() {
func_t f5 = static_cast<func_t>(&DEH::handle_event_5);
// ... where `func_t` is the inherited `EH::func_t`
register_handler(5, f5);
........
}
Чтобы сделать его более элегантным, вы можете предоставить оболочку для register_handler
в DEH
или использовать другие средства (макрос? Шаблон?), Чтобы скрыть приведение.
Этот метод не предоставляет никаких средств для проверки правильности указателя обработчика в момент вызова (как вы могли бы сделать с dynamic_cast
в версии на основе оболочки). Однако я не знаю, насколько вы заботитесь о том, чтобы этот чек был на месте. Я бы сказал, что в этом контексте это на самом деле ненужно и чрезмерно.