Как класс Derived наследует статическую функцию от базового класса?
struct TimerEvent
{
event Event;
timeval TimeOut;
static void HandleTimer(int Fd, short Event, void *Arg);
};
HandleTimer должен быть статичным, поскольку я передаю его в библиотеку C (libevent).
Я хочу наследовать от этого класса. Как это можно сделать?
Спасибо.
Ответы
Ответ 1
Вы можете легко наследовать от этого класса:
class Derived: public TimerEvent {
...
};
Однако вы не можете переопределить HandleTimer в своем подклассе и ожидать, что это сработает:
TimerEvent *e = new Derived();
e->HandleTimer();
Это связано с тем, что статические методы не имеют записи в таблице vtable и не могут быть виртуальными. Однако вы можете использовать "void * Arg" для передачи указателя на свой экземпляр... что-то вроде:
struct TimerEvent {
virtual void handle(int fd, short event) = 0;
static void HandleTimer(int fd, short event, void *arg) {
((TimerEvent *) arg)->handle(fd, event);
}
};
class Derived: public TimerEvent {
virtual void handle(int fd, short event) {
// whatever
}
};
Таким образом, HandleTimer все еще может использоваться из функций C, просто убедитесь, что всегда передавайте "реальный" объект как "void * Arg".
Ответ 2
В некоторой степени шаблон шаблонов позволяет наследовать и переопределять статические методы.
Сначала начните с базового класса:
struct base {
static void talk() { std::cout << "hello" << std::endl; }
static void shout() { std::cout << "HELLO !!" << std::endl; }
};
Затем выведите его и переопределите некоторые методы:
struct derived: public base {
static void talk() { std::cout << "goodbye" << std::endl; }
};
И теперь вызовите методы через класс признаков:
template < class T >
struct talker_traits {
static void talk() { T::talk(); }
static void shout() { T::shout(); }
};
talker_traits<base>::talk() // prints "hello"
talker_traits<base>::shout() // prints "HELLO !!"
talker_traits<derived>::talk() // prints "goodbye"
talker_traits<derived>::shout() // prints "HELLO !!"
демонстрация ideone
Класс признаков позволяет повторно использовать статический метод base::shout
, а "переопределять" base::talk
с помощью derived::talk
. Тем не менее, существует несколько отличий от фактического наследования:
- Функция вызова разрешается во время компиляции
- Детский метод не должен иметь такую же подпись, что и родительский
Он работает со статическими полями и typedefs, лучший пример - std:: iterator_traits.
Ответ 3
У вас здесь немного конфликта в вашем вопросе. Когда вы передаете &TimerEvent::TimerHandler
в библиотеку C, вы делаете именно это. Вы также могли бы пройти &DerivedTimerEvent::TimerHandler
, если хотите. Но вы не можете пройти &TimerEvent::TimerHandler
и ожидать, что библиотека C (!), Чтобы понять, что вы на самом деле означали &DerivedTimerEvent::TimerHandler
.