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

14.1 Идея

14.1 Идея

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

Каждый динамически скомпонованный метод вызывается через свой селектор и мы видели в главе 8, что селектор проверяет, может ли метод быть найден для объекта. В качестве примера предположим наличие селектора add() для метода добавления объекта к List:

 

struct Object * add (void * _self, const void * element) {

    struct Object * result;

    const struct ListClass * class =

                        cast(ListClass(), classOf(_self));

 

    assert(class -> add.method);

    cast(Object(), element);

 

    result = ((struct Object * (*) ())

                    class -> add.method)(_self, element);

    return result;

}

 

classOf() пытается удостовериться, что _self ссылается объект; окружение вызова cast() устанавливает, что описание класса _self принадлежит метаклассу ListClass, то есть что оно действительно содержит указатель на метод add; наконец, assert() защищает от нулевого значения, выдающего себя за этот указатель, то есть удостоверяется, что где-нибудь в цепочке наследования метод add был реализован.

Что происходит, если add() применяется к объекту, который никогда не слышал об этом методе, то есть что происходит, если _self проваливает различные тесты в селекторе add()? В настоящий момент где-нибудь в месте проблемы срабатывает assert() и наша программа завершается.

Предположим, что мы работаем с классом объектов X, которые сами по себе не являются потомками List, но которые знают некоторый объект List, которому они могли бы по логике передать запрос к add(). В настоящий момент за то, чтобы узнать (или найти с помощью respondsTo()), что add() не может быть применён к нему и соответственно перенаправить вызов, ответственность нёс бы пользователь объектов X. Однако, рассмотрим следующий немного переделанный селектор:

 

struct Object * add (void * _self, const void * element) {

    struct Object * result;

    const struct ListClass * class =

                            (const void *) classOf(_self);

 

    if (isOf(class, ListClass()) && class -> add.method) {

        cast(Object(), element);

        result = ((struct Object * (*) ())

                    class -> add.method)(_self, element);

    } else

        forward(_self, & result, (Method) add, "add",

                                            _self, element);

    return result;

}

 

Теперь _self может ссылаться на любой объект. Если оказывается, что его класс действительно содержит указатель add, этот метод вызывается как прежде. Иначе вся информация передаётся новому методу forward(): сам объект; категория ожидаемого результата; имя и указатель на селектор, потерпевший неудачу; и значения в исходном списке аргументов. forward() — самостоятельный динамически компонуемый метод, задекларированный в Object:

 

% Class Object {

        ...

%-

    void forward (const _self, void * result, \

            Method selector, const char * name, ...);

 

Очевидно, первоначальное определение немного бесполезно:

 

% Object forward {

%casts

    fprintf(stderr, "%s at %p does not answer %s\n",

                        nameOf(classOf(self)), self, name);

    assert(0);

}

 

Если сам Object не понимает метод, мы неудачники. Однако forward() компонуется динамически: если класс хочет передать сообщения, он может сделать это, переопределив forward(). Как мы увидим в примере раздела 14.6, это почти столь же хорошо, как объект, принадлежащий нескольким классам одновременно.

 

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