您的问题是关于函数的协变和逆变,我认为如果我们将论文中的一些与语言无关的符号关系映射到实际代码,这将有助于您的理解。在 C++ 中,这里讨论的函数是:
int GetSpeedOf(Vehicle vehicle);
子类型必须按照Liskov-substitution来理解;如果一个函数需要任何类型的动物,你可以给它一只猫,一切都应该正常工作,但反之则不然;需要猫的功能无法对任何类型的动物起作用。
假设您了解可以将 Car 传递给 GetSpeedOf 函数,现在我们将讨论更复杂的函数接受函数的情况,这会带来逆变。
下面的 CarWrapper 有一个私有 Car,它将使用从外部提供的函数对其进行处理。该功能必须适用于汽车。因此,如果您提供一个更普遍适用于所有车辆的功能,那很好。
#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”的类型实际上是std::function<auto(Vehicle) -> void> .因此“如果一个函数采用 Vehicle,那么它就是采用 Car 的函数的子类型”。这是可能的,因为“Works”函数将执行的所有操作也必须在实际传入的内容(汽车)上是可能的。
这种情况的一个用例是,Works 函数也可以传递给 BoatWrapper 类,该类需要在船上运行的函数。我们可以给出该函数类型的子类型“Vehicle -> void”,知道实际传递的函数中的所有操作也必须在传递给它的 Boat 上可用,因为 Boat 是 Vehicle 的子类型,而我们的实际函数只使用要操作的参数的更一般的 Vehicle'ness。
另一方面,协方差作用于返回类型;如果 CarWrapper 类需要一个为我们生成 Car 的回调,我们将无法传入 Vehicle 生成函数,因为这样 CarWrapper 将无法以特定于汽车的方式使用结果。
如果我们有一个期望车辆发电机的函数,我们可以给它一个汽车发电机或船发电机;因此 (void -> Car) 是 (void -> Vehicle) 的子类型,当且仅当 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 示例包含协方差的三个应用。