我们有一个庞大的软件框架,在代码的繁重部分中,我们有一个抽象的基类
class Base {
public:
virtual double eval() const = 0;
};
Run Code Online (Sandbox Code Playgroud)
它几乎充当了许多其他类的通用接口类,遍布各种子包,驻留在不同的存储库和诸如此类的东西中.
class Derived1 {
public:
virtual double eval() const override { return 1; }
}
Run Code Online (Sandbox Code Playgroud)
但是,在我们的代码中只有一个地方可以调用此函数,该代码位于核心应用程序的主循环中.
int main(int argc, char* argv[]){
Base* x = createInstance(argv[1]); // some factory function
while(true){
std::cout << x->eval() << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
我们最近发现扩展接口非常有用:
virtual double eval(int idx) const = 0;
Run Code Online (Sandbox Code Playgroud)
修复核心应用程序中对此方法的一次调用不是问题,但是修复几十个现有的派生类实现遍布我们的代码以接受并且(在大多数情况下)忽略这个新参数将是一场噩梦.
我想过提供一个看起来像这样的遗留包装器:
double Base::eval(int idx) const { return this->eval(); }
Run Code Online (Sandbox Code Playgroud)
但这意味着所有派生类都需要实现此函数的非参数版本才能存在,即使它应该被弃用.或者,我们可以将非参数版本作为其中的一部分来实现Base,但是我们会牺牲抽象性质Base,因为那时所有组件都将在那里实现.
是否有任何"整洁"的方法来解决这个问题,或者是实际联系所有子包开发人员并让他们改变他们的实现以遵守新界面的唯一理智的事情?
您可以添加新的抽象基类New,double eval(int idx)并弃用旧的基类.
当你让一个继承另一个时,你可以编写新的API接受New并保持兼容Old.
struct New
{
virtual ~New() {}
virtual double eval(int idx) = 0;
};
struct Old : New
{
virtual double eval() = 0;
virtual double eval(int idx) { eval(); } // backwards-compatible
};
Run Code Online (Sandbox Code Playgroud)
实施的New人被迫覆盖一元函数,而实施的Old人被迫覆盖旧的,无效的.