类设计,以避免需要基类列表

时间:2013-03-20 10:54:28

标签: c++ inheritance rtti

我目前正处于课程库的设计阶段,偶然发现类似于“Managing diverse classes with a central manager without RTTI”或“pattern to avoid dynamic_cast”的问题。

想象一下,有一个类层次结构,其基类 Base 和两个类 DerivedA DerivedB Base <的子类/ em>的。在我的库中的某个地方,将有一个类需要保存两种类型的对象列表 DerivedA DerivedB 。进一步假设此类需要根据类型对两种类型执行操作。显然我会在这里使用虚函数来实现这种行为。但是如果我需要管理类给我所有 DerivedA 类型的对象呢?

这是不良类设计的指标,因为我只需要对类层次结构的子集执行操作吗?

或者它只是意味着我的管理类不应该使用 Base 的列表,而是两个列表 - 一个用于 DerivedA ,一个用于 DerivedB ?因此,如果我需要对两种类型执行操作,我将不得不迭代两个列表。在我的情况下,需要向层次结构添加新子类的可能性非常低,当前数量大约为3或4个子类。

3 个答案:

答案 0 :(得分:3)

  

但是如果我需要管理类给我所有的对象呢?   输入DerivedA?

     

这是否是一个糟糕的课程设计的指标,因为我有需要   仅对类层次结构的子集执行操作?

更可能是肯定而不是否定。如果您经常需要这样做,那么有必要质疑层次结构是否有意义。在这种情况下,您应将其分为两个不相关的列表。

另一种可能的方法是通过虚拟方法处理它,例如,对于不影响该方法的方法,DeriveB将实现no-op实现。如果不了解更多信息,很难说清楚。

答案 1 :(得分:2)

如果将(指针)对象存储在一起,必须以不同方式处理,这肯定是设计糟糕的标志。

然而,您可以将此不同的行为实现为基类中的空函数或使用访问者模式。

答案 2 :(得分:-1)

你可以通过多种方式实现。

  • 尝试dynamic_cast到特定的类(这是一个暴力解决方案,但我只将它用于接口,将它用于类是一种代码味道。虽然它会工作。)
  • 做类似的事情:

    class BaseRequest {};
    class DerivedASupportedRequest : public BaseRequest {};
    

    然后修改您的类以支持该方法:

    // (...)
    void ProcessRequest(const BaseRequest & request);
    
  • 在基类中创建虚方法bool TryDoSth(); DerivedB将始终返回false,而DerivedA将实现所需的功能。

  • 上述替代方法:创建方法Supports(Action action),其中Action是定义可能的操作或操作组的枚举;在这种情况下,在类上调用DoSth(),它不支持给定的功能应该导致抛出异常。
  • 基类可能有方法ActionXController * GetControllerForX(); DerivedA将返回实际控制器,DerivedB将返回nullptr
  • 同样,基类可以提供方法:BaseController * GetController(Action a)

你问,这是不好的设计。我相信,这取决于功能的共同点和不同的功能。如果您有100种常用方法且只有一种不同,那么将这些数据保存在单独的列表中会很奇怪。但是,如果不同方法的计数值得注意,请考虑更改应用程序的设计。这可能是一般规则,但也有例外。在不了解背景的情况下很难分辨。