Я проигнорирую производительность и стоимость памяти, потому что у меня нет возможности измерить их для «общего» случая...
Классы с виртуальными функциями-членами не являются POD. Итак, если вы хотите использовать свой класс в низкоуровневом коде, который полагается на то, что он является POD, то (помимо других ограничений) любые функции-члены должны быть невиртуальными.
Примеры вещей, которые вы можете переносимо делать с экземпляром класса POD:
- скопируйте его с помощью memcpy (при условии, что целевой адрес имеет достаточное выравнивание).
- поля доступа с помощью offsetof()
- в общем, рассматривайте это как последовательность char
- ... um
- вот об этом. Я уверен, что я что-то забыл.
Другие вещи, которые люди упомянули, с которыми я согласен:
Многие классы не предназначены для наследования. Делать их методы виртуальными было бы заблуждением, поскольку это означает, что дочерние классы могут захотеть переопределить метод, а дочерних классов быть не должно.
Многие методы не предназначены для переопределения: то же самое.
Кроме того, даже когда вещи предназначены для подкласса/переопределения, они не обязательно предназначены для полиморфизма во время выполнения. Очень редко, несмотря на то, что говорит лучшая практика ООП, вам нужно наследование для повторного использования кода. Например, если вы используете CRTP для имитации динамической привязки. Итак, опять же, вы не хотите, чтобы ваш класс хорошо работал с полиморфизмом времени выполнения, делая его методы виртуальными, когда их никогда не следует вызывать таким образом.
Таким образом, вещи, которые предназначены для переопределения полиморфизма во время выполнения, должны быть помечены как виртуальные, а вещи, которые этого не делают, не должны. Если вы обнаружите, что почти все ваши функции-члены должны быть виртуальными, отметьте их виртуальными, если нет причин не делать этого. Если вы обнаружите, что большинство ваших функций-членов не предназначены для того, чтобы быть виртуальными, не отмечайте их как виртуальные, если для этого нет причин.
Это сложная проблема при разработке общедоступного API, потому что переключение метода с одного метода на другой является критическим изменением, поэтому вы должны сделать это правильно с первого раза. Но вы не обязательно знаете, прежде чем у вас появятся пользователи, захотят ли ваши пользователи «полиморфировать» ваши классы. Хо хм. Контейнерный подход STL, заключающийся в определении абстрактных интерфейсов и полном запрете наследования, безопасен, но иногда требует от пользователей большего набора текста.
person
Steve Jessop
schedule
15.11.2008