Почему STD :: Future и STD :: Promise не являются окончательными? - PullRequest
14 голосов
/ 17 апреля 2019

Я понимаю, почему классы std::future и std::promise не помечены спецификатором final. Деструктор является , а не виртуальным, так почему же final не был добавлен? Что было (есть) обоснование?

Ответы [ 3 ]

19 голосов
/ 17 апреля 2019

Посмотрите на этот надуманный (по общему признанию бессмысленный) пример с 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.

16 голосов
/ 17 апреля 2019

Согласно [деривация] / 4 :

Все типы, указанные в стандартной библиотеке C ++, должны быть не финальными типами , если не указано иное.

И std::future или std::promise не исключаются.

И, как уже упоминалось в комментарии, этот вопрос уже обсуждался ранее. Имеют ли разработчики библиотеки свободу добавлять final к неполиморфным компонентам? .

Решение этой проблемы заключалось в том, что она не считалась дефектом с заключением:

Если библиотека не использует ключевое слово final в спецификации, у пользователя явно есть свобода поставщик библиотеки не может свободно добавлять final переопределитель или атрибут класса.

.
0 голосов
/ 18 апреля 2019

Отсутствие какой-либо виртуальной функции в классе не делает ее не пригодной для использования в качестве базового класса.По моему мнению, добавление virtual функций к базовому классу является своего рода особенным случаем превращения базового класса в полиморфный.Многие программисты небрежно помещают virtual в функции, и особенно в деструктор класса (и отмечают, что «Виртуальный деструктор необходим» ).

ATL, например, сильно зависит от наследования, но не имеет никаких виртуальных функций.(Базовые) классы не являются полиморфными.Большинство (если не все) классов C ++ / STL являются неполиморфными.

Можно нарушить правило «Предпочитать сдерживание / составление над наследованием» и наследовать класс в нелогичной форме (приведен один примерпо lubgr);но это выполнимо и действует.Иногда более уместно наследовать от неполиморфного класса, а не содержать класс.

Классы Template / Template-meta полагаются на наследование, когда не задействованы никакие виртуальные функции.Атрибут-наследование является одним из примеров, где класс наследовал бы от различных классов (мульти-наследование) и наследовал атрибуты.

Один очень простой пример - сделать класс non_copyable, поместить конструктор копирования / оператор присваивания и т. Д. Как private / protected;и пусть другие классы наследуют от него.Таким образом, «производный» класс унаследует не копируемые «возможности / атрибут» базового класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...