Почему 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, поместить конструктор копирования/оператор присваивания и т.д. Как приватный/защищенный; и пусть другие классы наследуют от него. Таким образом, "производный" класс унаследует не копируемую "возможность/атрибут" базового класса.