Почему STD :: Future и STD :: Promise не являются окончательными?
Я удивляюсь, почему классы std::future
и std::promise
promis не помечены final
спецификатором. Деструктор не виртуален, так почему final
не был добавлен? Что было (есть) обоснование?
Ответы
Ответ 1
Посмотрите на этот надуманный (по общему признанию бессмысленный) пример с std::vector
:
template <class T>
struct Example : private std::vector<T> {
void doStuff(const T& t) { this->push_back(t); }
T retrieveStuff() { return this->operator[](0); }
};
Example<int> e;
e.doStuff(42);
std::cout << e.retrieveStuff() << "\n";
Это работает, вы не можете попасть в UB из-за того, что std::vector::~vector
не является virtual
потому что вы не можете удалить объект через указатель базового класса (здесь требуется public
наследование).
Наследование здесь - просто деталь реализации. Не рекомендуется практика, но люди, вероятно, сделали и делают это. После того, как принято решение не нарушать существующий код, сделав std::vector
или другие типы контейнеров final
, имеет смысл придерживаться этого с другими типами словаря, такими как std::promise
или std::future
.
Ответ 2
Согласно [выводу]/4:
Все типы, указанные в стандартной библиотеке C++, должны быть не финальными, если не указано иное.
И std::future
или std::promise
не исключаются.
И как уже упоминалось в комментарии, этот вопрос уже обсуждался. Имеют ли разработчики библиотек свободу добавлять окончательные к неполиморфным компонентам? ,
Решение этой проблемы заключалось в том, что она не считалась дефектом с заключением:
Если библиотека не использует ключевое слово final
в спецификации, у пользователя явно есть свобода наследования от такого класса, и, следовательно, одинаково ясно, что поставщик библиотеки не может свободно добавлять final
переопределитель или атрибут класса.
Ответ 3
Пенициллин.
Также несколько замечательных достижений в борьбе с вирусами.
Ответ 4
Отсутствие какой-либо виртуальной функции в классе не делает ее не пригодной для использования в качестве базового класса. По моему мнению, добавление virtual
функций в базовый класс является своего рода особым случаем превращения базового класса в полиморфный. Многие программисты небрежно помещают virtual
функции, особенно деструктор класса (и отмечают, что "Виртуальный деструктор необходим").
ATL, например, сильно зависит от наследования, но не имеет никаких виртуальных функций. (Базовые) классы не являются полиморфными. Большинство (если не все) классов C++/STL являются неполиморфными.
Можно нарушить правило "Предпочитать сдерживание/композицию, а не наследование" и наследовать класс в нелогичной форме (один пример, приведенный lubgr); но это выполнимо и действует. Иногда более унаследовано наследование от неполиморфного класса, а не от класса.
Классы Template/Template-meta полагаются на наследование, когда не задействованы виртуальные функции. Атрибут-наследование является одним из примеров, где класс наследовал бы от различных классов (мульти-наследование) и наследовал атрибуты.
Один очень простой пример - сделать класс non_copyable
, поместить конструктор копирования/оператор присваивания и т.д. Как приватный/защищенный; и пусть другие классы наследуют от него. Таким образом, "производный" класс унаследует не копируемую "возможность/атрибут" базового класса.