C++类层次结构设计选择

C++ classes hierarchy design choice

本文关键字:选择 结构设计 层次 C++      更新时间:2023-10-16

在我的模拟中,我有不同的物体可以通过三种方式感知:物体可以看到和/或听到和/或闻到。例如,动物可以被看到、听到和闻到。地上的一块肉能看得见,闻到,却听不到,墙也只能看得见。然后我有不同的传感器来收集这些信息 - EyeSensorEarSensorNoseSensor

在状态之前:简短版本 gist.github.com

链接

在我开始实现 NoseSensor 之前,我将所有三个功能都放在一个类中,每个对象都继承了这些功能 - CanBeSensed因为尽管类不同,但它们都需要相同的getDistanceMethod(),如果对象实现任何CanBeSensed功能,它需要一个 senseMask - 标志如果对象可以被听到/看到/闻到,我不想使用虚拟继承。我牺牲了在此类中拥有嗅觉、声音EyeInfo的数据成员,因为只能看到的对象不需要气味/声音信息。

然后将对象注册到相应的传感器中。

现在我注意到气味和声音传感器是相同的,只是在循环内的一行中有所不同 - 一个调用浮getSound(),另一个调用CanBeSensed*对象float getSmell()。当我创建这两个传感器中的一个时,我知道它需要调用什么,但我不知道如何在没有条件的情况下选择这条线,它位于一个紧密的循环和一个虚拟功能中。

所以我决定为这 3 个功能创建一个基类,使用虚拟继承来使用基类getDistanceMethod()

但是现在由于这种方法,我不得不使我的SensorBase类成为模板类

virtual void sense(std::unordered_map<IdInt, CanBeSensed*>& objectsToSense) = 0;

,这意味着我也需要将SensorySubSystem类(管理范围内的传感器和对象)制作为模板。这意味着我所有的子系统,如VisionSubSystem,HearingSubSystem和SmellSubSystem都继承自模板类,它破坏了我的SensorySystem类,该类通过指向类SensorySubSystem指针向量管理所有SensorySubSystems std::vector<SensorySubSystem*> subSystems;

请,您能否建议一些解决方案来重组它或如何使编译器在编译时决定(或每次调用至少一次/每次对象创建一次)在听觉/嗅觉Sensor中调用什么方法。

看看你的原始设计,我有几点意见:

  • 层次结构中的类设计对我来说.cpp看起来还不错。
  • 除非距离是特定于感官信息的东西,否则getDistance()看起来不像属于此类的方法。它可以移动到Vec2d类或辅助函数(calculatePositon(vec2d,vec2d))。我不明白,为什么getDistance()是虚拟的,如果它的作用与计算给定位置和对象位置之间的距离不同,那么它应该重命名。
  • 类CanBeSensed听起来更像是一个属性,可能应该重命名为例如SensableObject。

关于您的新方法:
继承应该主要用于表达概念(is-a-relations),而不是共享代码。如果要重用算法,请考虑编写算法类或函数(优先于组合而不是继承)。

总之,我建议保持你原来的类设计,如上所述。您可以添加虚拟函数canBeSmelled/canBeHeard/canBeSeen到CanBeSensed。
或者,您可以创建一个类层次结构:

  • class Object{ getPosition(); }
  • 类 ObjectWithSmell : 虚拟对象
  • 类 ObjectWithSound : 虚拟对象

但是,您将不得不处理虚拟继承,而没有任何明显的好处。
共享计算代码可以进入算法类或函数。