Глава 19: Динамическая идентификация типов и операторы приведения типа



 

 

В этой главе рассматриваются два средства C++, которые поддерживают современное объектно‑ориентированное программирование: динамическая идентификация типов (run‑time type identification ‑ RTTI) и набор дополнительных операторов приведения типа . Ни одно из этих средств не было частью оригинальной спецификации C++, но оба они были добавлены с целью усиления поддержки полиморфизма времени выполнения. Под RTTI понимается возможность проведения идентификации типа объекта во время выполнения программы. Рассматриваемые здесь операторы приведения типа предлагают программисту более безопасные способы выполнения этой операции. Как будет показано ниже, один из них, dynamic_cast , непосредственно связан с RTTI‑идентификацией, поэтому операторы приведения типа и RTTI имеет смысл рассматривать в одной главе.

 

Динамическая идентификация типов (RTTI)

 

С динамической идентификацией типов вы, возможно, незнакомы, поскольку это средство отсутствует в таких неполиморфных языках, как С. В неполиморфных языках попросту нет необходимости в получении информации о типе во время выполнения программы, так как тип каждого объекта известен во время компиляции (т.е. еще при написании программы). Но в таких полиморфных языках, как C++, возможны ситуации, в которых тип объекта неизвестен в период компиляции, поскольку точная природа этого объекта не будет определена до тех пор, пока программа на начнет выполняться. Как вы знаете, C++ реализует полиморфизм посредством использования иерархии классов, виртуальных функций и указателей на базовые классы. Указатель на базовый класс можно использовать для ссылки на члены как этого базового класса, так и на члены любого объекта, выведенного из него. Следовательно, не всегда заранее известно, на объект какого типа будет ссылаться указатель на базовый класс в произвольный момент времени. Это выяснится только при выполнении программы – при использовании одного из средств динамической идентификации типов.

Для получения типа объекта во время выполнения программы используйте оператор typeid.

Чтобы получить тип объекта во время выполнения программы, используйте оператор typeid . Для этого необходимо включить в программу заголовок <typeinfo> . Самый распространенный формат использования оператора typeid таков.

 

 

Здесь элемент object означает объект, тип которого нужно получить. Можно запрашивать не только встроенный тип, но и тип класса, созданного программистом. Оператор typeid возвращает ссылку на объект типа type_infо , который описывает тип объекта object .

В классе type_info определены следующие public‑члены.

 

 

Перегруженные операторы "==" и "!=" служат для сравнения типов. Функция before() возвращает значение true , если вызывающий объект в порядке сопоставления стоит перед объектом (элементом ob ), используемым в качестве параметра. (Эта функция предназначена в основном для внутреннего использования. Возвращаемое ею значение результата не имеет ничего общего с наследованием или иерархией классов.) Функция name() возвращает указатель на имя типа.

Рассмотрим простой пример использования оператора typeid .

 

 

При выполнении этой программы получены такие результаты.

 

 

Если оператор typeid применяется к указателю на полиморфный базовый класс (вспомните: полиморфный класс – это класс, который содержит хотя бы одну виртуальную функцию), он автоматически возвращает тип реального объекта, на который тот указывает: будь то объект базового класса или объект класса, выведенного из базового.

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

 

 

Вот как выглядят результаты выполнения этой программы:

 

 

Если оператор typeid применяется к указателю на базовый класс полиморфного типа, тип реально адресуемого объекта, как подтверждают эти результаты, будет определен во время выполнения программы.

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

Поскольку оператор typeid обычно применяется к разыменованному указателю (т.е. к указателю, к которому уже применен оператор "*" ), для обработки ситуации, когда этот разыменованный указатель оказывается нулевым, создано специальное исключение. В этом случае оператор typeid генерирует исключение типа bad_typeid .

Ссылки на объекты иерархии полиморфных классов работают подобно указателям. Если оператор typeid применяется к ссылке на полиморфный класс, он возвращает тип объекта, на который она реально ссылается, и это может быть объект не базового, а производного типа. Описанное средство чаще всего используется при передаче объектов функциям по ссылке. Например, в следующей программе функция WhatType() объявляет ссылочный параметр на объекты типа Base . Это значит, что функции WhatType() можно передавать ссылки на объекты типа Base или ссылки на объекты любых классов, производных от Base . Оператор typeid , примененный к такому параметру, возвратит реальный тип объекта, переданного функции.

 

 

Эта программа генерирует такие результаты.

 

 

Существует еще одна версия применения оператора typeid , которая в качестве аргумента принимает имя типа. Формат ее таков.

 

 

Например, следующая инструкция совершенно допустима.

 

 

Назначение этой версии оператора typeid – получить объект типа type_info (который описывает заданный тип данных), чтобы его можно было использовать в инструкции сравнения типов.

 

Пример RTTI‑приложения

 

В следующей программе показано, насколько полезной может быть средство динамической идентификации типов (RTTI). Здесь используется модифицированная версия иерархии классов геометрических фигур из главы 15, которая вычисляет площадь круга, треугольника и прямоугольника. В данной программе определена функция fасtorу() , предназначенная для создания экземпляра круга, треугольника или прямоугольника. Эта функция возвращает указатель на созданный объект. (Функция, которая генерирует объекты, иногда называется фабрикой объектов .) Конкретный тип создаваемого объекта определяется в результате обращения к функции rand() С++‑генератора случайных чисел. Таким образом, мы не можем знать заранее, объект какого типа будет сгенерирован. Программа создает десять объектов и подсчитывает количество созданных фигур каждого типа. Поскольку при вызове функции fасtorу() может быть сгенерирована фигура любого типа, для определения типа реально созданного объекта в программе используется оператор typeid .

 

 

Возможный результат выполнения этой программы таков.

 


Дата добавления: 2018-09-22; просмотров: 325; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!