2010-08-31 79 views
7

我正在扩展第三方库提供的类。我们称之为Foo的班级有一个reset()方法,可以调用该方法以重新启动Foo的行为。该类还内部使用reset()方法。强制执行第三方方法virtuality

class Foo 
{ 
    public: 
    void reset() { 
     /* ... */ 
    } 
    void something() { 
     reset(); 
    } 
}; 

到目前为止,我需要超负荷reset()方法,以恢复我的附加功能,以及:不幸的是

class Bar : public Foo 
{ 
    public: 
    void reset() { 
     /* ...something... */ 
     Foo::reset(); 
    } 
}; 

,因为Foo::reset()方法不是虚拟的,通过调用Bar::something()我得到的Foo::reset()方法调用而不是Bar::reset()

有没有一种方法(与超载Foo::something()不同),使它向后虚拟?

+0

顺便说一句,通过这种方式,我学会了永远将任何既公开又内部使用的方法设置为虚拟。 – Dacav 2010-08-31 15:08:19

+1

这是一个糟糕的决定,谷歌NVI,你会看到避免公共虚拟方法的趋势。你遇到的问题是不同的:你不能扩展一个没有被设计为扩展的类。 – 2010-08-31 15:10:17

+0

我强烈支持非虚拟接口。使用'virtual'公共方法类似于返回内部处理句柄 - >这是一个No-No。 – 2010-08-31 15:18:08

回答

5

您无法扩展那些无意扩展的类。

1

不,这是不可能的。方法的虚拟性是在方法被声明时决定的,并且你以后不能在基类中改变它。

为了让您这样做,没有什么不幸的。虚拟方法的行为与非虚拟方法的行为不同,在设计对象时必须考虑它。有了这个提议,我不得不考虑我所有的方法都可能以两种截然不同的方式表现出来。这大大增加了应用的设计成本并降低了可靠性。

1

如果既没有重置也没有虚拟的东西,你就搞砸了,这就是故事的结尾。如果某件事情是虚拟的,你可以覆盖它。但是,如果这些必要的方法不是虚拟的,那么这个类不打算被扩展(或者如果它是有意的,那么它是正确实现的)。

编辑:

您可以尝试组合,例如,

class Bar { 
    Foo f; 
    // foo's methods, etc, wrapped here 
    void something() { 
     f.reset(); 
     reset(); 
    } 
}; 

但是,如果您需要整体,隐式转换,东西,你仍然塞满了。

3

您不能在库中虚拟出reset(),这样它会影响基类而不更改基类的代码。对于初学者来说,编译器没有添加必要的簿记代码,允许它对reset()进行虚拟调用。

2

没有使用继承的“干净方式”。虚拟是一种编译/链接时间差异:在运行时(虚拟)与直接链接(非虚拟)使用vtable解析方法。