c++ - 逆变类型和可扩展性

标签 c++ types contravariance

我正在编写一个用于优化的 C++ 库,我遇到了一个与逆变类型有关的奇怪问题。

因此,我根据函数可以计算的信息定义了一个“函数”层次结构。

class Function {
 public:
    double value()=0;
}

class DifferentiableFunction : public Function {
 public:
  const double* gradient()=0;
}

class TwiceDifferentiableFunction : public DifferentiableFunction {
 public:
    const double* hessian()=0;
}

一切都很好,但现在我想为优化器定义接口(interface)。例如,一些优化器需要梯度信息或 hessian 信息才能进行优化,而有些则不需要。因此优化器的类型与函数的类型是逆变的。

class HessianOptimizer {
 public:
    set_function(TwiceDifferentiableFunction* f)=0;
}

class GradientOptimizer : public HessianOptimizer {
 public:
    set_function(DifferentiableFunction* f)=0;
}

class Optimizer: public GradientOptimizer {
 public:
    set_function(TwiceDifferentiableFunction* f)=0;
}

我想这从类型理论的角度来看是有道理的,但奇怪的是,通常当人们想要扩展代码时,他们会继承已经存在的类。因此,例如,如果其他人正在使用这个库,并且他们想要创建一种需要比 hessian 更多信息的新型优化器,他们可能会创建一个类似

class ThriceDifferentiableFunction: public TwiceDifferentiableFunction }
 public:
    const double* thirdderivative()=0;
}

但是要创建相应的优化器类,我们必须让 HessianOptimizer 扩展 ThirdOrderOptimizer。但是库用户必须修改库才能这样做!因此,虽然我们可以添加 ThriceDifferentiableFunction 而无需修改库,但逆变类型似乎失去了这个属性。这似乎只是类声明其父类型而不是子类型这一事实的产物。

但是你应该如何处理这个呢?有什么办法可以很好地做到这一点吗?

最佳答案

因为它们只是接口(interface),所以您不必担心它们的多重继承。为什么不让优化器类型成为 sibling 而不是后代?

class OptimizerBase
{
  // Common stuff goes here
};

class HessianOptimizer : virtual public OptimizerBase {
 public:
    virtual set_function(TwiceDifferentiableFunction* f)=0;
}

class GradientOptimizer : virtual public OptimizerBase {
 public:
    virtual set_function(DifferentiableFunction* f)=0;
}

class Optimizer : virtual public OptimizerBase {
 public:
    virtual set_function(TwiceDifferentiableFunction* f)=0;
}


// impl

class MyGradientOptimizer : virtual public GradientOptimizer, virtual public HessianOptimizer
{
  // ...
};

关于c++ - 逆变类型和可扩展性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29074006/

相关文章:

c++ - 将对象转换为 vector 的 const_iterator

c++ - 使用 C++ 打印数据库中的所有列

返回接口(interface)类型的 Java 方法

haskell - ixmap、数组和逆变仿函数之间的关系是什么?

c# - 有没有办法确定 C# 4.0 中接口(interface)/委托(delegate)的方差?

haskell - 可以为这种类型创建应用实例吗?

c++ - 无法在 XCode 4 项目中嵌入 C++ 中安装 libjson

C++ - 难以理解 easeInOutSine

javascript - Jquery AJAX 类型属性

data-structures - 如何确保 Rust 向量仅包含交替类型?