9.1 Инициализация

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

Описания классов — долгоживущие объекты. Они постоянны и существуют практически так же долго, как приложение выполняется. Такие объекты по возможности инициализируются во время компиляции. Однако в главе 6 мы решили, что статическая инициализация делает описания классов трудными для сопровождения: порядок компонентов структур должен быть согласован со всеми инициализациями, а наследование вынудило бы нас раскрыть динамически компонуемые методы за пределами их файлов реализации.

Для начальной загрузки мы инициализируем во время компиляции только описания Object и Class как статические структуры в файле Object.dc. Все другие описания классов генерируются динамически, а конструкторы метаклассов, начиная с Class_ctor(), заботятся о наследовании и перезаписи динамически компонуемых методов.

ooc генерирует функции инициализации, чтобы скрыть детали вызова new() для генерации описаний классов, но факт того, что они должны явно вызываться в коде приложения, является источником трудно диагностируемых ошибок. Например, рассмотрите initPoint() и initCircle() из раздела 6.10:

 

void initPoint (void) {

    if (! PointClass)

        PointClass = new(Class, "PointClass",

                Class, sizeof(struct PointClass),

                ctor, PointClass_ctor,

                0);

    if (! Point)

        Point = new(PointClass, "Point",

                Object, sizeof(struct Point),

                ctor, Point_ctor,

                draw, Point_draw,

                0);

}

 

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

 

void initCircle (void) {

    if (! Circle) {

        initPoint();

        Circle = new(PointClass, "Circle",

                Point, sizeof(struct Circle),

                ctor, Circle_ctor,

                draw, Circle_draw,

                0);

    }

}

 

Обе функции неявно соблюдают иерархию классов: initPoint() удостоверяется, что PointClass существует, прежде чем использовать его для генерации описания Point; вызов initPoint() в initCircle() гарантирует, что описание суперкласса Point и его описание метакласса PointClass существуют, прежде чем они будут использованы для генерации описания Circle. Опасности рекурсии нет: initCircle() вызывает initPoint(), потому что Point это суперкласс Circle, но initPoint() не будет ссылаться на initCircle(), потому что ooc не разрешает циклы в отношениях между суперклассами.

Однако, всё пойдёт ужасно неправильно, если мы когда-нибудь забудем проинициализировать описание класса до того, как будем его использовать. Поэтому в этой главе мы рассмотрим механизмы, которые автоматически предотвратят эту проблему.

 

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