4.2 Реализация базового класса — Point |
Предыдущая Содержание Следующая |
Интерфейс абстрактного типа данных в 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.?.
|
Предыдущая Содержание Следующая |