|
Программирование >> Полиморфизм без виртуальных функций в с++
даже большинство пользователей, повлек бы за собой огромные издержки для тех, кому нужны лишь минимальные сведения. my type table: дополнительная информация о типе your type table: SctypeidlT) Ваша дополнительная информация о типе Рис. 14.1 Разработчик компилятора может по своему выбору предоставлять информацию о типе, специфичную для данной реализации. Доступ к такой расширенной системной информации можно получать с помошью ассоциативного массива точно так же, как и к дополнительной информации, предоставляемой пользователем. Вместо этого допустимо поместить расширенную информацию в класс Extended type info, производный от type inf о (см. рис. 14.2). type infо: Стандартная информация о типе Информация о типе, зависящая от реализации Рис. 14.2 Чтобы понять, имеется ли нужная расширенная информация о типе, можно было бы воспользоваться оператором dynamic cast: #include <type info.h> typedef Extended type info Eti; void f(Sometype* p) if (Eti* р = dynamic cast<Eti*>(&typeid(*p))) { Какую расширенную информацию мог бы получить пользователь с помощью компилятора или инструментального средства? Практически любую имеющуюся в компиляторе, если во время выполнения она понадобится некоторой программе. Например: □ сведения о размещении объекта для ввода/вывода объектов или отладки; □ указатели на функции создания и копирования объектов; □ таблицы функций вместе с символическими именами для вызова из интерпретатора; □ списки объектов данного типа; □ ссылки на исходный код функций-членов; □ встроенную документацию по классу. Все это вынесено в библиотеки, возможно даже стандартные, поскольку есть очень много разных потребностей, зависящих от реализации деталей и слипшом много инфор.мации, чтобы поддерживать ее в са.мом языке. С другой стороны, некоторые возможные применения позволяют обойти статический контроль тигюв, а другие требуют неоправданно больших затрат. 14.2.6. Модель размещения объекта в памяти Вот как мог бы размещаться в памяти объект с таблицей виртуальных функций и информацией о типе (см. рис. 14.3). ту Т: vtbl: F ..type inf о: Рис. 14.3 Пунктирная стрелка с длинными штрихами представляет смещение, по которому можно найти начало полного объекта, имея лишь указатель на полиморфный подобъект. Это абсолютный аналог смещения (дельты), используемого при реализации виртуальных функций (см. раздел 12.4). Для каждого типа с виртуальными функция.ми генерируется объект типа type inf о. Эти объекты не обязательно должны быть уникальными. Однако хороший компилятор будет везде, где возможно, генерировать уникальные объекты type inf о и лишь для тех типов, для которых действительно используется в каком-то виде информация о типе. В простой реализации объект type inf о для класса разрешается поместить прямо рядом с vtbl. Реализации, основанные на Cfront или позаимствовавшие из него схему размещения таблицы виртуальных функций, можно модернизировать для поддержки RTTI так, что существующий код даже не придется перекомпилировать. Просто о поддержке RTTI я раз.мышлял в то время, когда реализовывал версию 2.0, и оставил два пустых слова в начале vtbl, и.мея в виду именно это расширение. Но в то время RTTI не была добавлена, так как я сомневался в том, что она потребуется, и не знал, в какой форме ее предоставить пользователям. В качестве эксперимента был реализован простой вариант, когда у каждого объекта класса с вир-туальны.ми функция.ми можно было бы запросить его имя. Тогда я убедился, что смогу добавить поддержку RTTI, если потребуется, и удалил эту возможность. 14.2.7. Простой ввод/вывод объектов Ниже представлены идея, как .можно было бы использовать RTTI в простой системе ввода/вывода объектов, и возможная схема реализации такой системы. Пользователь хочет прочитать объекты из потока, убедиться, что они имеют ожидаемые типы, а зате.м как-то их применить. Например: void user{) { открыть файл, предполагая, что он содержит объекты типа Shape, и присоединить к этому файлу ss в качестве istream ... io obj* р = get obj{ss); читать объект из потока if (Shape* sp = dynamic cast<Shape*>(р)) { sp->draw(); использовать Shape ... else { ошибка: в файле есть объект, не принадлежащий классу Shape Функция user () работает с фигурами только через абстрактный класс Shape и потому готова принять любую фигуру. Использование dynamic cast необходимо, поскольку система объектного ввода/вывода способна работать и со многими другими видами объектов, так что пользователь может случайно открыть файл, содержащий объекты, но только из классов, о которых он ранее не слышал. Такая система объектного ввода/вывода предполагает, что каждый объект, который можно записывать или считывать, принадлежит классу, производному от io ob j. Класс io ob j должен быть полиморфным, чтобы к нему можно было применять оператор dynamic cast. Например:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |