文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
4.2 超级类的实现 - 点
在 Point.h
中,抽象数据类型包含如下:
extern const void * Point; /* new(Point, x, y); */
void move (void * point, int dx, int dy);
我们能够重复利用第二章的 new
文件,尽管我们删除了很多方法并且对 new.h
文件增加了 draw()
方法:
void * new (const void * class, ...);
void delete (void * item);
void draw (const void * self);
在 new.r
中类型描述 struct Class
应该与在 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; /* coordinates */
};
构造器必须初始化坐标 .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()
之前没有资源需要回收。在 Point_draw()
函数中,我们以一种图片能够识别的方式打印当前的坐标:
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;
}
与在 new.c
中的动态连接相结合,这就得出了 Point.c
中点的实现。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论