两个相关的类层次结构 - 覆盖虚函数

时间:2013-02-09 10:58:58

标签: c++

假设我有这个基类:

struct Vehicle {
  //"op" stands for the operator of the vehicle
  //examples: pilot, truck driver, etc.
  virtual void insert_op(Op op) = 0;
  //other members...
};

这两个子类

struct Truck : public Vehicle {
  void insert_op(Op op) override {
    //prepare Truck with truck driver
  }
};

struct Airplaine : public Vehicle {
  void insert_op(Op op) override {
    //prepare Airplaine with pilot
  }
};

正如您猜测的那样,这是另一个层次结构:

struct Op {};
struct TruckDriver : public Op {};
struct Pilot : public Op {};

你已经看到了问题,不是吗?我想FORCE Truck只接受TruckDrivers和FORCE airplaines只接受飞行员,但这在目前的设计中是不可能的。 C ++不允许覆盖虚拟的diff参数。

我想我可以在insert_op的每个子类实现中对“Op”的类型进行运行时类型检查,但这听起来像一个非常难看的解决方案,加上它在编译时没有强制执行。

任何出路?

5 个答案:

答案 0 :(得分:3)

您的Vehiclevirtual void insert_op(Op op)表示“每辆车都可以接受任何Op”。

因此,根据您的设计,Truck不是Vehicle子类的有效候选者,因为它无法接受任何 Op - 它只能接受TruckDriver s。

相关:Liskov substitution principle


问题出在你的设计中,而不是实现它。我建议简化你的类层次结构。你真的需要这么多的课程和继承吗?您可以简单地使用包含标识其类型的字段的VehicleOp吗?


让我进一步解释设计问题:

假设某个对象A使用方法manVehicle(Vehicle&)Truck是Vehicle的子类,因此可以使用Truck类型的对象调用此方法。

然而,A的实现并不清楚具体类型的Vehicle是什么。它只知道所有车辆都有方法insert_op(Op),因此即使车辆实际上是insert_op(Pilot()),它也可以尝试Truck之类的呼叫。

结论:

  • 甚至无法进行编译时检查

  • 运行时检查可以正常工作......

    • 但只能解决地毯下的问题。 Vehicle的用户希望能够在任何insert_op(Op)上致电Vehicle

解决方案是将Vehicle界面修改为:

struct Vehicle {
  virtual bool can_insert_op(Op op) = 0;
  virtual void insert_op(Op op) = 0;
};

并对其进行记录,以便调用者知道insert_op只能在Op的{​​{1}}上使用can_insert_op来调用Vehicle。或类似的东西(如来自insert_op的记录异常“此车辆的无效操作类型”) - 任何工作只要它是此界面的记录部分。


BTW技术评论:您可能希望这些方法通过指针或引用取Op而不是复制它,以避免不必要的副本以及slicing

答案 1 :(得分:0)

Vehicle子类应各自创建其适当的运算符。应该没有设置运算符的方法。车辆可以有一个get_operator方法,但就是这样。

我猜这不是你的实际等级(除非你正在创造游戏或其他东西)。如果您显示实际的层次结构,可能有助于建议更好的解决方案。

答案 2 :(得分:0)

找不到OOD。如果卡车司机是司机的孩子,那么它是司机,但有其他功能。在你的情况下,驱动程序不允许,然后它不是子卡车司机。如果你想坚持当前的设计,你需要按照你的假设在fn的开头进行检查。 多态性的设计不会导致错误@compile时间因此它在运行时的动态绑定不依赖于编译时间。

答案 3 :(得分:0)

怎么样:

struct Vehicle {
  //"op" stands for the operator of the vehicle
  //examples: pilot, truck driver, etc.
  virtual void insert_op(Op op) = 0;
  virtual bool validate_op(Op op);
  //other members...
};

struct Truck : public Vehicle {
  void insert_op(Op op) override {
    if (validate_op(op)) {
        //prepare Truck with truck driver
    }
  }
  bool validate_op(Op op) override {
    //check if this is a valid truck driver
    return ( typeid(op)==typeid(TruckDriver) );
  }
};

您可以保留insert_op的通用定义并对其进行一些验证。

答案 4 :(得分:0)

您想要实现的目标是合法的,但是,不支持一个好的解决方案。这不是C ++本身的问题,而是面向对象的问题:

Vehicle开始,您的类层次结构与<{1}}的层次结构相关的是协变。如果你有一个燃料等级,你会遇到同样的问题。或者行动的国籍等等。

其他人告诉你如何通过运行时检查来解释这个问题,当然,总有一些事情需要。

如果要完成完整的编译时检查,并且您希望拥有的多态性类型是在编译时而不是运行时,则可以使用通用编程模板。