假设我有这个基类:
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”的类型进行运行时类型检查,但这听起来像一个非常难看的解决方案,加上它在编译时没有强制执行。
任何出路?
答案 0 :(得分:3)
您的Vehicle
说virtual void insert_op(Op op)
表示“每辆车都可以接受任何Op
”。
因此,根据您的设计,Truck
不是Vehicle
子类的有效候选者,因为它无法接受任何 Op
- 它只能接受TruckDriver
s。
相关:Liskov substitution principle
问题出在你的设计中,而不是实现它。我建议简化你的类层次结构。你真的需要这么多的课程和继承吗?您可以简单地使用包含标识其类型的字段的Vehicle
和Op
吗?
让我进一步解释设计问题:
假设某个对象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}}的层次结构相关的是协变。如果你有一个燃料等级,你会遇到同样的问题。或者行动的国籍等等。
其他人告诉你如何通过运行时检查来解释这个问题,当然,总有一些事情需要。
如果要完成完整的编译时检查,并且您希望拥有的多态性类型是在编译时而不是运行时,则可以使用通用编程模板。