2017-02-25 36 views
3

我喜歡NVI idiom如何解決使用CRTP實現破壞強封裝規則?

但有時我想從NVI成語中減少vftable成本。 然後我嘗試將CRTP應用於NVI,如下所示。

template<typename E> 
class unary_interface { 
public: 
    virtual ~unary_interface() = default; 

public: 
    double operator()(const double x) const 
    { 
     return static_cast<const E&>(*this).apply(x); //occurs compile error!!! 
    } 
}; 

class square : public unary_interface<square> { 
private: 
    double apply(const double x) const 
    { 
     return x * x; 
    } 
}; 

但出現此代碼編譯錯誤。

如果我在私有領域中將應用函數改爲public,則封裝被破壞。 我有一個不透明的別名解決這個問題的想法如下。

template<typename E> 
class unary_interface { 
public: 
    virtual ~unary_interface() = default; 

protected: 
    class input_type { 
    public: 
     explicit input_type(const double x) : _x(x) {} 
     operator double() const 
     { 
      return _x; 
     } 
    private: 
     const double _x; 
    }; 

public: 
    double operator()(const double x) const 
    { 
     return static_cast<const E&>(*this).apply(input_type(x)); 
    } 
}; 

class square : public unary_interface<square> { 
    using base_type = unary_interface<square>; 
public: 
    double apply(const base_type::input_type& d) const 
    { 
     const double x = static_cast<const double>(d); 
     return x * x; 
    } 
}; 

本設計禁止訪問除unary_interface的operator()之外的apply函數。

乍一看「應用函數」暴露給用戶代碼,但apply函數僅接受保護字段中的unary_interface上定義的受保護的不透明別名類型。 我認爲這種組合非常好,通過保持強大的封裝來降低虛擬功能成本。

這個想法有什麼缺點,我找不到,你有這個設計的具體名稱?

回答

3

但是這段代碼發生編譯錯誤。
...
乍一看「應用函數」暴露給用戶代碼,但應用函數只接受在受保護字段的unary_interface上定義的受保護的不透明別名類型。我認爲這種組合非常好,並且通過保持強大的封裝來降低虛擬功能成本。

可以輕鬆解決你的強大的封裝採用friend困境(在這種情況下,它不會附帶任何negative consequences):

class square : public unary_interface<square> { 
    friend class unary_interface<square>; // <<< 
    double apply(const double x) const // <<< Keep apply() private 
    { 
     return x * x; 
    } 
}; 

無需使用protected input_type偏離。請參閱Live Demo

這個想法有什麼缺點,我找不到,你有這個設計的具體名稱?

好,缺陷是過於複雜的情況,並提出最終用戶,他們實際上並不能使用公共功能。

我不知道反模式已被識別和命名。通過聲明在公共API處無法有效使用的承諾,可能會錯誤地使用public接口區域。

+0

感謝您的回覆。我同意複雜的設計是不好的。起初,我有使用朋友的想法。我錯誤地認爲朋友總是被棄用,但是我知道朋友是在特定情況下的高效工具,這要歸功於你。 –

+0

@YusukeMori很樂於助人。您可能需要爲該問題找到更好的標題。但總的來說,這是相當有用的。當你公開'private'內部類_handles_時,可以使用'public''API中的'auto'。 –