提问人:John V 提问时间:10/12/2018 最后编辑:TamaMcGlinnJohn V 更新时间:10/12/2018 访问量:202
如果 Car 是 Vehicle 的子类型,为什么 Vehicle->void 被视为 Car->void 的子类型?
If Car is a subtype of Vehicle, why is Vehicle->void considered a subtype of Car->void?
问:
阅读一篇关于继承的基础论文,我无法理解下面所示的推理。显然这是正确的,因为逆变确实有效,我只是想了解其中的道理。 首先,它表明:
- 如果函数返回 Car,则它是返回 Vehicle 的函数的子类型。那是因为所有的车辆也是汽车。(返回类型的协方差)。
- 如果一个函数接受 Vehicle,那么它就是接受 Car 的函数的子类型,因为“一般来说,车辆上的每个函数也是
汽车。
我无法理解这种反转的解释,所以我在下面展示这个:
我幼稚的解释:
由于所有车辆上的函数都将适用于所有车辆,因此函数 take Vehicle 是函数 take Car 的子类型,因为 Vehlice 的函数集较小 - Car 可以具有更多功能。
答:
你的问题是关于函数的协方差和逆方差,我认为如果我们将论文中一些与语言无关的符号关系映射到实际代码中,这将有助于你的理解。在 C++ 中,这里讨论的函数是:
int GetSpeedOf(Vehicle vehicle);
必须从Liskov替代的角度来理解亚型;如果一个函数需要任何类型的动物,你可以给它一只猫,一切都应该可以正常工作,但情况并非如此;需要猫的功能不能在任何类型的动物上起作用。
假设您了解可以将 Car 传递给 GetSpeedOf 函数,现在我们将解决函数接受函数的更复杂的情况,这带来了逆变。
下面的 CarWrapper 有一辆私家车,它将使用外部提供的功能对它做一些事情。该功能必须适用于汽车。因此,如果你给出一个更普遍适用于所有战车的功能,那就没问题了。
#include <functional>
class Vehicle { };
class Car : public Vehicle { };
class CarWrapper
{
Car car;
typedef std::function<auto(Car) -> void> CarCallback;
CarCallback functionPtr;
public:
void PassCallback(CarCallback cb)
{
functionPtr = cb;
}
void DoStuff()
{
functionPtr(car);
}
};
void Works(Vehicle v){}
int main() {
CarWrapper b;
b.PassCallback(&Works);
}
因此,PassCallback 函数需要类型 CarCallback(论文中的“Car -> void”),但我们给它一个子类型“Vehicle -> void”,因为“&Works”的类型实际上是 。因此,“如果一个函数接受 Vehicle,那么它就是接受 Car 的函数的子类型”。这是可能的,因为“Works”功能将执行的所有操作也必须在实际传入的东西上成为可能 - 汽车。std::function<auto(Vehicle) -> void>
一个用例是,Works 函数也可以传递给 BoatWrapper 类,该类需要在船上操作的函数。我们可以给出该函数类型的子类型,“Vehicle -> void”,因为 Boat 是 Vehicle 的一个子类型,而我们的实际函数只使用参数的更通用的 Vehicle'ness 来操作,因为实际传递的函数中的所有操作都必须在传递给它的 Boat 上可用。
另一方面,协方差对返回类型进行运算;如果 CarWrapper 类期望为我们生成 Car 的回调,我们将无法传入 Vehicle-generating 函数,因为这样 CarWrapper 将无法以特定于汽车的方式使用结果。
但是,如果我们有一个期望车辆发电机的函数,我们将能够给它一个汽车发电机或船发电机;因此 (void -> Car) 是 (void -> Vehicle 的子类型) iff Car 是 Vehicle 的子类型。
协方差意味着子类型关系保持在同一方向, 因此,我们可以继续坚持使用另一个功能应用程序,并且“汽车端”仍将是“车辆端”的子类型,即:
Car is a subtype of Vehicle means that:
(void -> Car) is a subtype of (void -> Vehicle) - as in the code sample above
(void -> (void -> Car)) is a subtype of (void -> (void -> Vehicle))
(void -> (void -> (void -> Car))) is a subtype of (void -> (void -> (void -> Vehicle)))
这意味着,如果我们期望一个 VehicleFactoryFactoryFactory,那么当给定一个 CarFactoryFactoryFactory 时,我们应该感到满意:
#include <functional>
class Vehicle { };
class Car : public Vehicle { };
typedef std::function<auto() -> Vehicle> VehicleFactory;
typedef std::function<auto() -> VehicleFactory> VehicleFactoryFactory;
typedef std::function<auto() -> VehicleFactoryFactory> VehicleFactoryFactoryFactory;
void GiveMeAFactory(VehicleFactoryFactoryFactory factory)
{
Vehicle theVehicle = factory()()();
}
typedef std::function<auto() -> Car> CarFactory;
typedef std::function<auto() -> CarFactory> CarFactoryFactory;
typedef std::function<auto() -> CarFactoryFactory> CarFactoryFactoryFactory;
Car ActualCarCreateFunc() { return Car(); }
CarFactory CarFactoryCreateFunc() { return &ActualCarCreateFunc; }
CarFactoryFactory CarFactoryFactoryCreateFunc() { return &CarFactoryCreateFunc; }
int main() {
GiveMeAFactory(&CarFactoryFactoryCreateFunc);
}
由于参数类型存在逆变,则关系会随着每个函数应用而反转。
Car is a subtype of Vehicle means that:
(Vehicle -> void) is a subtype of (Car -> void)
((Car -> void) -> void) is a subtype of ((Vehicle -> void) -> void)
(((Vehicle -> void) -> void) -> void) is a subtype of (((Car -> void) -> void) -> void)
在逆变的情况下,很难用直观的术语来理解这一点。这就是为什么我的 CarWrapper 只尝试针对规则的单个应用来解释它,而 CarFactory 示例包含三个协方差应用。
评论
上一个:总和类型的结构类型化
下一个:什么是尾递归?
评论