您可以拥有“空”的摘要/类吗?


10

当然可以,我只是想知道以这种方式进行设计是否合理。

我正在制作突破克隆,并正在进行一些类设计。我想使用继承(即使不是必须的)来应用我在C ++中学到的知识。我当时正在考虑类的设计,并想出了这样的东西:

GameObject->基类(由x和y偏移量等数据成员以及SDL_Surface *向量

组成:MovableObject:GameObject->抽象类+ GameObject的派生类(一个方法void move()= 0;)

NonMovableObject:GameObject->空类...除了构造函数和析构函数外,没有方法或数据成员(至少现在是这样?)。

后来我打算从NonMovableObject派生一个类,例如Tileset:NonMovableObject。我只是想知道是否经常使用“空”抽象类或只是空类...我注意到我这样做的方式,我只是为了分类而创建NonMovableObject类。

我知道我只是想做一个突破性克隆而已,但我的重点不在游戏上,而是在使用继承和设计某种游戏框架上。

Answers:


2

在C ++中,您具有多重继承,因此拥有这些空类实际上没有任何好处。如果您想稍后让Ball从GameObject和MovableObject继承(例如,您要持有一个GameObjects数组并每n秒调用一次Tick方法以使它们全部移动),这很容易做到。

但是,在那种情况下,我个人建议您记住一个公理 “代替继承,更喜欢使用组合(封装) ”,然后看一下状态模式。如果希望以后每个对象都有其运动状态,请将其传递给GameObject。例如:DiagonalBouncingMovementState代表球,HoriazontalControlledMovementState代表球拍,NoMovementState代表砖。

1)如果您选择(这也是我建议的话),这将使您更容易编写单元测试 -因为您可以独立测试GameObject和每个状态。

2)假设您有一些令牌从砖头上掉下来,但是您想更改其中一个,以便它们沿对角线移动-而不是围绕类继承的某些复杂层次结构移动令牌,您只需更改传递给它的硬编码移动状态。

3)最重要的是:当您要基于这些标记开始更改游戏中球和/或桨的移动方式时,您只需保持其移动状态(DiagonalMovementState变为DiagonalWithGravityMovementState)。

现在,这些都没有暗示继承总是不好的,只是为了说明为什么我们更喜欢封装而不是继承。您可能仍想从GameObject派生每种类型的对象,并使这些类了解其初始运动状态。您几乎肯定会想从抽象的MovementState类派生每个运动状态,因为C ++没有接口。

$ 0.02


8

在Java中,“空”接口用作标记(例如Serializable),因为在运行时可以检查对象是否“实现”了该接口。但是在C ++中,对我来说似乎毫无意义。

IMO,语言功能应被视为工具,它可以帮助您实现某些目标,而不是义务。仅仅因为您可以使用功能并不意味着您必须。毫无意义的继承不能使程序变得更好。


3

您没有想过它;你在想,那很好。

如前所述,不要仅仅因为它存在就使用语言功能。学习语言功能的权衡是良好设计的关键。

人们不应该使用基类进行分类。这可能意味着检查类型。那是个坏主意。

考虑编写定义对象合同的纯抽象。您对象的合同是面向外部的界面。它的公共接口。它能做什么。

注意:重要的是要了解这不是它拥有的数据xy而是它的作用move()

在您的设计中,您有一个class GameObject。您依赖于它的数据而不是它的功能。它感觉高效能正确使用继承分享什么似乎像常见的共享数据,你的情况xy

这不是继承的正确用法。永远记住,继承是您可能拥有的最紧密的耦合形式,因此您应始终争取宽松的耦合。

就其本质而言,NonMovableObject它不会移动。它x并且y最肯定应该声明const。就其本质而言,MoveableObject需要采取行动。它不能宣布其xyconst。因此,这不是相同的数据,因此无法共享。

考虑对象的功能或合同。他们怎么?正确处理,数据就会来临。一次处理一个对象。依次担心每一个。您会发现您的优秀设计是可重用的。

也许根本没有NonMovableObjectGameObjectBase定义move()方法的纯抽象呢?您的系统实例化GameObject执行的工具move(),而系统仅移动需要移动的系统。

这仅仅是个开始; 一种味道。兔子洞要深得多。没有勺子。


虽然这是事实,无论是MovableObjectNonMovableObject可以相互继承,它们都具有一个位置; 这样,它们两者都应该由代码消耗,例如,它们希望将怪物的目标对准某个对象而无需考虑该对象是否可能移动。
超级猫

2

它具有C#中的应用程序,例如提到的ammoQ,但在C ++中,唯一的应用程序是您要具有NonMovableObject指针列表。

但是,然后我想您会通过NonMoveableObject指针破坏对象,在这种情况下,您将需要虚拟析构函数,并且它不再是空类。:)


我也考虑过这种情况,但是您如何处理这样的不显示任何行为的对象列表?最有可能的是,您将以某种方式找出真实类型并使用强制转换来访问可用的方法和字段-绝对是代码味道。
user281377 2011年

是的,这是一个好点。
tenpn 2011年

1

您可能会看到的一种情况是,您希望强类型集合包含其他类型的异构类型。我并不是说这是个好主意,它可能表示抽象能力较弱或设计不佳,但它确实发生了。正如您所提到的,这是一种对事物进行分类的方法,它可能有用且完全有效。

例如,您想要一个收藏来容纳猫和狗。在您的设计中,您认为它们有很多共同点,因此有Mamal的基类,并在您的集合中使用此类型(例如List)。都好。然后,您决定要向集合中添加一些青蛙,但它们不是哺乳动物,因此一种方法是将“青蛙”和“哺乳动物”作为“动物”的子类,但也许您想不到“青蛙”和“哺乳动物”在动物中有很多。常见,所以动物保持空虚。然后,您可以使用Animal而不是Mamal输入您的收藏集,一切都很好。

在现实生活中,我发现即使我迟早创建了一个空的基类,某些功能仍然在那里存在,但是肯定存在它们。


但是,要问的一个问题是:如果这些类型没有共同点,为什么将它们保存在同一集合中?您无法对集合中的所有项目执行操作,这有点违背拥有这样一个集合的目的。现在,您可能需要将某些人工操作添加到两者中,以简化逻辑-例如,实现Visitor设计模式-此时,它可能会再次变得有用,但是现在它们有一些共同点……
Jules
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.