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.2 Реализация

14.2 Реализация

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

К счастью, в главе 7 мы решили осуществить наш стандарт кодирования с помощью препроцессора ooc, а селекторы — часть стандарта кодирования. В разделе 8.4 мы рассмотрели отчёт selector, который генерирует все селекторы. Как показано выше, передача сообщений выполняется декларацией forward(), определением реализации по умолчанию и модификацией отчёта selector в etc.rep таким образом, чтобы все сгенерированные селекторы перенаправляли всё, что они не понимают: (* Как и ранее, представление упрощено, чтобы не показывать части, которые имеют дело со списками с переменным количеством аргументов.)

 

`%header { `n

`%result

`%classOf

 

`%ifmethod

`%checks

`%call

`t } else `n

`%forward

`%return

} `n `n

 

Это почти тот же код, что и в разделе 8.4: как мы видели выше, cast() в отчёте classOf заменён на вызов isOf(), как часть отчёта ifmethod, и добавлено условие else с отчётом forward для генерации вызова forward().

Для проверки аргумента вызов forward() происходит через другой селектор. Вероятно, ничего полезного в том, чтобы застрять здесь в рекурсии нет, поэтому если селектор forward() генерирует самого себя, мы останавливаем всё с помощью assert():

 

% forward       // передаём вызов, но не передаём forward

 

`{if `method forward

`t `t assert(0);

`} `{else

`t `t forward(_self, \

          `{if `result void 0, `} `{else & result, `} \

          (Method) `method , " `method ", `%args );

`} `n

 

Дополнительный `{if проверяет, что селектор в конечном счёте возвращает результат, ожидаемый его вызывающей стороной. К этому результату должен будет привести forward(). Общий подход заключается в том, чтобы передать категорию результата в forward(), чтобы каким-то образом его заполнить. Если, однако, наш селектор возвращает void, у нас нет переменной result. В этом случае мы передаём нулевой указатель.

Выглядит так, что вручную можно было бы написать код получше: в некоторых случаях мы могли бы избежать переменной result, присвоения и отдельного оператора return. Однако такая правка излишне усложнила бы отчёты ooc, потому что любой разумный компилятор в любом случае сгенерирует один и тот же машинный код.

classOf — другой отчёт, в котором сделаны значительные изменения. Вызов cast() удалён, но нас интересует вопрос, что происходит, если вызов метода класса должен быть перенаправлен. Давайте посмотрим на селектор, который для new() генерирует ooc:

 

struct Object * new (const void * _self, ...) {

    struct Object * result;

    va_list ap;

    const struct Class * class = cast(Class(), _self);

 

    va_start(ap, _self);

    if (class -> new.method) {

        result = ((struct Object * (*) ()) class -> new.method)

                                                (_self, & ap);

    } else

        forward((void *) _self, & result, (Method) new, "new",

                                                _self, & ap);

    va_end(ap);

    return result;

}

 

new() вызывается для описания класса, подобного List. Вызов метода класса для чего-то другого, отличного от описания класса, является, вероятно, очень плохой идеей; поэтому чтобы запретить это используется cast(). new принадлежит Class; поэтому делать вызов isOf() необходимости нет.

Давайте предположим, что мы забыли определить начальный Object_new(), то есть что List не унаследовал даже метод new, и поэтому new.method представляет собой нулевой указатель. В этом случае forward() применяется к List. Однако, forward() это динамически компонуемый метод, но не метод класса. Поэтому forward() ищет в описании класса List метод forward, то есть пытается найти ListClass_forward():

 

OOC_Implementation

 

Это совершенно разумно: List_forward() ответственен за все сообщения, которые не понимает aList; ListClass_forward() ответственен за всё то, что List не может обработать. Вот отчёт classOf в etc.rep:

 

`{if `linkage %—

`{if `meta `metaroot

`t const struct `meta * class = classOf(_self); `n

`} `{else

`t const struct `meta * class = ` \

                    (const void *) classOf(_self); `n

`}

`} `{else

`t const struct `meta * class = ` \

                    cast( `metaroot (), _self); `n

`} `n

 

Для динамически компонуемых методов `linkage это %-. В этом случае мы получаем описание класса от classOf() как struct Class, но приводим его к структуре описания класса, что произойдёт как только isOf() проверит тип, чтобы мы могли выбрать подходящий компонент метода.

Для метода класса `linkage определяется как %+, то есть мы переходим ко второй половине отчёта и просто проверяем с помощью cast(), что _self представляет собой по крайней мере Class. Это единственная разница в селекторе для метода класса с перенаправлением.

 

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