在C++中使用抽象类和内部类是一种好的做法吗

Is it a good practice to use abstract class an inner classes in C++

本文关键字:一种 C++ 抽象类 内部类      更新时间:2023-10-16

我有一个类需要维护多个(目前为2或3个)上下文。这些上下文在类之外不可见。目前我的设计如下。在C++中使用抽象类作为内部类是一种好的做法吗?如果你有其他选择,请提出建议。

在下面的例子中:问题是,当编写最初的Car类时,方法(bar1和bar2)是在Sedan的上下文中编写的。现在,我通过引入一种新型汽车(掀背车)来扩展汽车类别。bar1和bar2中的算法是为Sedan类型编写的,不能用于Hatch back类型。不幸的是,我无法更改现有的Car类(即构造函数或方法签名)。因此,我在上面的例子中介绍了Type类。

我的设计方法有意义吗?请提出更好的替代方案或当前设计中的潜在问题。

class Car {
public:
   explicit Car(/* sedan-type */) {
      // set context as Sedan
   }
   explicit Car(/* hatchback-type */) {
      // set context as Hatchback
   }
   void bar1() { context_type.bar1() };
   void bar2() { context_type.bar2() };
private:
   class Type {
      virtual void bar1() = 0;
      virtual void bar2() = 0;
   }
   class SedanType {
      void bar1() {}
      void bar2() {}
   }
   class HatchBackType {      
      void bar1() {}
      void bar2() {}
   }
}

这是一种很好的做法,尤其是如果不同的类具有相似名称的策略,并且您不想混淆它们。如果你不担心这一点,那么有时把它们放在课堂之外就不那么费力了。不过,作为一种Java习语,它相当常见。

通常你只会看到基本的内部类,如果它是抽象的。您绝对不应该为Car使用不同的构造函数作为参数。你没有把你的担忧分开,也没有让政策变得可替代。

class Base {
public:
  Base(SomeAbstractPolicy *policy);
  struct SomeAbstractPolicy {
    virtual ~SomeAbstractPolicy() {}
    virtual void stuff() = 0;
  };
};

有时懒惰者会抱怨像这样的控制结构倒置。将具体的策略放在同一个头中或作为类中的静态助手可能是一个合理的折衷方案。

class Base {
public:
  Base(SomeAbstractPolicy *policy);
  struct SomeAbstractPolicy {
    virtual ~SomeAbstractPolicy() {}
    virtual void stuff() = 0;
  };
  static SomeAbstractPolicy *CreateAwesomeConcretePolicy();
  static SomeAbstractPolicy *CreateSweetConcretePolicy();
};

您可以更进一步,使用命名构造函数。

class Base {
public:
  Base CreateAwesomeBase();
  Base CreateSweetBase();
private:
  struct SomeAbstractPolicy {
    virtual ~SomeAbstractPolicy() {}
    virtual void stuff() = 0;
  };
  Base(SomeAbstractPolicy *policy);
  SomeAbstractPolicy *policy;
};

就其价值而言,单元测试要困难得多。

如果你不能有一个基于抽象策略的构造函数,那么抽象属于Car,而不是策略。当你做出这种改变时,这通常是一个更简单的解决方案。代码的味道是,您可以看到方法的整个主体是类型上的一个分支。

为什么不扩展类Car并重写bar1()bar2()方法。在它们的实现中,你不必调用父类的方法,所以你仍然可以得到你想要的。

例如,让我们以轿车为例:

class SedanCar : public Car {
  public :
     void bar1() {// do algorithm for sedan};
     void bar2() {// do algorithm for sedan};
}

现在,任何调用bar1()bar2()的SedanCar实例都将执行轿车实现。

相关文章: