|
Программирование >> Полиморфизм без виртуальных функций в с++
воспользоваться dbp else { dynamic cast возвращает такой указатель лишь тогда, когда объект, иа который направлен исходный указатель, действ1ггельно принадлежит специфицированному производному классу. В иротивно.м случае он возвращает 0; □ оператор typeid для идентификации точного типа объекта при наличии указателя на базовый класс; □ структура type inf о, позволяющая получить дополнительную информацию, ассоциированную с типом. При обсуждении RTTI внимание будет уделено преимупюственно указателям. 14.2.1. Зачем нужен механизм RTTI Допустим, в библиотеке имеется класс dialog box, иптерфейсы которого выражены в терминах объектов этого класса. Я же пользуюсь как dialog box, так и собственным классом dbox w str. class dialog box : public window { библиотечный класс . . . public: virtual int askO ; ... class dbox w str : public dialog box { мой класс . . . public: int ask(); virtual char* get string(); . . . Когда библиотека или система возврашает .мне указатель на dialog box, как я могу узнать, принадлежит ли на самом деле моему классу dbox w str? Замечу, что я не могу модифи пировать библиотеку, чтобы ввести в dbox w s t г идентифицирующие признаки. А даже если бы .мог, то не ста.,1 бы, чтобы не думать об этом классе в последующих версиях и об ошибках, которые я те.м самым мог внести в стандартную библиотеку. 14.2.2. Оператор dynamic ca5t Наивное решение - найти тип объекта, на который имеется указатель, и сравнить его с типом класса dbox w str: void my fct(dialog box* bp) if (typeid(*bp) == typeid(dbox w str)) { наивное решение dbox w str* dbp = (dbox w str*)bp; Оператор typeid {), которому в качестве операнда передано имя типа, возвращает объект, идентифицирующий этот тип. Если операндом является выражение, typeid {) возвращает объект, который идентифицирует тип объекта, обозначаемого этим выраже1Н1ем. В частности, typeid {*Ьр) возвращает объект, позволяющий програм.мисту задавать вопросы о типе объекта, на который указывает bp. В данном случае нас интересует только, совпадает ли тип этого объекта с типом dbox w s t г. Это простейший из вопросов, которые можно задать, но, как правило, он некорректен. Спрашиваем-то мы, чтобы узнать, можно ли безопасно воспользоваться той или иной воз.можностью производного класса. А чтобы применить ее, нам нужен указатель на объект этого производного класса. В примере выше мы использовали приведение типа в строке, следующей за проверкой. Но ведь обычно нас интересует, удастся ли безопасно выполнить приведение. Этот запрос можно дать непосредственно, воспользовавшись операторо.м dynamic cast: void my fct(dialog box* bp) { if (dbox w str* dbp = dynamic cast<dbox w str*>(bp)) { воспользоваться dbp else { работать с *bp, как с обычным диалоговым окном Оператор dynamic cast<T*> (р) преобразует свой операнд в нужный тип Т*, если *р действительно принадлежит пшу т или типу класса, производного от Т. В противном случае значение dynamic cast<T*> (р) равно 0. Есть несколько причин для объединения проверки и приведения типа в одну операцию: □ динамическое приведение не допускает несоответствия между приведением и проверкой; □ пользуясь данными, которые содержатся в объектах с информацией о типе, можно выполнять приведение к типам, которые не полностью определены в области действия проверки; □ при тако.м же условии допустимо выполнять приведение от виртуального базового класса к производному (см. раздел 14.2.2.3); □ статическое приведение типов не дает правильных результатов во всех случаях (см. раздел 14.3.2.1). В большинстве ситуаций можно обойтись оператором dynamic cast. Думается, что это важнейшая часть механизма RTTI и именно на нее пользователи должны обратить особое внимание. работать с *Ьр, как с обычным диалоговым окном Оператор dynamic cast можно использовать и для приведения к ссылочным типам. Если приведение к типу ссылки заканчивается неудачно, возникает исключение bad cast. Напри.мер: void my fct(dialog box& b) { dbox w str& db = dynamic cast<dbox w str&>(b); воспользоваться db Я пользуюсь приведением к ссылке, когда хочу проверить предположение о ее типе и считаю, что ошибочное предположение - это сбой в программе. Если же нужно выбрать один из нескольких возможных вариантов, то использую приведение к указателю и проверяю результат. Не помню, когда я пришел к выводу, что приведение с проверкой типа - лучший способ идентификации типа во время исполнения, коль скоро в языке есть явная поддержка этого. Данную идею .мне подал кто-то из специалистов ко.мпании Xerox PARC. Предложение заключалось в то.м, чтобы обычные приведения выполняли проверку. Как отмечается в разделе 14.2.2.1, этот вариант сопровождался большими затратами и проблемами с совместимостью, но я осознал, что слегка отличный синтаксис приведения может свести к минимуму неправильное использование, к которому располагает механизм переключения по типу вроде предложения INSPECT в Simula. 14.2.2.1. Синтаксис Спор о том, как должен выглядеть оператор dynamic cast, имел синтаксические аспекты. Приведения типов в наибольшей степени провоцируют ошибки при программировании на языке С++. И синтаксически они принадлежат к числу наиболее неудачных особенностей. Естественно, по мере возможности я хотел: □ устранить приведения вообще; □ сделать их безопасными; □ предложить такой синтаксис приведений, который с очевидностью показывал бы, что используется небезопасная информация; □ предложить альтернативы приведению типов, чтобы не возникало желания прибегать к ним. Вывод о том, что 3-е и 4-е сочетания реализуемы, а 1-е и 2-е - нет, отражает dynamic cast. Рассматривая первое сочетание, мы отметили, что ни в каком языке, поддерживающем системное программирование, нельзя полностью отказаться от приведения типов. Определенные его формы нужны даже для эффективной поддержки численных расчетов. Поэтому следовало лишь постараться минимизировать употребление приведений и по возможности безопасно определить их поведение. Исходя из этой предпосылки, мы с Ленковым разработали предложение, в котором унифицировались динамические и статические приведения с использованием
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |