Какой механизм C++ делает невозможным объявление статической функции-члена виртуальной?
Статическая функция-член не может быть виртуальной, потому что она вызывается без объекта и не получает скрытый указатель this. Виртуальный вызов, напротив, выбирает реализацию с учётом динамического типа конкретного объекта.
Виртуальные функции появились как механизм поддержки динамического полиморфизма: код работает через интерфейс базового класса, а реализация выбирается по фактическому типу объекта. Для этого объект обычно содержит служебную информацию о виртуальных функциях, а вызов использует ссылку или указатель на объект.
Статические функции-члены решают другую задачу: объединяют функцию с областью видимости класса, но не связывают её с экземпляром. Такой функции не нужен объект, состояние объекта или его динамический тип.
Если функция вызывается через базовый указатель или ссылку, виртуальный механизм должен определить, какой объект фактически стоит за этим обращением. У статической функции объекта нет: вызов разрешается по имени класса или по статическому типу выражения.
Попытка совместить эти свойства разрушила бы саму модель вызова: функция одновременно должна была бы не зависеть от объекта и выбирать реализацию по динамическому типу объекта. Поэтому язык запрещает объявлять статическую функцию виртуальной.
У нестатической виртуальной функции есть скрытый параметр this. При обращении через указатель или ссылку на базовый класс этот объект позволяет механизму виртуального вызова использовать динамический тип и выбрать переопределение производного класса.
У статической функции скрытого this нет. Она не может напрямую обращаться к нестатическим членам и не участвует в динамическом полиморфизме.
Вызов p->run() виртуальный: фактический объект имеет тип Derived, поэтому выбирается Derived::run. Вызов p->reset() не виртуальный: статическая функция разрешается по статическому типу p, то есть вызывается Base::reset; переопределения статических функций не существует.
Производный класс может объявить статическую функцию с тем же именем. Это не переопределение, а скрытие имени или отдельная функция, которая может скрывать одноимённую функцию базового класса. Для выбора нужной реализации применяют квалифицированное имя, например вызов через Base::reset().
Практический компромисс прост: если поведение должно зависеть от динамического типа объекта, используйте нестатическую виртуальную функцию. Если объект и его состояние не нужны, статическая функция уместна, но полиморфно переопределить её нельзя.
В обработчике событий хранился указатель на базовый класс Handler. Разработчик сделал метод create() статическим, рассчитывая, что при вызове через Handler* будет создан объект конкретного производного обработчика.
Возможны два варианта. Статическая функция проста и не требует экземпляра, но всегда выбирается по статическому типу и не поддерживает полиморфизм. Нестатическая виртуальная фабричная функция поддерживает выбор по динамическому типу, однако требует существующего объекта и обычно должна учитывать его состояние или контекст.
В данном случае выбран отдельный внешний фабричный компонент, которому явно передают тип или идентификатор обработчика. Это не маскирует статическую функцию под виртуальную, делает выбор реализации явным и позволяет создавать объекты без искусственного базового экземпляра.
Да, синтаксически это допустимо, если функция доступна. Однако объект при этом не превращает вызов в виртуальный: статическая функция всё равно не получает this, а выбор реализации не зависит от динамического типа объекта. Такой синтаксис часто вводит в заблуждение, поэтому предпочтительнее обращаться к статической функции через имя класса.
Нет, потому что у неё нет конкретного объекта, чьи поля нужно читать или изменять. Она может обращаться к статическим членам, глобальным объектам или к нестатическим членам через явно переданный указатель либо ссылку на объект.
Это не будет переопределением. Производная функция обычно скрывает одноимённые функции базового класса при неквалифицированном обращении; конкретную базовую реализацию можно выбрать квалифицированным именем. Виртуальная диспетчеризация в таком вызове не участвует, поскольку обе функции статические.