4

这是无聊的学术 OOP 问题之一,但它不是作业。我从一个新手程序员那里得到了一个关于 OOP 的愚蠢教科书示例的问题。

想象一下,你正在设计一个 Square 类和一个 Cube 类,应该继承哪个?

我看到了关系,但它是什么,我真的看不出来!

你能给我一个关于 OOP 的合乎逻辑的论点吗?

4

8 回答 8

22

两者都不!由于正方形不是立方体,立方体也不是正方形,所以两者都不应该从另一个继承。正方形可以继承多边形,立方体可以继承多面体,但两者本身是互斥的。

于 2009-07-17T20:25:35.243 回答
15

没有继承。继承是一种“is-a”关系(嗯,有时甚至不是“is-a”关系,如下面的链接所述)。立方体不是正方形,正方形也不是立方体。

你将如何构建,这取决于你如何建模。你可以用一个立方体有 6 个正方形(立方体不是,它有 6 个正方形;一个组合),或者一个立方体有一个边大小,就像正方形一样。但是一旦没有“is-a”,继承将是危险的区域......

此外,在继承中,对基类有效的所有内容都必须对 Derived 有效。这是正方形扩展矩形的问题。例如:

假设 Cube 继承了 Square:如果你的 Square 有方法 changeArea(double area) 和 getSide(),那么 Cube 应该也是可以的。但事实并非如此,因为立方体的面积是正方形面积的 6 倍(它有 6 个正方形)。

假设 Square 继承了 Cube:如果你的 Cube 有 setVolume(double volume) 方法,你的 square 将被破坏,一旦它没有体积

最后,如果你想使用继承,你可以创建一个GeometryObjectWithEqualSides对象,然后两者都可以继承它。:)

于 2009-07-17T20:26:52.743 回答
7

无论哪种方式都将违反Liskov 替换原则

于 2009-07-17T20:28:54.113 回答
1

都继承自超立方体

于 2009-07-17T20:33:15.570 回答
1
struct Square // Rectangle actually
{
  Square( int dx, int dy ) : dx(dx), dy(dy) {};

  int dx;
  int dy;

  int floor_area() { return dx*dy; };
};

struct Cube : Square  // Cuboid actually
{
  Cube( int dx, int dy, int dz ) : Square(dx, dy), dz(dz) {};

  int dz;

  int cube_area() { return floor_area()*2+dx*dz*2+dy*dz*2; };
};

似乎这里没有违反Liskov 替换原则。

于 2009-07-17T21:08:18.417 回答
1

正方形和立方体可以被认为是同一类“超立方体”的两个实例,它也将包含点(0 维)、线段(1 维)和除此之外的其他内容。维度的数量和一侧的长度足以定义 Hypercube 的特定实例(您当然可以添加一个 n 维的原点和方向)。

超立方体可以提供返回特定实例的顶点数、边数、面数等值的函数/方法。

有关更多信息,请参阅Wikipedia 上的Hypercube

于 2009-07-22T19:18:30.697 回答
0

两者都不应该继承另一个。一个是 2 维形状,另一个是 3 维对象。两者之间确实没有足够的相似性来证明继承是合理的。

现在你可以想象制作一个由正方形组成的立方体,如果你需要为每一边一个单独的对象;)

于 2009-07-17T20:27:41.103 回答
0

这里的大多数评论都正确地说它们都不应该从另一个继承。在大多数情况下都是如此。但我认为有更通用的答案: 这取决于你对他们的期望。 你希望 Square 做什么?Cube也这样做吗?可能是另一种方式 - 你可以在使用 Cube 时使用 Square 吗?根据常识,我认为“Cube 完成了 Square 所做的一切”和“Square 完成了 Cube 所做的一切”这两种说法都是错误的,因此它们都不应该从另一个继承。但是,由您决定它们的结构和行为,因为是您定义程序的功能和组成。

最有可能的“立方体包含 6 个正方形”是您看到的关系。

于 2009-07-17T21:21:43.803 回答