我正在阅读面向对象编程语言的类的一些幻灯片,并进入类型子类型定义:
Barbara Liskov,“数据抽象和层次结构”,SIGPLAN通知, 23,5,1988年5月:
这里需要什么 喜欢以下替代 property:如果对于每个对象o_s 类型S有一个对象o_T 类型T使得对于所有程序P
用T来定义,行为 当o_S为时,P不变 取代o_T然后S是a T的子类型
然后是一个例子:
Point = {x:整数,y:整数}
PositivePoint = {x:正面,y:正面}
其中Positive = {k:Integer | k> 0}我们可以说PositivePoint≤Point吗?
是的,因为PositivePoint类型的元素可能总是如此 在中定义的程序中替换Point类型的元素 点条款!
现在......对我而言,它似乎应该完全相反:Point≤DealgePoint,因为我无法在使用带负坐标的Point的程序中使用PositivePoint,而我可以反过来。
我怀疑语法是Type ≤ Sub-type
还是Sub-Type ≤ Type
,但声明似乎更清楚,那有什么不对呢?
为了让事情变得简单,问题是:
你能说PositivePoint
是Point
的子类型吗?
为什么呢?
我在这里报告我在评论中所写的内容,希望它能让我的问题更加清晰:
假设程序必须绘制一个 来自
Point
的方形地图(-100,-100) 到Point
(100,100)。什么会 如果你使用类型会发生PositivePoint
?该计划是否会 行为不变?它不会。 这种“不变的行为”是唯一的 我得不到的东西。如果定义 子类型只是inheriting and overriding
来自另一种类型 没关系,但似乎不是 案件。
答案 0 :(得分:3)
Liskov是正确的,PositivePoint≤Point,因为PositivePoint是Point的细化。任何使用Point的代码也必须能够使用PositivePoint,因为总是有可能Point的坐标是正的。反之亦然,因为使用PositivePoint的代码可能会假设坐标始终为正,并且将PositivePoint替换为Point会破坏该假设。
请注意,她并不是说PositivePoint可以替换Point,只是可以在需要Point的地方使用PositivePoint。
答案 1 :(得分:1)
您可以通过subsets建模类型关系。
PositivePoint ⊂ Point
与PositiveInt ⊂ Int
的原因相同:正数是所有可能数字的子集!
每个PositivePoint
都属于Point
,但不是其他方式。
答案 2 :(得分:1)
这个想法是任何接受PositivePoint的函数都依赖于点的值为正的事实。如果传入一个值不为正值的Point,则假设为false,函数将失败。
然而,接受Point的函数不会对该点的正面性做出任何假设,所以如果你传入一个PositivePoint,那就没关系了。
请注意,这仅适用于不可变的Point类。如果您能够更改Point的值,则PositivePoint和Point可能根本没有子类关系,因为对于PositivePoints,操作p.x = -1
将失败。
编辑:详细说明:
假设我们有二维数组,它会在需要时自动增长(即,当传递两个正数索引时,你永远不会得到索引越界错误)。现在我们有一个接受PositiveInteger p的函数,然后在索引x,y处访问2d数组。这不会失败,因为x和y保证是正的,2d阵列可以用任何一对正索引索引。但是,如果Point是PositivePoint的子类型,则p实际上可能具有负值,即使它被声明为正值。这意味着使用它来索引数组不再安全。
然而,接受Point的函数不知道该点的值是负还是正 - 它已经必须考虑它们是正的可能性。所以传入一个PositiveInteger不会破坏任何东西。
答案 3 :(得分:0)
我之前没有看到用于表示这个的≤符号,但我认为PositivePoint ≤ Point
的含义意味着Point
具有比PositivePoint
更大的潜在值范围(即:PositivePoint
是Point
的子集,PositivePoint
的所有实例都可以由Point
的有效实例替换,但不能相反。)