|
Программирование >> Полиморфизм без виртуальных функций в с++
dynamic cast, который выполняет приведения только тогда, когда ответ положительный. Иными словами, хотелось бы и.меть возможность писать такой код: void my fct(dialog box* bbp) { if (dbp->isKindOf(dbox w str)) ( dbox w str* dbsp = {dbox w str*)dbp; воспользоваться dbsp else { считать, что *dbp - это обычное диалоговое окно К сожалению, в ряде случаев приведение не дает правильного результата (см. раздел 14.3.2.1). Это пример того, как трудно бывает и.мпортировать концепции из других языков. В Smalltalk есть оператор isKindOf для опроса типа, но данный язык не нуждается в дальнейшем приведении. Однако пря.мой перенос isKindOf в С-и-привсл бы как к техническим, так и к стилистическим трудностям. В действительности именно аргу.менты стилистического характера заставили .меня отдать нредпочтепис какой-то форме условного приведения типа, и только позже я обнаружил некоторые технические доводы против оператора опроса типа наподобие isKindOf. Таким образом, разделение проверки и преобразования типа излишне .многословно и оставляет возможность рассогласования между ре-зультата.ми того и другого. 14.2.8.3. Упорядоченность типов Было предложение определить для объектов type info операторы <, <= и т.д., чтобы выразить отношение порядка в иерархии классов. Это несложно, но СЛИП1К0.М мудрено. Кроме того, здесь есть те же проблемы с явными операциями сравнения типов, что и описанные в 14.2.8.2. Нам в любом случае нужно приведение, так лучше уж воспользоваться dynamic cast. 14.2.8.4. Мультиметоды Более привлекательно выглядит применение RTTI для поддержки так называемых мультиметодов, то есть возможности вызывать виртуальную функцию на базе более чем одного объекта. Такое средство стало бы подарком для программистов, ПИП1УШИХ код, с помошью которого осушествляются бинарные операции над различными объектами (см. раздел 13.8). Очевидно, объекты type inf о могли бы хранить необходимую для этого информацию. К то.му же мультиметоды становятся, скорей всего, последующим расширением, а не альтернативой принятому подходу. Однако предложение не было внесено, поскольку я не мог отчетливо представить все последствия такого изменения и не хотел предлагать новое крупное расширение, не имея опыта его применения в контексте C+-I-. 14.2.8.5. Методы без ограничений Имея RTTI, удастся поддержать методы без ограничений (unconstrained methods), то есть в объекте type inf о для некоторого класса можно хранить достаточно информации, чтобы во время исполнения проверить, поддерживается в нем данная функция или нет. Так можно было реализовать проверяемые во время исполнения вызовы функций в духе Smalltalk. Однако такое расширение противоречило стремлеиию способствовать эффективному и безопасному с точки зрения типов программированию. Динамическое приведение позволяет сначала проверить, а потом вызвать функцию if (D* pd = dynaii\ic cast<D*>(pb)) { *pb принадлежит типу D? pd->dfct(); вызвать функцию из D .. . вместо того чтобы сначала вызвать, а потом проверить, что получилось (как в языке Smalltalk); pb->dfct(); в надежде, что pb указывает на что-то, имеющее dfct; если это не так, обработать неудачный вызов где-то в другом месте Первая стратегия в большей степени опирается на статическую проверку типов (уже на этапе компиляции известно, что для класса D определена функция dfct), позволяет обойтись без лишних затрат при подавляюшем большинстве вызовов, не нуждающихся в проверке, и содержит визуальное указание на то, что происходит нечто неординарное. 14.2.8.6. Контролируемая инициализация Мы также думали, что стоит контролировать присваивание и инициализацию ггадобно тому, как это делается в языках Beta и Eiffel, например: void f(B* pb) ( D* pdl = pb; ошибка: несоответствие типов D* pd2 ?= pb; правильно, проверка того, что *pb принадлежит классу D, производится во время исполнения pdl = pb; ошибка: несоответствие типов pd2 ?= pb; правильно, проверка того, что *рЬ принадлежит классу D, производится во время исполнения Однако я решил, что в реальном коде отыскать символ ? будет слишком сложно, а вся конструкция провоцирует ошибки, так как после нее будут забывать проверять результат. Кроме того, иногда применение данной конструкции сопряжено с введением именованной переменной, предназначенной только для этой цели. Альтернатива - разрешить использование ?= только в условиях - выглядела очень привлекательно: void f(B* pb) { D* pdl ?= pb; ошибка: нет проверки условная инициализация if (D* pd2 ?= pb) { правильно: есть проверка условная инициализация . . . Однако пришлось бы отличать случай, когда при ошибке возбуждается исключение, от случая, когда возвращается 0. Кроме того, оператор ?= не так неудачен, как приведения типов, поэтому провоцирует на неправильное употребление. Разрешив объявления в условиях (см. ра.здел 3.11.5.2), я сделал возможным использование dynamic cast в стиле этой альтернативы: void f(B *pb) { if (D* pd2 = dynamic cast<D*>(pb)) { правильно: контролируется ... 14.3. Новая нотация для приведения типов Синтаксически и семантически приведения типов - одна из самых неудачных особенностей С и С++. Поэтому поиск других вариантов не прекращался. Неявные преобразования аргументов в объявлениях функций (см. раздел 2.6), шаблоны (см. раздел 14.2.3) и ослабление правил перегрузки для виртуальных функций (см. раздел 13.7) - все это позволяет устранить некоторые виды приведений. С другой стороны, оператор dynamic cast (см. раздел 14.2.2) в отдельных случаях - более безопасная альтернатива старым приведениям. Он и натолкнул на мысль пойти по другому пути - вычленить логически различные применения приведений типов и поддержать их с помощью операторов, похожих на dynamic cast: static cast<T>(е) хорошие приведения типов reinterpret cast<T>(е) приведения, даюшие значения, которые для / / безопасного использования нужно привести к исходному типу const cast<T>(е) отбрасывание const В данном разделе анализируются проблемы, свойственные старым приведениям типов, и описывается синтез нового средства. Во многом определения операторов появились в процессе бурных споров среди членов рабочей группы по расширениям. Особенно конструктивные предложения внесли Дэг Брюк, Джер ри Шварц и Эндрю Кениг. Новые операторы приведения были одобрены па заседании комитета в Сан-Хосе в ноябре 1993 г.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |