11.3 Реализация методов классов |
Предыдущая Содержание Следующая |
Внутреннее различие между методом класса и другим динамически компонуемым методом скрывается в селекторе. Рассмотрим динамически компонуемый метод exec() для расчёта узла. Для получения описания класса селектор применяет classOf() и ищет .exec в этом месте:
double exec (const void * _self) { const struct NodeClass * class = cast(NodeClass(), classOf(_self));
assert(class -> exec.method); return ((double (*) ()) class -> exec.method)(_self); }
В противоположность ему рассмотрим new(), метод класса, который применяется к описанию класса. В этом случае self ссылается на само описание класса и селектор ищет .new как компонент *self:
struct Object * new (const void * _self, ...) { struct Object * result; va_list ap; const struct Class * self = cast(Class(), _self);
assert(self -> new.method); va_start(ap, _self); result = ((struct Object * (*) ()) self -> new.method) (_self, & ap); va_end(ap); return result; }
Вот картинка, описывающая связь exec() и new():
И методы классов, и динамически компонуемые методы, используют один и тот же селектор суперкласса, потому что он получает указатель описания класса в виде явного параметра.
struct Object * super_new (const void * _class, const void * _self, va_list * app) { const struct Class * superclass = super(_class);
assert(superclass -> new.method); return ((struct Object * (*) ()) superclass -> new.method) (_self, app); }
Селекторы генерируются ooc под управлением отчёта selectors в etc.rep. Поскольку селекторы отличаются для методов класса и динамически компонуемых методов, ooc должен знать способ компоновки метода. Поэтому методы классов определены в файле описания класса после динамически компонуемых методов и разделителя %+. Вот куски кода из Object.d:
% Class Object { ... % const Class @ classOf (const _self); // класс объекта ... %- void * ctor (_self, va_list * app); // конструктор ... void delete (_self); // возвращение экземпляра %+ Object @ new (const _self, ...); // создание экземпляра %}
delete() перемещён к динамически компонуемым методам, а new() представлен как метод класса.
% Class Class: Object { ... % Object @ allocate (const _self); // память для экземпляра ... %}
После удаления new() из списка статически компонуемых методов для Class, мы упаковываем группу распределения памяти новым статически компонуемым методом allocate(). ooc узнаёт компоновку каждого метода с помощью разделителей %- и %+, а отчёт selectors может быть расширен для генерации селекторов, показанных выше. Другие отчёты генерируют декларации селекторов для файла интерфейса, декларации селекторов суперклассов и размещение описания метакласса для файла представления, цикл в конструкторе метакласса, который распознаёт тройной набор селектор / тэг / метод и вводит их в описание класса, и, наконец, функции инициализации для описаний классов и метаклассов. Все эти отчёты должны быть расширены. Например, в отчёте -h в h.rep декларации динамически компонуемых методов генерируются с помощью
`{%— `%header ; `n `}n
Новый цикл добавляет декларации методов классов:
`{%+ `%header ; `n `}n
`{+ представляет собой цикл по методам классов текущего класса. Так как мы обращаемся к new() и delete() через селекторы, то должны реализовать их для Object в Object.dc:
% Object new { %casts return ctor(allocate(self), app); }
new() создаёт область для нового объекта и вызывает подходящий конструктор для его инициализации. allocate() в основном содержит старый код new(). Он получает динамическую память и вставляет указатель описания класса, так что динамическая компоновка ctor() в new() работает корректно:
% allocate { struct Object * object; %casts assert(self -> size); object = calloc(1, self -> size); assert(object); object -> magic = MAGIC; object -> class = self; return object; }
delete() вызывает деструктор dtor() как и раньше и передаёт результат в free():
% Object delete { %casts free(dtor(self)); }
Всякий раз, когда мы добавляем методы в Object, обращение к которым происходит через селекторы, мы не должны забыть вставить их вручную в описания классов в Object.dc. Вот пример для _Object:
static const struct Class _Object = { { MAGIC, & _Class }, "Object", & _Object, sizeof(struct Object), { "", (Method) 0, (Method) Object_ctor }, ... { "delete", (Method) delete,(Method) Object_delete }, ... { "", (Method) 0, (Method) Object_new }, };
|
Предыдущая Содержание Следующая |