简体   繁体   English

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

[英]C++ classes hierarchy design choice

In my simulation I have different objects that can be sensed in three ways: object can be seen and/or heard and/or smelled. 在我的模拟中,我可以通过三种方式感知不同的对象:可以看到和/或听到和/或闻到对象。 For example, Animal can be seen, heard and smelled. 例如,可以看到,听到和闻到动物。 And piece of Meat on the ground can be seen and smelled but not heard and Wall can only be seen. 可以看到并闻到一块肉在地上,但闻不到,只能看到墙。 Then I have different sensors that gather this information - EyeSensor , EarSensor , NoseSensor . 然后,我有收集此信息的不同传感器EyeSensorEarSensorNoseSensor

Before state: brief version gist.github.com link 之前状态:简短版本gist.github.com链接

Before I started implementing NoseSensor I had all three functionality in one class that every object inherited - CanBeSensed because although classes were different they all needed the same getDistanceMethod() and if object implemented any CanBeSensed functionality it needed a senseMask - flags if object can be heard/seen/smelled and I didn't want to use virtual inheritance. 在开始实现NoseSensor之前,我在一个类中具有所有对象都继承的所有三种功能CanBeSensed因为尽管类不同,但它们都需要相同的getDistanceMethod()并且如果对象实现了任何CanBeSensed功能,则需要SenseMask-标记是否可以听到对象/ seen / smelled,我不想使用虚拟继承。 I sacrificed having data members inside this class for smell, sounds, EyeInfo because objects that can only be seen do not need smell/sound info. 我牺牲了在此类中使用数据成员来获取气味,声音和EyeInfo因为只能看到的对象不需要气味/声音信息。

Objects then were registered in corresponding Sensor. 然后将对象注册到相应的传感器中。

Now I've noticed that Smell and Sound sensors are the same and only differ in a single line inside a loop - one calls float getSound() and another float getSmell() on a CanBeSensed* object. 现在,我已经注意到,气味和声音传感器是相同的,只有在一个循环中一行的不同-一个电话浮getSound()和其他float getSmell()一对CanBeSensed*对象。 When I create one of this two sensors I know what it needs to call, but I don't know how to choose that line without a condition and it's inside a tight loop and a virtual function. 当我创建这两个传感器之一时,我知道它需要调用什么,但是我不知道如何在没有条件的情况下选择该行,它位于紧密循环和虚函数内。

So I've decided to make a single base class for these 3 functionality using virtual inheritance for base class with getDistanceMethod() . 因此,我决定使用getDistanceMethod()基类的虚拟继承为这3个功能创建单个基类。

But now I had to make my SensorBase class a template class because of this method 但是现在由于这种方法,我不得不将SensorBase类设为模板类

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

, and it meant that I need to make SensorySubSystem class(manages sensors and objects in range) a template as well. ,这意味着我还需要使SensorySubSystem类(管理范围内的传感器和对象)成为模板。 And it meant that all my SubSystems like VisionSubSystem, HearingSubSystem and SmellSubSystem inherit from a template class, and it broke my SensorySystem class which was managing all SensorySubSystems through a vector of pointers to SensorySubSystem class std::vector<SensorySubSystem*> subSystems; 这意味着我所有的子系统(例如VisionSubSystem,HearingSubSystem和SmellSubSystem)都从模板类继承,这打破了我的SensorySystem类,后者通过指向SensorySubSystemstd::vector<SensorySubSystem*> subSystems;的指针的矢量来管理所有std::vector<SensorySubSystem*> subSystems;

Please, could you suggest some solution for how to restructure this or how to make compiler decide at compile time(or at least decide once per call//once per object creation) what method to call inside Hearing/Smell Sensor s. 请问您是否可以提出一些解决方案,以了解如何重组此结构或如何使编译器在编译时确定(或至少每个对象创建一次//一次确定)在“听觉/气味Sensor调用哪种方法。

Looking at your original design I have a few comments: 看看您的原始设计,我有几点评论:

  • The class design in hierarchy.cpp looks quite ok to me. 对我来说,hierarchy.cpp中的类设计看起来还不错。
  • Unless distance is something specific to sensory information getDistance() doesn't look like a method that belongs into this class. 除非距离是特定于感官信息的东西,否则getDistance()看起来并不像属于此类的方法。 It could be moved either into a Vec2d-class or to a helper function (calculatePositon(vec2d, vec2d)). 可以将其移动到Vec2d类或辅助函数(calculatePositon(vec2d,vec2d))中。 I do not see, why getDistance() is virtual, if it does something different than calculating the distance between the given position and the objects position, then it should be renamed. 我看不到,为什么getDistance()是虚拟的,如果它执行的操作与计算给定位置和对象位置之间的距离不同,则应将其重命名。
  • The class CanBeSensed sounds more like a property and should probably be renamed to eg SensableObject. CanBeSensed类听起来更像是一个属性,应该将其重命名为例如SensableObject。

Regarding your new approach: 关于您的新方法:
Inheritance should primarily be used to express concepts (is-a-relations), not to share code. 继承应主要用于表达概念(关系),而不是共享代码。 If you want to reuse an algorithm, consider writing an algorithm class or function (favour composition over inheritance). 如果要重用算法,请考虑编写算法类或函数(偏爱继承而不是继承)。

In summary I propose to keep your original class design cleaning it up a little as described above. 总而言之,我建议如上所述使您的原始班级设计清理干净一点。 You could add virtual functions canBeSmelled/canBeHeard/canBeSeen to CanBeSensed. 您可以将虚拟函数canBeSmelled / canBeHeard / canBeSeen添加到CanBeSensed。
Alternatively you could create a class hierachy: 或者,您可以创建一个类层次结构:

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

But then you'd have to deal with virtual inheritance without any noticeable benefit. 但是,那么您将不得不处理虚拟继承而没有任何明显的好处。
The shared calculation code could go into an algorithmic class or function. 共享的计算代码可以进入算法类或函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM