2010-08-31 74 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解析方法。