Я готовлюсь к экзамену, и у меня есть вопрос, на который я стараюсь дать ответ.
Почему не существует базового класса итераторов, от которого наследуются все остальные итераторы?
Полагаю, мой учитель ссылается на иерархическую структуру из ссылки на cpp " http://prntscr.com/mgj542 ", и мы должны предоставить другую причину, чем почему они должны это делать?
Я знаю, что итераторы (вроде) и что они используются для работы с контейнерами. Из того, что я понимаю, из-за разных возможных базовых структур данных, разные контейнеры имеют разные итераторы, потому что вы можете, например, получить произвольный доступ к массиву, но не к связанному списку, а разные контейнеры требуют разных способов перемещения по ним.
Вероятно, это специализированные шаблоны в зависимости от контейнера, верно?
Ответы:
Вы уже получили ответы, указывающие на то, почему не нужно, чтобы все итераторы наследовали от одного базового класса Iterator. Я получил немного дальше, хотя. Одной из целей C ++ является абстракция с нулевыми затратами времени выполнения.
Если итераторы работают на всех из них, наследуя общий базовый класс, и используют виртуальные функции в базовом классе для определения интерфейса, а производные классы предоставляют реализации этих виртуальных функций, то это может (и часто может) существенно увеличить время выполнения. накладные расходы на операции.
Давайте рассмотрим, например, простую иерархию итераторов, которая использует наследование и виртуальные функции:
Тогда давайте проведем быстрый тест:
[примечание: в зависимости от вашего компилятора вам может потребоваться сделать немного больше, например, определить iterator_category, diff__type, reference и т. д., чтобы компилятор принял итератор.]
И вывод:
[Конечно, если вы запустите код, ваши результаты не будут точно соответствовать.]
Таким образом, даже для этого простого случая (и выполняющего только около 80 приращений и сравнений) мы добавили около 60% накладных расходов к простому линейному поиску. Особенно, когда итераторы были первоначально добавлены в C ++, довольно много людей просто не приняли бы дизайн с такими большими накладными расходами. Они, вероятно, не были бы стандартизированы, и даже если бы они были, практически никто не использовал бы их.
источник
Разница между тем, что что-то есть, и тем, как что-то ведет себя.
Многие языки пытаются объединить эти два понятия, но это совершенно разные вещи.
Если как и что и как ...
Если все наследуется,
object
тогда получаются некоторые преимущества, такие как: любая переменная объекта может содержать любое значение. Но это также проблема, все должно вести себя ( как ) какobject
и и похоже ( что )object
.Но:
Либо
object
тип становится по существу бесполезным - из-за объекта, не обеспечивающего общности во всех возможных экземплярах. Или же будут существовать объекты, у которых есть сломанное / подкаблучное / абсурдное определение некоторого предполагаемого универсального свойства, найденного на основе,object
которое обеспечивает почти универсальное поведение, за исключением ряда уловок.Если что не связано с тем, как
В качестве альтернативы вы можете оставить раздел « Что и как» . Тогда несколько различных типов (с ничего общего у всех , что ) все это может вести себя таким же образом , как видно из соавтора Хау . В этом смысле идея
Iterator
не является чем-то конкретным , а как . В частности, как вы взаимодействуете с вещами, когда вы еще не знаете, с чем взаимодействуете.Java (и аналогичные) позволяют подходить к этому с помощью интерфейсов. Интерфейс в этом отношении описывает средства связи и, неявно, протокол связи и действий, которые соблюдаются. Любое То, что заявляет о себе как о данном Как , заявляет, что оно поддерживает соответствующие коммуникации и действия, изложенные в протоколе. Это позволяет любому Соавтор полагаться на Хау и не увязнуть, указав , какие именно Какие «s могут быть использованы.
C ++ (и аналогичные) позволяют подходить к этому посредством утки. Шаблону не важно, объявляет ли сотрудничающий тип, что он следует поведению, только в пределах данного контекста компиляции, с которым объект может взаимодействовать определенным образом. Это позволяет указателям C ++ и объектам, перекрывающим определенные операторы, использоваться одним и тем же кодом. Потому что они соответствуют контрольному списку, чтобы считаться эквивалентным.
Базовый тип даже не должен выполнять итерации контейнера, это может быть что угодно . Кроме того, это позволяет некоторым соавторам быть еще более универсальными, представьте, что функция нуждается только в ней
a++
, итератор может удовлетворить это, как и указатель, так и целое число, так же как и любой объект, реализующийoperator++
.Под и над спецификацией
Проблема с обоими подходами находится под и над спецификацией.
Использование интерфейса требует, чтобы объект объявил, что поддерживает заданное поведение, что также означает, что создатель должен наполнить его с самого начала. Это приводит к некоторому Что «S , чтобы не делать разрез, так как они не объявляли его. Это также означает , что когда - нибудь , что имеет общий предок, интерфейс , представляющий Хау . Это круг назад к первоначальной проблеме
object
. Это заставляет соавторов переопределять свои требования, одновременно вызывая невозможность использования некоторых объектов из-за отсутствия объявлений или скрытых ошибок, так как ожидаемое поведение плохо определено.Использование шаблона требует, чтобы соавтор работал с совершенно неизвестным « Что» , и через свои взаимодействия он определяет « Как» . В некоторой степени это усложняет написание коллабораторов, так как он должен анализировать What для своих примитивов связи (функции / поля / и т. Д.), Избегая при этом ошибок компиляции, или, по крайней мере, указывать, как данное What не соответствует его требованиям для How . Это позволяет коллаборационисту требовать абсолютного минимума от любого заданного « Что» , что позволяет широчайший диапазон того, что должно быть использовано. К сожалению, у этого есть недостаток, позволяющий бессмысленное использование объектов, которые технически предоставляют коммуникационные примитивы для данногоКак , но не следуйте подразумеваемому протоколу, позволяющему совершать всевозможные плохие вещи.
итераторы
В этом случае
Iterator
является Как это сокращение для описания взаимодействия. Все, что соответствует этому описанию, по определениюIterator
. Знание как позволяет нам писать общие алгоритмы и иметь короткий список « как дано конкретное что », которые необходимо предоставить, чтобы заставить алгоритм работать. Этим списком являются функция / свойства / и т. Д., Их реализация учитывает конкретные аспекты алгоритма.источник
Потому что C ++ не должен иметь (абстрактных) базовых классов для полиморфизма. Он имеет структурный подтип, а также номинативный подтип .
Сбивает с толку в конкретном случае итераторов, предыдущие стандарты определены
std::iterator
как (приблизительно)Т.е. как просто поставщик необходимых типов членов. Это не имело никакого поведения во время выполнения, и было объявлено устаревшим в C ++ 17
Обратите внимание, что даже это не может быть общей основой, так как шаблон класса не является классом, каждое создание является отдельным от других.
источник
Одна из причин заключается в том, что итераторы не обязательно должны быть экземплярами класса. Например, во многих случаях указатели являются очень хорошими итераторами, и, поскольку они являются примитивами, они не могут наследовать ни от чего.
источник