逆变类型和可扩展性

Jer*_*wen 6 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;
}
Run Code Online (Sandbox Code Playgroud)

这一切都很好,但现在我想为优化器定义接口.例如,一些优化器需要梯度信息或粗体信息才能进行优化,有些则不需要.因此,优化器的类型与函数的类型相反.

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;
}
Run Code Online (Sandbox Code Playgroud)

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

class ThriceDifferentiableFunction: public TwiceDifferentiableFunction }
 public:
    const double* thirdderivative()=0;
}
Run Code Online (Sandbox Code Playgroud)

但是随后要创建相应的优化器类,我们必须使HessianOptimizer扩展ThirdOrderOptimizer.但是库用户必须修改库才能这样做!因此,虽然我们可以在不必修改库的情况下添加ThriceDifferentiableFunction,但似乎逆变类型会丢失此属性.这似乎只是类声明其父类型而非子类型的事实.

但是你应该怎么处理这个呢?有没有办法很好地做到这一点?

Rei*_*ica 2

由于它们只是接口,因此您不必担心它们的多重继承。为什么不让优化器类型成为兄弟姐妹而不是后代呢?

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
{
  // ...
};
Run Code Online (Sandbox Code Playgroud)

  • +1。OP 关于使 `TwiceDifferentiableFunction` 继承自 `DifferentiableFunction` 是正确的,因为它在语义上是有意义的。然而,“GradiantOptimizer”继承自“HessianOptimizer”是没有意义的。从语义上讲,这是不正确的。 (2认同)