4.3 继承 - 环
一个环形仅仅是一个大的点:此外对于中心坐标它需要一个半径。画法有点不同,但是移动只需要我们改变中心坐标。
这就是我们能够正常的为我们的文本编辑器和演择源代码重用而做好准备的地方。我们对点的实现做一个拷贝并且改变环与点不同的地方。 Struct Circle
获取其他额外的组成:
int rad;
这部分组成在构造器中初始化
self->rad=va_arg(*app,int);
并且在 Circle_draw()
中使用:
printf("circle at %d,%d rad %d\n",
self —> x, self —> y, self —> rad);
我们在 move()
中有点迷惑。对于一个点和一个环必要的动作是相同的:对于坐标部分我们需要增加转移参数。然而,在一种情况, move()
工作于 struct Point
,在另外一种情况,它工作与 struct Circle
。如果 move()
是动态连接的,我们需要提供两个不同的函数去做相同的事情。但是,会有更好的方式,考虑一下点和环表示的层:
struct Point struct Circle
图片显示每一个环都以一个点开始。如果我们分配一个 struct Circle
通过增加到 struct Point
的结尾,我们可以向 move()
函数中传递一个环,因为表示式的初始化部分看起来仅仅像点,而 move()
方法期望接到收点,并且点仅仅是 move()
方法能够改变的。这里是一个合理的方式确保对环的初始化部分总看起来像点:
struct Circle { const struct Point _; int rad; };
我们让派生的结构体以一个我们要扩展的基结构体的拷贝而开始。信息隐藏要求我们决不直接的访问基结构体;因此,我们使用几乎不可见的下划线作为它的名字并且把它声明为 const
避开粗心的指派。
这就是简单的继承的全部:一个子类从一个超类(或者基类)继承仅仅通过扩充表示超类的结构体。
由于子类对象(一个环)的表示就像一个超类对象(一个点)的表示一样动身。环总能够佯装成一个点 - 在一个环的表示的初始化地址处的确是一个点的表示。
向 move()
中传递一个环是完全确定的:子类继承了超类的方法,因为这些方法仅在子类的表示上操作,这些子类的表示和超类的表示是相同的, 而这些方法原先就在超类上写好了。传递一个环就像传递一个点意味着把 struct Circle*
转换成 struct Point*
。我们将把这样的操作看成一个从子类到超类的上抛 - 在标准化 C 语言中,它能够使用明确的转换操作符来实现或者通过中间的 void*
的值。
这通常是不佳的,然而,传递一个点到一个函数专为环如, Circle_draw()
: 如果一个点原先就是一个环,从 struct Point*
转换成 struct Circle*
仅仅是可允许的。我们称这样的从超类到子类的转换为下抛 - 这也要求明确的转换或 void*值,并且它仅仅对于指针,对于对象能够使用,指针,对象在子类的开始做转换。
对于动态连接方法如 draw()
,这种情形是不同的。让我们再次看先前的图片,这次完全明确类型描述符如下 :
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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