Механизм RTTI (run-time type identification)

Страницы работы

Содержание работы

..1 Механизм RTTI (run-time type identification)

..1.1 static_cast и указатели

Неявное приведение указателя на объект производного типа к указателю на объект базового типа компилятор прекрасно выполняет сам, так как производный класс содержит полные определения своих базовых классов => такое повышающее (upcast) приведение типа всегда безопасно!

B b;

A* pA = &b;

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

Для приведения указателя на базовый тип к указателю производного типа предназначен оператор явного приведения типа static_cast – это механизм времени компиляции!

//A и B связаны наследованием

class A{

};

class B:public A{

};

// С – «автономный» класс

class С{

};

void F(A* pA)

{

B* pB = static_cast<B*>(pA);//с точки зрения компилятора все корректно, так как классы связаны наследованием!

}

void main()

{

B b;

     F(&b);//компилятор преобразует адрес B* к A* - это всегда корректно

//Но!

D d;

//   F(&d);    //ошибка компилятора – такого преобразования нет!

//Но!

A a;

F(&a);    //ошибки компилятора нет, но результат некорректный, так как на самом деле объект A, а не B!

}

Замечание: компилятор проверяет только тот факт, что оба класса связаны с помощью наследования => считает такое приведение корректным. А на самом деле такое преобразование небезопасно! Поэтому возникла необходимость в способе проверки возможности такого преобразования.

Замечание: static_cast обычно используется для неполиморфных типов (нет виртуальных функций).

..1.2  Динамическая идентификация типа

Замечание: хотя мы будем обсуждать RTTI применительно к указателям, те же аспекты применимы и к ссылкам.

RTTI характеризуется тремя понятиями:

1)  оператор dynamic_cast – для преобразования полиморфных типов

2)  оператор typeid – для определения точного (exact) типа объекта

3)  класс type_info – (это то, что возвращает оператор typeid)

..1.3 Для подключения RTTI:

1)  в опциях проекта Project\Properties\C/C++\Language – включить Enable Run-Time Type info (или /GR)

2)  #include <typeinfo>

3)  механизм работает только для полиморфных классов (то есть задействованы таблицы виртуальных функций)

..1.4 Оператор typeid и класс type_info Мейерс2 – стр132

Идентификация типов во время выполнения позволяет получить информацию об объектах и классах. При этом для хранения запрашиваемой информации должна быть отведена область памяти.

Логично:

1)  сколько бы объектов класса X мы не создавали, достаточно хранить информацию собственно о типе X в единственном экземпляре в каждом классе => для каждого класса компилятор создает структуру данных типа type_info

2)  должен существовать способ получения этой информации для каждого объекта => доступ к объекту type_info можно получить при помощи оператора typeid.

3)  Что существует в единственном экземпляре для всех объектов? – static или таблица виртуальных функций. В спецификации языка сказано, что получение этой информации гарантируется только для полиморфных типов (то есть если есть хотя бы одна виртуальная функция). Данные RTTI выполняют примерно ту же задачу, что и таблица виртуальных функций => RTTI была разработана именно с помощью виртуальной таблицы класса. Например индекс 0 в таблице может содержать указатель на объект type_info:

При такой реализации память будет тратиться только на добавление еще одной ячейки в каждую таблицу виртуальных функций + выделение памяти для хранения объекта type_info для каждого класса.

..1.4.1 Формат type_info

class type_info {

public:

virtual ~type_info();

   int operator==(const type_info& rhs) const;

   int operator!=(const type_info& rhs) const;

int before(const type_info& rhs) const;

   const char* name() const;     //имя, котороедалпрограммист (human-readable)

   const char* raw_name() const; //декорированноеимя

private:

...

};

Основные возможности: 1) перегружены операторы == и !=.

2) + методы для получения имени класса.

..1.4.2 Формы оператора typeid:

const type_info& typeid(объект)  //где в качестве объекта может выступать выражение, например (*P)

const type_info& typeid(тип)

Похожие материалы

Информация о работе