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

时间:2016-01-17 14:54:32

标签: c++ c++11 inheritance multiple-inheritance

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

在州之前:简要版gist.github.com link

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

然后

对象在相应的传感器中注册。

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

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

但是现在我必须使我的SensorBase类成为模板类,因为这个方法

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

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

拜托,您能否建议一些解决方案,如何重组这个或如何让编译器在编译时决定(或至少每次调用一次//每个对象创建一次)在Hearing / Smell内部调用什么方法{{1 }}第

1 个答案:

答案 0 :(得分:1)

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

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

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

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

  • class Object {getPosition(); }
  • class ObjectWithSmell:virtual Object
  • class ObjectWithSound:virtual Object
  • ...

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