我正在编写一个用于优化的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;
}
这一切都很好,但现在我想为优化器定义接口。例如,一些优化器需要梯度信息或粗体信息才能进行优化,有些则不需要。因此,优化器的类型与函数类型相反。
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;
}
我认为从类型理论的角度来看是有意义的,但奇怪的是,通常当人们想要扩展代码时,他们将继承现有的类。因此,例如,如果其他人正在使用此库,并且他们想要创建一种需要比粗麻布更多信息的新型优化器,他们可能会创建类似
的类class ThriceDifferentiableFunction: public TwiceDifferentiableFunction }
public:
const double* thirdderivative()=0;
}
但是要创建相应的优化器类,我们必须使HessianOptimizer扩展ThirdOrderOptimizer。但是库用户必须修改库才能这样做!因此,虽然我们可以在不必修改库的情况下添加ThriceDifferentiableFunction,但似乎逆变类型会丢失此属性。这似乎只是类声明其父类型而非子类型的事实。
但是你应该怎么处理这个?有没有办法做得很好?
答案 0 :(得分: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
{
// ...
};