两个相关的类层次结构 - 覆盖虚函数
Two related class hierarchies - overriding virtual functions
假设我有这个基类:
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++ 不允许对被覆盖的虚拟使用差异参数。
我想我可以对insert_op的每个子类实现中的"Op"类型进行运行时类型检查,但这听起来像是一个非常丑陋的解决方案,而且它在编译时没有强制执行。
有什么出路吗?
您的Vehicle
说virtual void insert_op(Op op)
,意思是"每辆车都可以接受任何Op
"。
因此,根据您的设计,Truck
不是Vehicle
子类的有效候选项,因为它不能接受任何Op
- 它只能接受TruckDriver
s。
相关:利斯科夫替代原理
问题在于您的设计,而不是它的实现。我建议简化您的类层次结构。你真的需要这么多的类和继承吗?您可以简单地使用具有标识其类型的字段的Vehicle
和Op
吗?
让我进一步解释一下设计问题:
假设某个对象A
与方法manVehicle(Vehicle&)
. Truck
是 Vehicles 的子类,因此可以使用类型 Truck
的对象调用此方法。
但是,A
的实现并不知道Vehicle
的具体类型。它只知道所有车辆都有一个方法insert_op(Op)
,所以即使车辆实际上是Truck
,它也可以尝试像insert_op(Pilot())
这样的调用。
结论:
-
甚至不可能进行编译时检查
-
运行时检查可以工作...
- 但只会把问题扫到地毯下。
Vehicle
的用户希望能够在任何Vehicle
上呼叫insert_op(Op)
。
- 但只会把问题扫到地毯下。
解决方案是将Vehicle
界面修改为如下所示:
struct Vehicle {
virtual bool can_insert_op(Op op) = 0;
virtual void insert_op(Op op) = 0;
};
并记录下来,以便调用方知道insert_op
只能使用满足给定Vehicle
can_insert_op
的Op
调用。或类似的东西(例如来自"此车辆的无效操作类型"insert_op
记录的异常( - 只要它是此接口的记录部分,就可以正常工作。
顺便说一句,技术评论:您可能希望这些方法通过指针或引用获取Op
而不是复制它,以避免不必要的复制和切片。
每个载具子类都应创建其相应的运算符。不应有设置运算符的方法。车辆可以有一个get_operator的方法,但仅此而已。
我猜这不是你实际的层次结构(除非你正在创建一个游戏或其他东西(。如果您显示实际层次结构,则可能有助于建议更好的解决方案。
反对 OOD。 如果卡车司机是司机的孩子,那么它就是司机,但有其他功能。 在您的情况下,不允许司机,那么它不是副卡车司机。如果你想坚持当前的设计,你需要按照你的假设在fn的开头进行检查。多态性旨在@compile时间不出错,因此它在运行时是动态绑定,不依赖于编译时间。
怎么样:
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
的通用定义,并对其进行一些验证。
你想要完成的是合法的,但是,没有对良好解决方案的支持。 这不是C++本身的问题,而是面向对象的问题:
从 Vehicle
开始的类层次结构相对于 Op
的层次结构是协变的。 如果你有一个燃料等级,你会遇到同样的问题。 或行动的国籍等。
其他人已经告诉您如何使用运行时检查完成此操作的解释,但是当然,总有一些需要的地方。
如果要完成完整的编译时检查,并且想要的多态性是在编译时而不是运行时,则可以使用泛型编程模板。
- 如何重构类层次结构以避免菱形问题
- C++ 中模板化类型的类层次结构
- 为什么不同类型层次结构的指针之间的dynamic_cast定义得很好?
- 继承层次结构并将元素添加到向量
- C++ 类层次结构中的"对齐"是什么意思?
- 相同的层次结构,访问基类的受保护成员时的行为不同
- 类层次结构中的运算符重载
- 如何在层次结构中实现运算符使用?
- 反向层次结构中的可变参数模板参数
- 如何在继承层次结构中调用具有默认参数的构造函数?
- C++ 提升 - 包含类层次结构对象的类的序列化
- 在C++继承层次结构时提取实现者
- 在C++中将类实例添加到对象层次结构中的问题
- 确定大层次结构中基本指针的实际类型,无需dynamic_cast
- 在继承层次结构中复制和移动
- 模板冲突的类型-但类型应该是相同的cfr类层次结构
- 删除父/子窗口层次结构的最佳方法
- 是否可以使一个类成为两个不同层次结构的子类?
- 在类层次结构中覆盖C++
- 两个相关的类层次结构 - 覆盖虚函数