Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 100 101 102 [ 103 ] 104 105 106 ... 144


□ реализации в разных библиотеках несовместимы между собой;

□ обычно реализация является недостаточно общей;

□ в больщинстве случаев RTTI выглядит как привлекательная штучка , которой так и хочется воспользоваться, а не как опасное устройство, к которому надо прибегать в крайнем случае;

□ в любой крупной библиотеке, похоже, существует немного случаев, где применение RTTI необходимо настолько, что без нее библиотека либо вообще не могла бы предоставить какую-нибудь возможность, либо предоставляла ее в очень сложном (как для пользователей, так и для разработчиков) виде.

Предоставив стандартный механизм RTTI, мы сможем преодолеть барьер на пути использования библиотек из разных источников (см. раздел 8.2.2). Удастся реализовать механизм RTTI логически последовательно, попытаемся сделать его безопасным, предупреждая о возможных неправильных способах использования.

Наконец, при проектировании C+-I- был заложен принцип: когда все сказано и сделано, надо доверять программисту. Воз.\южная польза важнее, че.м предполагаемые ошибки.

Однако некоторые пользователи, в частности Джим Уолдо, энергично доказывают, что в RTTI возникает необходимость очень редко, а неправильное понимание, лежащее в основе всех ошибок применения данного средства, распространено широко, значит, общее воздействие этого механизма на C-I-+ негативно. Только время покажет, кто прав.

14.2.5. Оператор typeidQ

я надеялся, что оператор dynamic cast сможет удовлетворить все потребности, так что никаких других механизмов RTTI пользователям не понадобится. Однако многие пользователи, с которыми я обсуждал этот вопрос, со мной не согласились и указали еще на два момента:

□ необходимость знать точный тип объекта, то есть быть уверенпы.м, что объект принадлежит именно классу X, а не классу X или производпо.му от него (только последнее и можно получить от оператора dynamic cast);

□ использование точного типа объекта как источника дополнительной информации об этом типе.

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

Точный тип объекта нужно знать для того, чтобы применить ко всему объекту некоторый стандартный сервис. В идеале такие сервисы должны предоставляться в виде виртуальных функций, так что точный тип знать не обязательно, но, когда этой функции нет, знание точного типа и выполнение над ним операции необходимы. Системы объектного ввода/вывода и системы баз данных работают именно так. В подобных случаях нельзя предполагать наличие общего интерфейса у всех управляемых объектов, поэтому приходится прибегать к точно.му типу. Другое, гораздо более простое применение - получить имя класса для выдачи диагностического сообщения:

cout typeid(*р) .named ;



const char* nameO const; имя типа

Комитет по стандартизации все еще обсуждает соглашения об именовании стандартных библиотечных классов. Я выбрал те имена, которые, скорее всего, будут утверждены.

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

class type info;

const type info& typeid(имя типа); псевдообъявление const type info& typeid(выражение); псевдообъявление

Таким образом, typeid () возвращает ссылку на неизвестный тип, который называется type inf о. Если операндо.м является имя типа, то typeid () возвращает ссылку на объект type inf о, представляющий тип именно с этим именем. Если же операнд - это выражение, то typeid () возвращает ссылку на объект type inf о, представляющий тип объекта, обозначенного этим выражением.

Причина, по которой typeid () возвращает именно ссылку, а не указатель на type inf о: мы хотели запретить обычные операции с указателями, например == или ++, над объектами, возвращенными type id (). Например, вовсе не очевидно, что каждая реализация сможет гарантировать уникальность объектов для идентификации типа. А это значит, что сравнение результатов typeid () нельзя определить просто как сравнение указателей на объекты типа type inf о. Если же typeid () возвращает ссылку на type inf о, то нетрудно определить оператор ==, так чтобы он правильно обрабатывал возможное дублирование объектов type inf о для одного и того же типа.

14.2.5.1. Класс typejnfo

Класс type info определен в заголовочном файле <type info.h>, который нужно включать, если используется результат, выданный typeid (). Точное определение класса type inf о зависит от реализации, но это полиморфный тип, в котором имеются операторы сравнения и операция, возвращающая имя типа:

class type info {

представление зависит от реализации

private:

type info(const type info&); пользователи не могут

type info& operator=(const type info&); копировать type info

public:

virtual ~type infо(); полиморфный

int operator==(const type info&) const; можно сравнивать

int operator!=(const Cype info&) const;

int before(const type info&) const; упорядоченный



Может предоставляться и более детальная информация. Однако пользователи понимают детальную информацию по-разному. Тем же, кому она вообще не нужна, хотелось бы уменьшить расход памяти. Поэтому предоставляемые типом type info сведения намеренно сведены к минимуму.

Функция before () предназначена для сортировки объектов типа type inf о, чтобы их можно было хранить в хэш-таблицах и т.п. Отношение, описываемое этой функцией, никак не связано с отношением наследования (см. раздел 14.2.8.3). Более того, нет никакой гарантии, что before () будет давать одинаковые результаты в разных программах или при разных запусках одной и той же программы. В этом смысле before () напоминает оператор взятия адреса.

14.2.5.2. Расширенная информация о типе

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

Расс\ютрнм, как компилятор или инструментальное средство могли бы предоставить пользователю информацию о типах во время исполнения. Предположим, что и.меется инструмент, генерирующий таблицу объектов Tinia My type inf о. Наилучший способ представления инфор.мации пользователю - применение ассоциативного массива (отображение, словарь), который сопоставляет такие таблицы с именами типов. Чтобы получить таблицу для конкретного типа, можно было бы написать;

linclude <type info.h>

extern Map<My type info,const char*> my type table;

void f(B* p) (

My type info& mi = my type table[typeid(*p).naraeO]; воспользоваться mi

Кто-то предпочел бы индексировать таблицы непосредственно значениями typeid (), а не требовать от пользователя обращения к строке name ():

extern Map<Your type info,type info*> your type table;

void g(B* p) {

Your type info& yi = your type table[btypeid(*p)]; воспользоваться yi

С помощью такого способа ассоциирования результатов typeid с информацией пользователи могут привязывать к типам различную инфор.мацию (см. рис. 14.1). Аналогичные действия производятся и инструментальными средства.ми. При этом добавленные сведения не мешают друг другу.

Это очень важно, поскольку вероятность, что есть информация, устраивающая всех пользователей, равна нулю. Любой набор данных о типе, устраивающий



1 ... 100 101 102 [ 103 ] 104 105 106 ... 144

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика