Главная » Статьи » C++ » Статьи по С++ |
Скачивать материалы с сайта, могут только зарегистрированные пользователи.
Для регистрации заполните два поля ниже!
Через минуту Вы получите "Гостевой доступ"
Использование RTTI в приложениях на базе VCL
В статье рассматриваются механизм работы и использование механизма динамической идентификации типов (RTTI - runtime type identification) в приложениях, использующих объектную библиотеку ф. Borland VCL - Visual Component Library. Содержание:
Почему не стоит читать эту статью?RTTI используется ,как правило, во всех приложениях, созданных компилятором C++. Если компилятору указано не включать в объектный файл RTTI информацию, то не возможна будет динамическая идентификация типов и динамическое приведение типов. Обычно в состав RTTI входит следующая информация: имя типа (для идентификации), указатель на базовый тип (для приведения типов), указатель на конструктор копий. В RTTI поддерживающую VCL входит дополнительная информация, используемая IDE Builder C++, в первую очередь инспектором объектов. Однако структура и содержание этих дополнительных данных не документирована и вероятно может меняться в зависимости от версии Builder. Поэтому использование расширенной RTTI в приложениях возможно только при соблюдении ограничения: исходный код не может переноситься на другие версии Builder C++. Тем не менее, думаю приведенная информация будет интересна программистам в Builder C++, особенно при написании компонент. Все данные, приведенные в этой статье получены для Builder C++ 3.0. Что можно узнать из RTTI?Кроме имени типа, и указателя на базовый тип для классов со спецификатором DELPHICLASS в состав RTTI включается информация о всех свойствах, объявленных в секции __published. В том числе: имя свойства, его тип, указатели на методы установки, чтения и предикат хранения, а также значения индекса для методов установки/чтения, обслуживающих несколько свойств. А вот другие члены класса, объявленные в __published - переменные и методы в RTTI не попадают. Формат хранения информации о типе приведен в таблице №1.Таблица №1
Таблица №2
Для классовпотомков TObject получить указатель на RTTI информацию можно посредством метода ClassInfo(): void* rtti = p_class-> ClassInfo(); Указатель rtti будет указывать на область памяти, с данными с информацией о типе объекта p_class. Несколько слов о том, как самостоятельно исследовать информацию о типе. Для этого нужен какой-нибудь отладчик. В данном случае достаточно удобно пользоваться встроенным отладчиком (View|CPU). Получив значение указателя на RTTI класса, его содержимое просматривается в дампе памяти отладчика и имея описание класса (т.е. фактически зная информацию о его типе) можно делать логические заключения о структуре RTTI. Работа со свойствамиСвойства (property) введены в Builder C++ специально для поддержки классов, описанных на Object Pascal. О том, как описать свойство, установить или получить его значение, написано десятки книг (для начинающих я порекомендовал бы книгу К.Сурков, Д.Сурков, А.Вальвачев "Программирование в среде DELPHI 2.0" Минск 1997). Тем не менее остановимся на некоторых моментах:1. Доступ к значению свойства может быть напрямую или посредством функции: __property int ParamA = {read = pаram_a};//доступ к значению свойства напрямую __property int ParamB = {read = GetParamB};//доступ посредством функции метода GetParamB. В первом случае в RTTI будет приведено значение смещения переменной param_a в экземпляре класса, во втором - адрес функции, возвращающей значение свойства 2. Свойства бывают индексируемыми __property int ParamA[int index] = {read= GetParamA}; К индексированному свойству доступ возможен только через функцию, которая принимает параметр index. Самое интересное - из RTTI нельзя узнать, индексируется свойство или нет. 3. Если несколько свойств обслуживаются одним методом, в описании свойства указывается целый индекс, передаваемый в метод: __property int ParamA = {read = GetParamA,index = 0}; Значение этого индекса можно узнать из RTTI. 4. Для свойства можно указать, следует ли сохранять в файле формы его значение. Сохраняются значения свойств, отличные от значения по умолчанию, однако это можно запретить. //значение свойства не сохраняется предикат StoredC. Значение параметра stored можно узнать из RTTI. 5.Свойство может иметь значение по умолчанию (см. п 4) __property int ParamA = {read = param_a, default = 100}; Отметим, что значение default не устанавливает начальное значение свойства - это работа конструктора. Значение параметра default можно посмотреть в RTTI. Кстати, хотя везде написано, что параметру default должно присваиваться константное выражение, на самом деле можно присвоить только целое константное выражение из-за того, что как мы увидим далее для значения default отводится только 4 байта, а вещественные константы могут занимать 4,8 и 10 байт. Получение информации о классе объектаКак уже говорилось выше, информация об классе находится по адресу, возвращаемому методом ClassInfo. По этому адресу находится следующая информация:
07 05 54 4D 65 6D 6F F0 Заголовок класса: 07 - идентификатор описания класса, имя класса, указатель на конструктор копий, указатель на базовый класс, количество опубликованных свойств, имя модуля, количество опубликованных в класск свойств. Перечисления свойств: Смещение переменной - прямой доступ для чтения, адрес метода установки значения, stored = true, index = -1 (нет индекса), default = 0, порядковый номер свойства, имя свойства (Align) Формат RTTI для опубликованных свойствИз выше приведенного дампа памяти можно уяснить себе, в каком формате храниться описание опубликованного свойства. Тем не менее приведем этот формат в явном виде:
Для того чтобы прочитать значение свойства следует выполнить следующие действия:
Установка значения свойства выполняется аналогично. Как видно из выше сказанного, установка и чтение свойства невозможны без знания типа свойства. Рассмотрим кратко возможные форматы описания типов: Формат целых типов:
Формат символьного типа
Формат перечислений
Примечание: Если в описании перечисления указаны значения для символьных констант, например: enum TSeason {winter = 100, spring = 200, summer = 300, autumn = 400}; то в RTTI такой тип трактуется как целый и вся символьная информация не включается в RTTI. Формат вещественного типа
К вещественным типам относятся также типы для представления времени TDateTime (он объявлен тождественным типу double). Формат классов Формат описания классов рассмотрен выше Формат обработчиков событий
Формат строковых типов
В Pascal для хранения строк существует специальный класс - String. В "чистом" С нет специальных типов для представления строковых данных, с ними работают как с массивами байтовых (или двухбайтовых) целых чисел. Для поддержки строк в формате String в Builder C++ объявлен специальный класс AnsiString. Примеры доступа к опубликованным свойствам используя RTTI.Хотел бы заметить, что в большинстве случаев, естественно, нет нужды организовывать доступ к свойством используя RTTI. Лишь в одном случае такой подход оправдан - когда на этапе компиляции программы неизвестен тип объектов, с которыми будет работать программа. Ситуация чем-то напоминающая использование OLE Автоматизации и диспетчерских интерфейсов. Кстати, использование упомянутой технологии в этом случае предпочтительно, но если объекты не предоставляют информацию о своем типе, и известно, что их код был скомпилирован в Builder C++ при использовании VCL, то работу с ними можно автоматизировать предлагаемым способом.Работу со свойствами рассмотри на примере доступа к свойству целого типа: //описание типа функции чтения свойства Следует обратить внимание на две вещи: 1) соглашение о вызове функции должно совпадать с описанным в классе для доступа к значению функции; 2) поскольку метод- член класса неявно первым параметром получает указатель на экземпляр класса его вызвавший, следует описать этот параметр int ReadIntProperty(void* p_obj, void* p_read) Установка значения свойства производится аналогично: typedef void __fastcall(* FINTPROPSET)(void*, int); Доступ к свойствам других типов осуществляется аналогично. Статья с сайта www.ishodniki.ru | |||||||||||||||||||||||||||||||
Просмотров: 972 | | |
Выразить благодарность - Поделиться с друзьями!
Всего комментариев: 0 | |