Вы не должны наследовать от std :: vector

Ну, Josh Bloch сказал себя в Эффективный Java, 2-й :

Предпочитают интерфейсы по абстрактным классам

Некоторые основные моменты:

  • Существующие классы могут быть легко модифицированы для реализации нового интерфейса . Все, что необходимо сделать, добавляют требуемые методы, если они don’t уже существуют и добавляют пункт реализаций к объявлению класса.

  • Интерфейсы идеальны для определения mixins. Свободно говоря, смешивание является типом, который класс может реализовать в дополнение к его “primary type”, чтобы объявить, что это обеспечивает некоторое дополнительное поведение. Например, Сопоставимый смесительный интерфейс, который позволяет классу объявлять, что его экземпляры заказаны относительно других взаимно сопоставимых объектов.

  • Интерфейсы позволяют конструкцию неиерархических платформ типа . Иерархии типа являются большими для организации некоторых вещей, но другие вещи don’t аккуратно попадают в твердую иерархию.

  • Интерфейсы включают безопасные, мощные улучшения функциональности через обертку - на идиому класса. При использовании абстрактных классов для определения типов, Вы оставляете программиста, который хочет добавить функциональность без альтернативы, но использовать наследование.

, Кроме того, можно объединить достоинства интерфейсов и абстрактных классов путем обеспечения абстрактного скелетного класса реализации для движения с каждым нетривиальным интерфейсом, который Вы экспортируете.

, С другой стороны, интерфейсы очень трудно развить. Если Вы добавите метод к интерфейсу, то это повредит весь, его - реализации.

пз.: Купите книгу. Это намного более подробно.

182
задан Armen Tsirunyan 27 April 2012 в 22:11
поделиться

1 ответ

Этот вопрос, как гарантируют, произведет затаившее дыхание сжатие жемчуга, но на самом деле нет никакой защитимой причины предотвращения, или "излишне умножающихся объектов" для предотвращения, деривация из Стандартного контейнера. Самое простое, самое короткое выражение является самым четким, и лучше всего.

действительно необходимо проявить всю обычную заботу вокруг любого производного типа, но нет ничего специального о случае основы из Стандарта. Переопределение основной функции членства могло быть хитрым, но это будет неблагоразумно, чтобы сделать с любой невиртуальной основой, таким образом, не будет большого количества специального предложения здесь. Если бы необходимо было добавить элемент данных, то необходимо было бы волноваться о разрезании, если бы участник должен был быть сохранен согласовывающимся с содержанием основы, но снова который является тем же для любой основы.

место, где я нашел получение из стандартного контейнера особенно полезным, состоит в том, чтобы добавить единственного конструктора, который делает точно необходимую инициализацию без шанса беспорядка или угона другими конструкторами. (Я смотрю на Вас, initialization_list конструкторы!) Затем можно ли свободно использовать полученный объект, нарезанный - передают его в отношении чего-то, ожидая основу, перемещаются от него до экземпляра основы, что имеет Вас. Нет никаких пограничных случаев для волнения о, если это не побеспокоило бы Вас для привязки аргумента шаблона с производным классом.

А помещают, где эта техника будет сразу полезна в C++ 20, резервирование. Где мы, возможно, записали

  std::vector<T> names; names.reserve(1000);

, мы можем сказать

  template<typename C> 
  struct reserve_in : C { 
    reserve_in(std::size_t n) { this->reserve(n); }
  };

и затем иметь, как раз когда участники класса,

  . . .
  reserve_in<std::vector<T>> taken_names{1000};  // 1
  std::vector<T> given_names{reserve_in<std::vector<T>>{1000}}; // 2
  . . .

(согласно предпочтению) и не должны записать конструктору только для вызова резерва () на них.

(Причина, что reserve_in, технически, потребности ожидать C++ 20 состоят в том, что предшествующие Стандарты не требуют, чтобы способность пустого вектора была сохранена через перемещения. Это подтверждается как контроль и, как могут обоснованно ожидать, будет зафиксировано как дефект как раз к '20. Мы можем также ожидать, что фиксация будет, эффективно, проведена задним числом к предыдущим Стандартам, потому что все существующие реализации на самом деле сохраняют способность через перемещения; Стандарты просто не потребовали его. Нетерпеливое может безопасно забежать вперед - резервирование является почти всегда просто оптимизацией так или иначе.)

Некоторые утверждали бы, что случай reserve_in лучше подается бесплатным шаблоном функции:

  template<typename C> 
  auto reserve_in(std::size_t n) { C c; c.reserve(n); return c; }

Такая альтернатива, конечно, жизнеспособна - и могла даже, время от времени, быть бесконечно мало быстрее, из-за *RVO. Но выбор деривации или бесплатной функции должен быть сделан на ее собственных достоинствах, а не от необоснованного (heh!) суеверие о получении из Стандартных компонентов. В использовании в качестве примера выше, только вторая форма работала бы с бесплатной функцией; хотя за пределами контекста класса это могло быть записано немного более кратко:

  auto given_names{reserve_in<std::vector<T>>(1000)}; // 2
0
ответ дан 23 November 2019 в 06:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: