The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

11.3 Реализация методов классов

11.3 Реализация методов классов

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

Внутреннее различие между методом класса и другим динамически компонуемым методом скрывается в селекторе. Рассмотрим динамически компонуемый метод 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():

 

OOC_Implementing_Class_Methods

 

И методы классов, и динамически компонуемые методы, используют один и тот же селектор суперкласса, потому что он получает указатель описания класса в виде явного параметра.

 

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 },

};

 

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