4.2 Реализация базового класса — Point

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

Интерфейс абстрактного типа данных в Point.h содержит следующее:

 

extern const void * Point;    /* new(Point, x, y); */

 

void move (void * point, int dx, int dy);

 

Можно снова использовать файлы new.? из главы 2, хотя мы удалим большинство методов и добавим в new.h draw():

 

void * new (const void * class, ...);

void delete (void * item);

void draw (const void * self);

 

Описание типа struct Class в new.r должно соответствовать декларации методов в new.h:

 

struct Class {

    size_t size;

    void * (* ctor) (void * self, va_list * app);

    void * (* dtor) (void * self);

    void (* draw) (const void * self);

};

 

Селектор draw() реализован в new.c. Он заменяет такие селекторы, как differ(), введённые в разделе 2.3, и кодируется в том же стиле:

 

void draw (const void * self) {

    const struct Class * const * cp = self;

 

    assert(self && * cp && (* cp) -> draw);

    (* cp) -> draw(self);

}

 

После этих приготовлений можно обратиться к реальной работе по написанию Point.c, реализации точек. И снова объектно-ориентированный подход помог точно определить, что необходимо сделать: мы должны принять решение о представлении и реализовать конструктор, деструктор, динамически скомпонованный метод draw() и статически скомпонованный метод move(), который представляет собой простую функцию. Если мы придерживаемся двумерной декартовой системы координат, то выбираем очевидное представление:

 

struct Point {

    const void * class;

    int x, y;          /* координаты */

};

 

Конструктор должен проинициализировать координаты .x и .y — теперь совершенно стандартной:

 

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

    struct Point * self = _self;

 

    self -> x = va_arg(* app, int);

    self -> y = va_arg(* app, int);

    return self;

}

 

Оказывается, деструктор не нужен, потому что нет ресурсов, которые должны быть освобождения до того, как delete() удалит саму struct Point. В Point_draw() печатаются текущие координаты в виде, котором их сможет понять pic:

 

static void Point_draw (const void * _self) {

    const struct Point * self = _self;

 

    printf("\".\" at %d,%d\n", self -> x, self -> y);

}

 

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

 

static const struct Class _Point = {

    sizeof(struct Point), Point_ctor, 0, Point_draw

};

 

const void * Point = & _Point;

 

move() не использует динамическую компоновку, поэтому мы опускаем static, чтобы экспортировать её из Point.c, а её имя не начинается с префикса имени класса Point:

 

void move (void * _self, int dx, int dy) {

    struct Point * self = _self;

    self -> x += dx, self -> y += dy;

}

 

На этом завершается написание кода для точек в Point.? вместе с поддержкой динамической компоновки в new.?.

 

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