7.5 Возвращаемся к Object

Предыдущая  Содержание  Следующая V*D*V

В разделе 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.

 

Предыдущая  Содержание  Следующая