7.5 Возвращаемся к Object |
Предыдущая Содержание Следующая |
В разделе 7.1 мы увидели, что для того, чтобы работать с Point, необходимо собрать информацию для всех суперклассов по пути к корневому классу. Так как же определить Object? Конечно, не имело бы смысла определить Object как часть программы awk. Очевидный подход — написать файл описания класса:
#include <stdarg.h> #include <stddef.h> #include <stdio.h> %prot #include <assert.h>
% Class Object { const Class @ class; // описание объекта % void delete (_self); // удалить экзмепляр const void * classOf (const _self); // класс объекта size_t sizeOf (const _self); // размер объекта %— void * ctor (_self, va_list * app); // конструктор void * dtor (_self); // деструктор int differ (const _self, const Object @ b); // истина, если != int puto (const _self, FILE * fp); // вывести на экран %}
К сожалению, это особый случай: будучи корневым классом Object не имеет суперкласса, а будучи первым метаклассом Class не имеет мета суперкласса. Только одно описание класса обладает этим свойством; поэтому, мы позволяем ooc распознавать этот специальный синтаксис для заголовка класса в качестве описаний классов `root и `metaroot. Class представляет собой ещё одну проблему: мы видели в разделе 7.1, что новые метаклассы могут быть задекларированы напрямую с новым классом, так как они могут иметь в качестве новых компонентов только ссылки на методы. Class является первым метаклассом и имеет некоторые дополнительные компоненты:
% Class Class: Object { const char * name; // имя класса const Class @ super; // суперкласс класса size_t size; // занимаемый объектом размер памяти % Object @ new (const _self, ...); // создание экземпляра const void * super (const _self); // суперкласс класса %}
Оказывается, что нашего синтаксиса описания классов вполне достаточно, чтобы описать Class. Это ещё один особый случай для ooc: это единственный класс, которому разрешено иметь в виде метакласса самого себя. Если мы поместим оба описания в один файл описания класса Object.d и если позволим Object быть перед Class, поиск описаний классов в ooc будет заканчиваться сам по себе. Наша база данных завершена. Мы могли бы написать реализацию Object и Class вручную — нет смысла в добавлении специального кода для ooc, если он используется только для генерации одной реализации. Тем не менее, наш механизм генерации отчётов достаточно хорош, чтобы быть адаптированным для Object, и мы можем получить значительную выгоду. Файлы интерфейса для Point и Object очень похожи за исключением того, что Object.h не имеет интерфейса суперкласса для подключения и не декларирует функцию инициализации. Однако, соответствующий ему файл отчета h.rep используется много раз, так что мы должны избежать загромождения его условными операторами, которые обычно не нужны. Вместо этого мы добавим параметр в командной строке ooc:
$ ooc -R Object -h > Object.h
Этот параметр вызывает загрузку специального файла отчёта h−R.rep, который создан специально для корневого класса. Оба файла отчёта в основном генерируют заголовки методов и могут совместно использовать ещё один файл отчета header.rep, который содержит отчёт header, используемый в обоих случаях. Аналогично, много общего имеют файлы представлений Point и Object и чтобы для учёта различий загрузить файл отчёта r-R.rep вместо r.rep мы используем -R:
$ ooc -R Object -r > Object.r
Object.r не имеет суперкласса представление для подключения, а структура метакласса для Class начинается с дополнительных компонентов. Общий код декларации селекторов суперклассов и методов, как компонентов метакласса, находится в другом файле отчёта, va.rep. Наконец, можно использовать -R и ещё один файл отчёта c-R.rep вместо c.rep, чтобы помочь сгенерировать данную реализацию:
$ ooc -R Object Object.dc > Object.c
ooc добавит операторы include и заголовки методов предварительной обработки в Object.dc как и в любой другой файл реализации. Единственное различие заключается в реализации %init: мы всё ещё можем позволить ooc сгенерировать селекторы и селекторы суперклассов, но мы должны закодировать статическую инициализацию описаний классов, показанных в разделе 6.7, вручную. Существует вопрос, как следует написать конструктор метакласса Class_ctor(). Если мы сделаем это в Object.dc вручную, то по существу закодируем цикл для обработки пар селектор / метод дважды: один раз в Object.dc для Class_ctor() и один раз в файле отчета c.rep для всех других классов. Оказывается, у нас есть достаточно информации, чтобы сделать это в c-R.rep. Если мы предположим, что первые несколько аргументов конструктора появляются в тот же порядке, что и компоненты, указанные для Class, то сможем сгенерировать весь конструктор и таким образом использовать общий код цикла в качестве отчёта meta-ctor-loop в общем файле отчёта etc.rep.
|
Предыдущая Содержание Следующая |