employee *pe = new manager;
employee& re = *pe;
if ( typeid( pe ) == typeid( employee* ) ) // enoeiii
// ?oi-oi naaeaou
/*
if ( typeid( pe ) == typeid( manager* ) ) // ei?ii
if ( typeid( pe ) == typeid( employee ) ) // ei?ii
if ( typeid( pe ) == typeid( manager ) ) // ei?ii
*/
Условие в инструкции if сравнивает результаты применения typeid к операнду, являющемуся выражением, и к операнду, являющемуся именем типа. Обратите внимание, что сравнение
typeid( pe ) == typeid( employee* )
возвращает истину. Это удивит пользователей, привыкших писать:
// вызов виртуальной функции
pe-salary();
что приводит к вызову виртуальной функции salary() из производного класса manager. Поведение typeid(pe) не подчиняется данному механизму. Это связано с тем, что pe – указатель, а для получения типа производного класса операндом typeid должен быть тип класса с виртуальными функциями. Выражение typeid(pe) возвращает тип pe, т.е. указатель на employee. Это значение совпадает со значением typeid(employee*), тогда как все остальные сравнения дают ложь.
Только при употреблении выражения *pe в качестве операнда typeid результат будет содержать тип объекта, на который указывает pe:
typeid( *pe ) == typeid( manager ) // истинно
typeid( *pe ) == typeid( employee ) // ложно
В этих сравнениях *pe – выражение типа класса, который имеет виртуальные функции, поэтому результатом применения typeid будет тип адресуемого операндом объекта manager.
Такой оператор можно использовать и со ссылками:
typeid( re ) == typeid( manager ) // истинно
typeid( re ) == typeid( employee ) // ложно
typeid( &re ) == typeid( employee* ) // истинно
typeid( &re ) == typeid( manager* ) // ложно
В первых двух сравнениях операнд re имеет тип класса с виртуальными функциями, поэтому результат применения typeid содержит тип объекта, на который ссылается re. В последних двух сравнениях операнд &re имеет тип указателя, следовательно, результатом будет тип самого операнда, т.е. employee*.
На самом деле оператор typeid возвращает объект класса типа type_info, который определен в заголовочном файле typeinfo. Интерфейс этого класса показывает, что можно делать с результатом, возвращенным typeid. (В следующем подразделе мы подробно рассмотрим этот интерфейс.)
19.1.3. Класс type_info
Точное определение класса type_info зависит от реализации, но некоторые его характерные черты остаются неизменными в любой программе на C++:
class type_info {
// представление зависит от реализации
private:
type_info( const type_info& );
type_info& operator= ( const type_info& );
public:
virtual ~type_info();
int operator==( const type_info& );
int operator!=( const type_info& );
const char * name() const;
};
Поскольку копирующие конструктор и оператор присваивания – закрытые члены класса type_info, то пользователь не может создать его объекты в своей программе:
#include typeinfo
type_info t1; // ошибка: нет конструктора по умолчанию
// ошибка: копирующий конструктор закрыт
type_info t2 (typeid( unsigned int ) );
Единственный способ создать объект класса type_info – воспользоваться оператором typeid.
В классе определены также операторы сравнения. Они позволяют сравнивать два объекта type_info, а следовательно, и результаты, возвращенные двумя операторами typeid. (Мы говорили об этом в предыдущем подразделе.)
typeid( re ) == typeid( manager ) // истинно
typeid( *pe ) != typeid( employee ) // ложно
Функция name() возвращает C-строку с именем типа, представленного объектом type_info. Этой функцией можно пользоваться в программах следующим образом:
#include typeinfo
int main() {
employee *pe = new manager;
// ia?aoaao: "manager"
cout typeid( *pe ).name() endl;
}
Для работы с функцией-членом name() нужно включить заголовочный файл .