6.9 Селекторы суперклассов

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

Перед тем, как конструктор подкласса выполнит свою собственную инициализацию, необходимо вызвать конструктор суперкласса. Аналогичным образом, деструктор подкласса должен вызвать деструктор своего суперкласса после того, как завершил свою собственную работу по удалению ресурсов. Реализуя селекторные функции, мы должны также предоставить селекторы для вызовов суперкласса:

 

void * super_ctor (const void * _class,

                void * _self, va_list * app) {

    const struct Class * superclass = super(_class);

 

    assert(_self && superclass -> ctor);

    return superclass -> ctor(_self, app);

}

 

void * super_dtor (const void * _class, void * _self) {

    const struct Class * superclass = super(_class);

 

    assert(_self && superclass -> dtor);

    return superclass -> dtor(_self);

}

 

Эти селекторы должны вызываться только реализацией подкласса; поэтому мы подключаем их декларации в файл представления, а не в файл интерфейса. Чтобы быть на безопасной стороне, мы поставляем селекторы суперкласса для всех динамически скомпонованных методов, то есть каждый селектор имеет соответствующий селектор суперкласса. Таким образом, каждый динамически скомпонованный метод имеет простой способ вызвать метод суперкласса.

На самом деле есть тонкая ловушка искушения. Рассмотрим как метод произвольного класса X вызывал бы метод своего суперкласса. Это правильный путь:

 

static void * X_method (void * _self, va_list * app) {

    void * p = super_method(X, _self, app);

    ...

 

Посмотрев на селекторы суперкласса, показанные выше, мы видим, что super_method() в этом случае вызывает

 

super(X) -> method(_self, app);

 

то есть метод в суперклассе класса X, для которого мы только что определили X_method(). Тот же метод до сих пор достигается даже если какой-то подкласс Y унаследовал X_method(), потому что реализация не зависит от будущего наследования.

Следующий код для X_method() может выглядеть более правдоподобно, но он сломается как только этот метод унаследуется:

 

static void * X_method (void * _self, va_list * app) {

    void * p =  /* НЕПРАВИЛЬНО */

        super_method(classOf(_self), _self, app);

    ...

 

Определение селектора суперкласса теперь вызывает

 

super(classOf(_self)) -> method(_self, app);

 

Если _self в классе X, мы приходим к тому же методу, что и раньше. Однако, если _self в подклассе Y от X, получаем

 

super(Y) -> method(_self, app);

 

и который всё тот же X_method(), то есть вместо вызова метода суперкласса мы застреваем в последовательности рекурсивных вызовов!

 

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