В целях поддержания динамического полиморфизма в языке C++ введена динамическая идентификация типа (RTTI – Run-Time Type Identification). Эта динамическая идентификация позволяет идентифицировать тип объекта при выполнении программы. Основным средством динамической идентификации типа является оператор typeid() .
С целью обеспечения лучшего приведения типов в последние версии C++ включены дополнительные операторы приведения типа. К этим операторам относятся:
- dynamic_cast ;
- const_cast ;
- reinterpret_cast ;
- static_cast .
Также язык C++ имеет стандартный оператор приведения типа, который имеет вид
(type)expression
Более подробную информацию об этом операторе приведения типа можно получить здесь .
2. Идентификация типа. Операор typeid()
Язык программирования C++ поддерживает динамический полиморфизм благодаря сочетанию наследования, виртуальных функций и использования указателя на базовый класс. В иерархии классов указатель на базовый класс может указывать на экземпляр любого класса в иерархии. Поэтому не всегда можно предположить, на объект какого класса иерархии указывает указатель. Идентификацию типа нужно производить по ходу выполнения программы.
Switch. Что это. Пример. Синтаксис. Оператор множественного выбора. Урок #13.
Для идентификации типа в языке C++ используется оператор typeid() . Этот оператор имеет две формы использования:
- typeid(object) – определение характеристик типа объекта или переменной с именем object ;
- typeid(type) – определение характеристик типа с именем type .
Оператор typeid() возвращает ссылку на объект типа type_info . Класс type_info описывает тип объекта и имеет следующие внутренние члены:
- Операторные функции
bool operator==(const type_info bool operator!=(const type_info
Эти функции перегружают операторы сравнения == и != .
const char* name();
Эта функция возвращает указатель на имя определяемого типа.
bool before(const type_info
Эта функция возвращает true , если вызывающий объект предшествует объекту, использованному в качестве параметра.
Чтобы использовать оператор typeid() , нужно подключить модуль typeinfo .
#include typeinfo>
2.1. Оператор typeid() для объекта
2.1.1. Пример использования оператора typeid() для переменных базовых типов и объектов классов
#include iostream> #include typeinfo> using namespace std; // Некоторый класс class MyClass < // . >; void main() < // Получить характеристики типа на основе объекта (экземпляра) // 1. Объявить переменные (объекты) разных типов int a, b; double x; string s; MyClass obj; // 2. Использовать ссылку на type_info для получения информации о типе // 2.1. Метод name() — получить имя типа const type_info cout «Type of x is: » // 2.2.
Сравнить типы объектов s и obj const type_info const type_info if (ti_s == ti_obj) cout «typeid(s)==typeid(obj)» else cout «typeid(s)!=typeid(obj)» // 3. Непосредственное использование typeid() без объявления ссылки // 3.1. Сравнить типы объектов a, b – использовать функцию operator==() if (typeid(a) == typeid(b)) cout «Types of a and b are equal.» else cout «Types of a and b are not equal.» // 3.2.
Перегрузка операторов пример. ООП. Перегрузка оператора присваивания. C++ Для начинающих. Урок#83
Сравнить типы переменных x и a использовать функцию operator!=() if (typeid(x) != typeid(a)) cout «Types of x and a are not equal.» else cout «Types of x and a are equal.» // 3.3. Получить данные на основании типа string tName = typeid(s).name(); cout «typeid(string) color: #333300;»>⇑
2.1.2. Пример использования оператора typeid() для объектов классов, образующих иерархию
Оператор typeid() полезен в случае когда классы образуют иерархию и в классах реализованы виртуальные функции. В нижеследующем примере объявляется базовый класс Area и два производных класса Circle и Rectangle. Все 3 класса содержат реализацию виртуальной функции GetArea(), которая возвращает разные значения площади в зависимости от выбранной фигуры.
В демонстрационных целях реализована функция Demo_ref_typeid(), которая получает ссылку на базовый класс Area. В функции вызывается оператор typeid(), который определяет тип экземпляра, передаваемого в функцию. Тип экземпляра зависит от того, какой экземпляр по иерархии классов был передан при вызове функции Demo_ref_typeid().
В функции main() демонстрируется использование оператора typeid() для объектов классов и передачу его в функцию Demo_ref_typeid().
#include iostream> #include typeinfo> using namespace std; // Применение typeid к иерархии классов // полиморфный класс Area — площадь class Area < public: virtual double GetArea() < return 0; >; // виртуальная функция >; // класс окружность class Circle :public Area < double r; public: Circle(double _r) < if (_r > 0) r = _r; else r = 1; > double GetArea() < const double pi = 3.1415; return pi * r * r; > >; // класс прямоугольник class Rectangle :public Area < double a, b; public: Rectangle(double _a, double _b) < if ((_a >= 0) (_b >= 0)) < a = _a; b = _b; >else < a = b = 0.0; >> double GetArea() < return a * b; > >; // Передача в метод ссылки на базовый класс // если класс полиморфный, то тип ссылки определяется типом параметра-объекта void Demo_ref_typeid(Area cout «The type of ref is: «; cout typeid(ref).name() void main(void) < Area* p; // указатель на базовый класс Area a; Circle c(3); Rectangle r(7, 5); // так нельзя, неинициализированное значение p // cout p = cout «Pointer p points to object of type: «; cout typeid(*p).name() // class Area p = cout «Pointer p points to object of type: «; cout typeid(*p).name() // class Circle p = cout «Pointer p points to object of type: «; cout typeid(*p).name() // class Rectangle // Важно: если забрать слово virtual в классе Area, // то выведет следующий результат: // Pointer p points to object of type: class Area // Pointer p points to object of type: class Area // Pointer p points to object of type: class Area // Демонстрация использования typeid для ссылок Demo_ref_typeid(a); // The type of ref is: class Area Demo_ref_typeid(c); // The type of ref is: class Circle Demo_ref_typeid(r); // The type of ref is: class Rectangle >
Если в вышеприведенном коде метод Demo_ref_typeid() будет получать ссылку на базовый класс, в котором не поддерживается полиморфизм (нет цепочки виртуальных функций), то будет получаться тип базового класса Area .
Реализация функции Demo_ref_typeid() получает параметр-ссылку на базовый класс Area #include typeinfo> using namespace std; // Набор классов // Базовый класс class A < // . >; // Производные классы class B : public A < // . >; class C : public B < // . >; void main(void) < // 1. Создать экземпляры классов B, C B objB; C objC; // 2. Проверка, к какому типу относится экземпляр objC if (typeid(objC) == typeid(A)) cout «objC is of type A» if (typeid(objC) == typeid(B)) cout «objC is of type B» if (typeid(objC) == typeid(C)) cout «objC is of type C» // 3. Проверка, переменная ли a целого типа int int a; if (typeid(a) == typeid(int)) cout «Variable a is of type int.» else cout «Variable a is not of type int»
Результат выполнения программы
objC is of type C Variable a is of type int.
3. Пример применения оператора typeid() для шаблонных классов
Оператор typeid() может быть применен к шаблонным классам, оперирующим некоторым обобщенным типом. Для каждого конкретного экземпляра класса формируется подходящий тип.
Ниже представлен пример использования оператора typeid() для шаблонного класса Point .
#include iostream> #include typeinfo> using namespace std; // Шаблонный класс, реализующий точку на координатной плоскости template class T> class Point < private: T x, y; public: // Конструктор Point(T _x, T _y) : x(_x), y(_y) < > // Методы доступа T X() < return x; > T Y() < return y; > >; void main(void) < // Объявить экземпляры класса Point для разных типов Pointint> objInt(8, 9); Pointdouble> objDouble(7.2, 3.1); // Вывести типы объектов objInt и objDouble cout «typeid(objInt) color: #0000ff;»>typeid(objInt).name() << endl; cout «typeid(objDouble) color: #0000ff;»>typeid(objDouble).name() // Определить, одинаковы ли типы объектов objInt и objDouble if (typeid(objInt) == typeid(objDouble)) cout «Types of objInt and objDouble are equal.» else cout «Types of objInt and objDouble are not equal.»
Результат выполнения программы
typeid(objInt) = class Point typeid(objDouble) = class Point Types of objInt and objDouble are not equal.
Связанные темы
Источник: www.bestprog.net
Оператор typeid
Оператор typeid позволяет определить тип объекта во время выполнения.
Результатом typeid является const type_info public: virtual void vvfunc() <>>; class Derived : public Base <>; using namespace std; int main() < Derived* pd = new Derived; Base* pb = pd; cout
Если выражение разыменовывает указатель и его значение равно нулю, typeid вызывает исключение bad_typeid. Если указатель не указывает на допустимый объект, __non_rtti_object создается исключение. Он указывает на попытку анализа RTTI, которая вызвала ошибку, так как объект каким-то образом является недопустимым. (Например, это неправильный указатель или код не был скомпилирован с помощью /GR.
Если выражение не является указателем и не ссылкой на базовый класс объекта, результатом type_info будет ссылка, представляющая статический тип выражения. Статический тип выражения относится к типу выражения, известному во время компиляции. Семантика исполнения игнорируется при оценке статического типа выражения. Кроме того, ссылки по возможности игнорируются при определении статического типа выражения:
// expre_typeid_Operator_2.cpp #include int main() < typeid(int) == typeid(int // evaluates to true >
typeid Также можно использовать в шаблонах для определения типа параметра шаблона:
// expre_typeid_Operator_3.cpp // compile with: /c #include template < typename T >T max( T arg1, T arg2 ) < cout arg2 ? arg1 : arg2 ); >
Источник: learn.microsoft.com
Глава 19: Динамическая идентификация типов и операторы приведения типа
В этой главе рассматриваются два средства C++, которые поддерживают современное объектно‑ориентированное программирование: динамическая идентификация типов (run‑time type identification ‑ RTTI) и набор дополнительных операторов приведения типа . Ни одно из этих средств не было частью оригинальной спецификации C++, но оба они были добавлены с целью усиления поддержки полиморфизма времени выполнения. Под RTTI понимается возможность проведения идентификации типа объекта во время выполнения программы. Рассматриваемые здесь операторы приведения типа предлагают программисту более безопасные способы выполнения этой операции. Как будет показано ниже, один из них, dynamic_cast , непосредственно связан с RTTI‑идентификацией, поэтому операторы приведения типа и RTTI имеет смысл рассматривать в одной главе.
Динамическая идентификация типов (RTTI)
С динамической идентификацией типов вы, возможно, незнакомы, поскольку это средство отсутствует в таких неполиморфных языках, как С. В неполиморфных языках попросту нет необходимости в получении информации о типе во время выполнения программы, так как тип каждого объекта известен во время компиляции (т.е. еще при написании программы). Но в таких полиморфных языках, как C++, возможны ситуации, в которых тип объекта неизвестен в период компиляции, поскольку точная природа этого объекта не будет определена до тех пор, пока программа на начнет выполняться.
Как вы знаете, C++ реализует полиморфизм посредством использования иерархии классов, виртуальных функций и указателей на базовые классы. Указатель на базовый класс можно использовать для ссылки на члены как этого базового класса, так и на члены любого объекта, выведенного из него. Следовательно, не всегда заранее известно, на объект какого типа будет ссылаться указатель на базовый класс в произвольный момент времени. Это выяснится только при выполнении программы – при использовании одного из средств динамической идентификации типов.
Для получения типа объекта во время выполнения программы используйте оператор typeid.
Чтобы получить тип объекта во время выполнения программы, используйте оператор typeid . Для этого необходимо включить в программу заголовок . Самый распространенный формат использования оператора 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 ; просмотров: 291 ; Мы поможем в написании вашей работы!
Источник: studopedia.net