шаблонные типы должны следовать
«концепция» (Input Iterator, Forward
Итератор и тд ...) где актуальный
детали концепции определены
полностью за счет реализации
шаблонная функция / класс, а не
класс типа, используемого с
шаблон, который является несколько
против использования ООП.
Я думаю, вы неправильно понимаете предполагаемое использование концепций шаблонами. Например, прямой итератор - это очень четкое понятие. Чтобы найти выражения, которые должны быть действительными, чтобы класс был прямым итератором, и их семантика, включая сложность вычислений, вы посмотрите на стандарт или на http://www.sgi.com/tech/stl/ForwardIterator.html (вам нужно перейти по ссылкам на ввод, вывод и Тривиальный Итератор, чтобы увидеть все это).
Этот документ является очень хорошим интерфейсом, и "реальные детали концепции" определены тут же. Они не определяются реализациями прямых итераторов и не определяются алгоритмами, использующими прямые итераторы.
Различия в том, как обрабатываются интерфейсы между STL и Java, имеют три аспекта:
1) STL определяет допустимые выражения, используя объект, тогда как Java определяет методы, которые должны вызываться на объекте. Конечно, допустимым выражением может быть вызов метода (функции-члена), но это не обязательно.
2) Java-интерфейсы являются объектами времени выполнения, тогда как концепции STL не видны во время выполнения даже с RTTI.
3) Если вы не в состоянии сделать правильными требуемые допустимые выражения для концепции STL, вы получите неопределенную ошибку компиляции при создании экземпляра какого-либо шаблона с типом. Если вам не удается реализовать требуемый метод интерфейса Java, вы получаете конкретную ошибку компиляции, говорящую так.
Эта третья часть, если вам нравится некая «типизация» (время компиляции): интерфейсы могут быть неявными. В Java интерфейсы несколько явные: класс «is» Iterable, если и только если он говорит, что он реализует Iterable. Компилятор может проверить, что все сигнатуры его методов присутствуют и являются правильными, но семантика все еще неявна (т.е. они либо документированы, либо нет, но только больше кода (модульных тестов) может сказать вам, является ли реализация правильной).
В C ++, как и в Python, семантика и синтаксис неявны, хотя в C ++ (и в Python, если вы получаете препроцессор строгой типизации) вы получаете некоторую помощь от компилятора. Если программисту требуется явное объявление интерфейсов в Java-стиле реализующим классом, тогда стандартным подходом является использование признаков типа (а множественное наследование может предотвратить это слишком многословно). По сравнению с Java не хватает одного шаблона, который я могу создать для своего типа и который будет скомпилирован тогда и только тогда, когда все необходимые выражения допустимы для моего типа. Это скажет мне, реализовал ли я все необходимые биты, «прежде чем я его использую». Это удобно, но это не ядро ООП (и оно все еще не проверяет семантику, и код для проверки семантики, естественно, также проверяет правильность рассматриваемых выражений).
STL может быть или не быть достаточно ОО на ваш вкус, но он, безусловно, четко отделяет интерфейс от реализации. Он не обладает способностью Java выполнять рефлексию над интерфейсами и по-разному сообщает о нарушениях требований к интерфейсу.
вы можете сказать функции ... ожидает Итератор Forward только
глядя на его определение, где вам нужно либо посмотреть на
реализация или документация для ...
Лично я считаю, что неявные типы являются сильной стороной при правильном использовании. Алгоритм говорит, что он делает со своими параметрами шаблона, и разработчик следит за тем, чтобы эти вещи работали: это в точности общий знаменатель того, что должны делать «интерфейсы». Кроме того, с STL вы вряд ли будете использовать, скажем, std::copy
, основываясь на поиске его прямого объявления в заголовочном файле. Программисты должны выяснить, что функция берет на основе своей документации, а не только сигнатуры функции. Это верно в C ++, Python или Java. Существуют ограничения на то, что может быть достигнуто с помощью набора текста на любом языке, и попытка использовать набор для выполнения того, чего он не делает (проверьте семантику), будет ошибкой.
Тем не менее, алгоритмы STL обычно называют свои параметры шаблона таким образом, чтобы было понятно, какая концепция требуется. Однако это делается для того, чтобы предоставить полезную дополнительную информацию в первой строке документации, а не для того, чтобы сделать предварительные декларации более информативными. Есть больше вещей, которые вы должны знать, чем могут быть включены в типы параметров, поэтому вы должны прочитать документы. (Например, в алгоритмах, которые принимают входной диапазон и выходной итератор, скорее всего, выходному итератору нужно достаточно «пространства» для определенного числа выходных данных, исходя из размера входного диапазона и, возможно, его значений. Попробуйте строго ввести это. )
Вот Бьярне о явно объявленных интерфейсах: http://www.artima.com/cppsource/cpp0xP.html
В общем случае аргумент должен быть
класс, производный от интерфейса (
C ++ эквивалентен интерфейсу
абстрактный класс), указанный в
определение родового. Это означает
что все общие типы аргументов должны
вписаться в иерархию. Это налагает
ненужные ограничения на конструкции
требует необоснованного предвидения на
часть разработчиков. Например, если
вы пишете общий, и я определяю
класс, люди не могут использовать мой класс как
аргумент вашего общего, если я не знал
об интерфейсе, который вы указали и
вывел мой класс из этого. Это
жесткие.
Если взглянуть на это с другой стороны, с помощью утки вы можете реализовать интерфейс, не зная, что интерфейс существует. Или кто-то может написать интерфейс намеренно, чтобы ваш класс реализовал его, проконсультировавшись с вашими документами, чтобы убедиться, что они не просят ничего, чего вы еще не делали. Это гибко.