2015-05-30 106 views
1

我有以下典型的場景,其中我想隱藏在子類實現的細節,並通過接口將其暴露:訪問保護功能

template <typename Derived> 
class Interface 
{ 
public: 
    void a() 
    { 
     static_cast<Derived*>(this)->_a(); 
    } 
}; 

class Implementation : public Interface<Implementation> 
{ 
protected: 
    void _a() 
    { 
     /* 
     ... 
     */ 
    } 
}; 

我想我明白爲什麼這並未並且我知道聲明類InterfaceImplementation的朋友可以解決它,但是當涉及到更復雜的層次結構(如多個接口)和各種級別的繼承(就像我的真實情況)時,事情變得非常混亂。

我想避免在每個實現接口的類中聲明friend class Interface<Implementation>

對於這個問題,有沒有另一個好的解決方案?

謝謝!

+1

使'_a()'不受保護?那或「朋友」是真正走的唯一途徑。 – Barry

+0

當然,這是一個解決方案,但是然後每個人都可以訪問_a(),這是我不想做的。如果沒有CRTP,這種情況非常簡單,所以我認爲它也可以用它來完成。 –

+0

不要將實現類型的對象暴露在模塊的界面中,那麼每個人都無法訪問它們。 –

回答

0

您可以編寫Interface的構造函數,以便它必須被賦予調用_a的函數。即:

template<class Derived> 
class Interface 
{ 
protected: 
    explicit Interface(TypeForUnderscoreA fa); 

}; 

然後使用它。

問題是什麼TypeForUnderscoreA?有幾個選項。最簡單的方法是將其設置爲std::function。這可以起作用,但是,大概你做了CRTP來避免虛擬功能。使用mem_fun和一些演員(醜陋但隱藏在Interface),會讓你失望到一個簡單的間接成本。

+0

確切地說,CRTP的意義在於避免虛函數,並允許編譯器在編譯時儘可能多地進行優化。 此解決方案看起來像'朋友'一樣混亂,因爲我必須將每個必需的函數放在Interface的構造函數中。 謝謝你的時間! –

+0

是的,但這個解決方案畢竟不需要虛擬功能。還要注意,對於在此解決方案中構造函數中傳遞的每個參數,您需要爲另一個解決方案中的基類聲明一個虛函數,所以它在這方面不會更糟。至於''friend'' - 那就是封裝的原子彈:-) –

1

如何使用虛函數和多態?

在您的子類中創建一個對象,並將其重新分配給接口類指針或引用。然後在你的接口類中創建一個純虛函數,並在你的子類中定義它。

+1

這是一個好主意,但是CRTP通常用於避免虛擬功能的成本。 –

+0

@AmiTavory這是我第一次聽說過CRTP的成語。我不認爲我能提供更多的幫助。但是,很高興知道CRTP消除了對v表的需求。 – Bryan

+0

(喜歡這個名字,順便說一句)確切地說,CRTP並不排除在所有情況下對v表的需求。 –