阅读a fundamental paper有关继承的信息,我无法理解下面显示的推理。显然这是正确的,因为反差确实有效,我只想了解其原因。 首先,它显示为:
我的天真解释:
由于所有车辆上的功能都将在所有汽车上运行,因此,“乘用车辆”功能是“乘用汽车”功能的子类型,因为“车辆”功能集较小-汽车可以具有更多功能。
答案 0 :(得分:2)
您的问题是关于函数的协方差和协方差的,如果我们将论文中某些语言不可知的符号关系映射到实际代码,这将对您的理解有所帮助。在C ++中,此处讨论的功能为:
int GetSpeedOf(Vehicle vehicle);
子类型必须用Liskov-substitution来理解;如果某个功能需要任何类型的动物,则可以给它一只猫,并且一切都会正常进行,但是事实并非如此。需要猫的功能无法在任何类型的动物上使用。
假设您了解可以将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”的类型实际上是{{1 }}。因此,“如果一个函数使用了Vehicle,那么它就是一个使用Car的函数的子类型”。之所以可以这样做,是因为“ Works”功能将要执行的所有操作,也必须在实际传入的东西(汽车)上成为可能。
一个用例是,Works函数也可以传递给BoatWrapper类,该类需要在船上运行的函数。我们可以给出该功能类型的子类型“ Vehicle-> void”,知道实际传递的函数中的所有操作也必须在传递给它的Boat上可用,因为Boat是Vehicle的子类型,而我们的实际函数仅使用该参数的操作性越通用。
另一方面,协方差对返回类型进行操作;如果CarWrapper类需要一个回调为我们生成Car,则我们将无法传递Vehicle生成函数,因为CarWrapper无法以汽车特定的方式使用结果。但是,如果我们有一个期待车辆产生器的功能,那么我们可以给它提供汽车产生器或船用产生器;因此(void-> Car)是(void-> Vehicle)的子类型,前提是Car是Vehicle的子类型。
协方差意味着子类型关系保持相同的方向, 因此我们可以继续使用其他功能应用程序,而“ Car side”仍然是“ Vehicle side”的子类型,即:
std::function<auto(Vehicle) -> void>
这意味着如果我们期望有一个VehicleFactoryFactoryFactory,那么当我们获得CarFactoryFactoryFactory时我们应该满足:
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)))
由于参数类型的矛盾,关系随每个函数应用程序而反转。
#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);
}
在有逆差的情况下,很难以直觉的方式理解这一点。这就是为什么我的CarWrapper仅尝试对规则的单个应用解释它的原因,而CarFactory示例包含三个协方差应用。