3.6 Новые возможности языка C++ C++Builder обеспечивает не только поддержку последних нововведении стандарта ANSI C++, но и расширяет язык новыми возможностями. Компоненты, свойства, методы, обработчики событии, а также шаблоны, пространства имен, явные и непостоянные объявления, RTTI и исключения - вся мощь этих средств доступна программистам, использующим C++Builder для визуальной разработки приложений. Важно понять, что расширения языка никогда не являются самоцелью, и вы по-прежнему сможете компилировать тексты, написанные в рамках стандартного C++. Однако, чтобы воспользоваться в полной мере преимуществами, которые предоставляет C++Builder для технологии быстрой разработки приложений (RAD), вам придется принять введенные расширения языка. Некоторые из расширений (например, _classid) C++Builder резервирует, главным образом, для внутреннего использования. Другие расширения совершенно очевидны (_int8, _int16 и т.д.), и здесь не рассматриваются. Наше внимание будет сфокусировано на наиболее значимых расширениях C++, которые, в основном, относятся к компонентным классам и будут постоянно встречаться как в тексте книги, так и в ваших приложениях, разрабатываемых в среде C++Builder. 3.6.1 Компоненты Компоненты часто достигают более высокой степени инкапсуляции, нежели стандартные C++ классы. Проиллюстрируем это на простом примере разработки диалога, содержащего кнопку. В типичной C++ программе для Windows нажатие мышью на кнопку приводит к генерации сообщения WM_LBUTTONDOWN. Это сообщение должно быть "поймано" программой либо в операторе switch, либо в соответствующей строке таблицы откликов (RESPONSE_TABLE), а затем передано процедуре реакции на это сообщение. Так, приложение, написанное в рамках OWL (Object Windows Library), использует макрос DEFINE_RESPONSE_TABLE1(TEventTestDlgClient, TDialog) чтобы ассоциировать событие (сообщение WM_LBUTTONDOWN), генерируемое кнопкой IDEVENTBUTTON в диалоге TEventTestDlgClient, с функцией реакции EventBNClicked. C++Builder покончил с этими трудно осваиваемыми программистскими трюками. Компонента кнопки уже запрограммирована так, чтобы реагировать на нажатие кнопки событием OnClick. Все, что надо сделать - это выбрать готовый (или написать собственный) метод и с помощью Инспектора объектов включить его в обработчик данного события. 3.6.1.1 Объявления компонентных классов Опережающие объявления классов Библиотеки Визуальных Компонент VCL, входящей в состав C++Builder, используют модификатор _declspec: _declspec(<спецификатор>) Это ключевое слово может появляться в любом месте перечня объявлений, а не только непосредственно перед модифицируемым объявлением, причем спецификатор принимает одно из следующих значений: delphiclass используется для опережающего объявления прямых или косвенных производных от VCL класса TObject. Он определяет правила совместимости VCL при обращении с RTTI, конструкторами, деструктором и исключениями. delphireturn используется для опережающего объявления прямых или косвенных производных от VCL классов Currency, AnsiString, Variant, TDateTime и Set. Он определяет правила совместимости VCL при обращении с параметрами и возвращаемыми значениями функций-членов. pascalimplementation указывает, что компонентный класс реализован на Объектном Паскале. VCL класс имеет следующие ограничения: • Запрещено наследование виртуальных базовых классов. • Компонентные классы сами не могут служить базовыми классами для наследования. • Компонентные объекты создаются в динамической памяти кучи с помощью оператора new. 3.6.1.2 Объявления свойств C++BuiIder использует модификатор _property для идентификации свойств компонентных классов. Синтаксис описания свойства имеет вид: property <тип свойства> <имя свойства> = {<список атрибутов>} ; где список атрибутов содержит перечисление следующих атрибутов свойства: write = < член данных или метод записи > определяет способ присваивания значения члену данных; read = < член данных или метод чтения > определяет способ получения значения члена данных; default = < булева константа > разрешает или запрещает сохранение значения свойства по умолчанию в файле формы с расширением .dim; stored = < булева константа или функция > определяет способ сохранения значения свойства в файле формы с расширением .dfm. C++BuiIder использует модификатор _published для спецификации тех свойств компонент, которые будут отображаться Инспектором объектов на стадии проектирования приложения. Если разработчик компоненты желает разрешить модификацию значения некоторого свойства, оно не объявляется как _published. Правила видимости, определяемые этим ключевым словом, не отличаются от правил видимости членов данных, методов и свойств, объявленных как public. Единственное отличие проявляется в том, что во время работы программы Инспектору объектов передается информация RTTI. 3.6.1.3 Объявления обработчиков событий C++BuiIder использует модификатор _closure для объявления функции обработчиков событий: <тип> (_closure * <name>) (<список параметров>) Это ключевое слово определяет указатель функции с именем name. В отличие от 4-байтового адресного указателя обычной функции (который передается в кодовые регистры CS:IP) 8-байтовый _closure передает еще и скрытый параметр (непостоянный указатель this на экземпляр текущего класса). Введение 8-байтовых указателей делает возможным не только вызывать некоторую функцию определенного класса, но и обращаться к функции в определенном экземпляре этого класса. Эта способность была заимствована из Объектного Паскаля, а _closure оказался жизненно необходимым для реализации механизма событий в Библиотеке Визуальных Компонент. 3.6.1.4 Объявления автоматизированных свойств и методов OLE Automation - это разновидность механизма связи Object Linking and Embedding, позволяющего приложениям для Windows управлять друг другом. Автоматизированный OLE контроллер является приложением, которое способно автоматизировать другое приложение - автоматизированный OLE сервер. По существу, OLE Automation представляет собой протокол обмена, посредством которого контроллер управляет действиями сервера. Все компонентные OLE объекты, экспортируемые автоматизированным сервером своим контроллерам, являются производными от базового класса TAutoObject. При создании автоматизированного сервера необходимо определить его интерфейс с контроллером, содержащий объявления свойств и методов OLE объекта с тем, чтобы контроллер получил к ним доступ. Никогда не удаляйте уже включенные в интерфейс свойства и методы - это приведет к ошибкам в работе существующих контроллеров. C++Builder использует модификатор _automated в объявлениях автоматизированного метода (Листинг 3.13). Это объявление может заканчиваться еще одним новым ключевым словом _dispid, которое ассоциирует значение идентификатора диспетчеризации OLE Automation с данной функцией. class MyOLEAutoClass : TAutoObject Листинг 3.13. Объявление автоматизированного метода. Правила видимости, определяемые этим ключевым словом, не отличаются от правил видимости, объявленных в секции public. Единственное отличие проявляется в том, что генерируемая компилятором информация о типах свойств и методов OLE Automation, делает возможным создание автоматизированных серверов. C++Builder поставляется вместе с примером (удивительным по внешней простоте и лаконичности кода) взаимодействия приложений контроллера и сервера посредством механизма OLE Automation. Этот пример проливает свет на данную методику, изложенную в системной документации весьма сбивчиво и туманно. Автоматизированный сервер Autosrv демонстрирует использование: • компонентных объектов TAutoObject и TAutoClassInfo; • метода RegisterAutoClass автоматизированного объектного класса для регистрации сервера; • свойств и методов, объявленных с ключевым словом _automated. Контроллер Autocon управляет сервером и демонстрирует: • установку и выборку свойств объекта сервера; • использование вариантов (детальная информация об типе Variant содержится в параграфе 3.6.1.6 "Расширенные типы данных Delphi". Чтобы испытать на практике, что дает взаимодействие приложений OLE Automation, выполните следующие действия: => По команде главного меню File | Open Project откройте диалог выбора проектов. => Войдите в каталог \...\CBuilder\Examples\Apps\Autosrv => Выберите проектный файл с именем Autosrv и нажмите кнопку Open. => Командой главного меню Run | Run запустите процесс компиляции и сборки автоматизированного сервера. => Снова откройте диалог выбора проектов, войдите в каталог \...\CBuilder\Examples\Apps\Autocon, выберите проектный файл с именем Autocon и нажмите кнопку Open. => Запустите процесс компиляции и сборки контроллера. Вводя сообщения в области редактируемого ввода и нажимая кнопки контроллера, вы можете моделировать некоторые процессы управления сервером. получая результаты, которые отображены на нижеследующих рисунках: Рис. 3.4. Контроллер готовит сообщение и посылает его серверу. Рис. 3.5. Контроллер принимает сообщение, "обработанные" сервером. Рис. 3.6. Контроллер снимает старое сообщение с сервера. Чтобы узнать, как реализовано такое взаимодействие, необходимо разобраться в текстах модулей автоматизированного сервера (Листинг 3.14 и Листинг 3.15) и контроллера (Листинг 3.16 и Листинг 3.17), которые заслуживают того, чтобы привести их целиком, снабдив необходимыми комментариями. Сервер содержит единственный объект Edit1 компоненты TEdit для редактируемого ввода и приема сообщений от контроллера в свойство Text. Контроллер записывает введенное пользователем сообщение в свойство Text своего объекта Edit1, а управляет сервером посредством трех кнопок Button1, Button2 и Button3 компоненты TButton (с названиями "Послать", "Принять" и "Очистить"). #ifndef Auto2H // Класс сервера ButtonServer. производный от TAutoObjiect _automated: // Автоматизированные свойства и методы public: // Общедоступные свойства и методы }; //---------------------------------------------------------- #endif Листинг 3.14. Файл объявлений Auto1.h модуля автоматизированного сервера. #include <vcl.h> // Чтение текстового значения автоматизированного свойства // Запись текстового значения автоматизированного свойства // Чтение численного значения автоматизированного свойства // Запись численного значения автоматизированного свойства // Очистка значения автоматизированного свойства // Составление текстового значения свойства из трех строк // Составление текстового значения свойства из трех чисел void _fastcall ButtonServer::SetThreeNum (int nl, int n2, int
n3) // Регистрация объекта автоматизированного сервера // Инициализация полей структуры типа TAutoClassInfo // Регистрация класса автоматизированного сервера // Инициализация объекта автоматизированного сервера int Initialization() Листинг 3.15. Кодовый файл Auto2.cpp модуля автоматизированного сервера. #ifndef Auto1H class TForm1 : public TForm { published: // IDE-managed Components private: // User declarations public: // User declarations }; extern TForm1 *Form1; #endif Листинг 3.16. Файл объявлений Auto1.h, все строки которого (за исключением выделенной строки объявления варианта) C++Builder генерирует автоматически при размещении компонент на форме контроллера. #include <vcl.h> __fastcall TForm1::TForm1(TComponent *0wner) : TForm(Owner) // Обработчик события при нажатии кнопки Buttoni void _fastcall TForm1::Button1Click(TObject *Sender) // Обработчик события при нажатии кнопки Button2 void _fastcall TForm1::Button2Click(TObject *Sender) // Обработчик события при нажатии кнопки Button3 void _fastcall TForm1::Button3Click(TObject *Sender) Листинг 3.17. Кодовый файл Auto1.cpp модуля контроллера. 3.6.1.5 Быстрый вызов функций При объявлении функций, параметры которых передаются через процессорные регистры, используется модификатор __fastcall: <возвращаемый тип> __fastcall <name>(<список параметров>) Это ключевое слово определяет, что первые три типизированных параметра функции с именем name (слева направо по списку) передаются не через стек, а через процессорные регистры AX, BX и DX. Регистры не используются, если значение параметра не умещается в регистр, т.е. при передаче через параметр чисел с плавающей точкой, структур и функций. Строго говоря, быстрый вызов функций не является прерогативой компилятора C++Builder. В предыдущей главе я уже обращал внимание читателя на использование __fastcall в объявлениях функций обработки событий, которые C++Builder генерирует автоматически.
|