2014-02-18 29 views
0

說實話,我不喜歡虛擬調度,Interface類。出於這個原因,我想實現自己的類沒有任何基礎的抽象類。爲了形象,我正在實現MyCustomWidget,它的一些方法已經實現,其他方法沒有,因爲它不是必需的。在C++中實現條件虛擬方法11

// here is my custom widget class, which 'show' method is implemented, but 'close' method is not. 
struct MyCustomWidget 
{ 
    void show(){ std::cout << "Hey" << std::endl; } 
    //void close(){ std::cout << "Bye" << std::endl; } 
}; 

// here is your custom widget class, which 'show' is not implemented but 'close' is . 
struct YourCustomWidget 
{ 
    //void show(){} 
    void close(){ std::cout << "Bye" << std::endl;} 
}; 

// common widget class, which may stored within any custom widgets. 
struct Widget 
{ 
    Widget() = default; 

    template< typename CustomWidget > 
    void add(CustomWidget cw) 
    { 
     auto child = std::make_unique< proxy<CustomWidget> >(std::move(cw)) 
     childs.push_back(std::move(child)); 
    } 
    void show() 
    { 
     for(auto & e : childs) 
      e->show(); 
    } 
    void close() 
    { 
     for(auto& e : childs) 
      e->close(); 
    } 
private: 
    struct proxy_base 
    { 
     virtual void show() = 0; 
     virtual void close() = 0; 
     virtual ~proxy_base(){} 
    }; 

    template< typename CustomWidget > 
    struct proxy : public proxy_base 
    { 
     explicit proxy(CustomWidget cw_) : cw(std::move(cw_)) 
     {} 

     void show() override final 
     { // -------------->>>>>> (1) 
      // call cw.show() if cw has 'show' method, otherwise nothing. 
     } 
     void close() override final 
     {  /// ---------------->>>> (2) 
      // call cw.close if cw has a 'close' method, otherwise nothing. 
     } 

     CustomWidget cw; 
    }; 

std::vector< std::unique_ptr<proxy_base> >childs; 
}; 

int main() 
{ 
    Widget w; 
    w.add(MyCustomWidget()); 
    w.add(YourCustomWidget()); 

    w.show(); 
    //.... a lot of code 

    w.close(); 
} 

我的問題很簡單:我是如何實現(1)和(2)虛擬方法?

編輯:我看到那個問題已經被回答。讓我改變我的問題。問題2:(1)和(2)方法是'final'並且在基類中它們被聲明爲純虛擬的,對於這種情況編譯器可以優化虛擬表,並避免它? 我很喜歡GCC,CLang和Visual Studio 2013.

+0

可能重複[是否有可能寫一個C++模板來檢查函數的存在?(http://stackoverflow.com/questions/257288/is-it-possible-to-write -ac-template-to-check-for-a-functions-existence) – KeatsPeeks

+0

我認爲SFINAE成語可以很好地解決您的問題,請參閱我標記爲重複的問題的答案 – KeatsPeeks

+0

ouh,greate !!!謝謝。 – Khurshid

回答

3

你可以把這些在代理類的private部分:

template<typename T> 
auto show_helper(int) -> decltype(std::declval<T>().show(), void()) 
{ 
    cw.show(); 
} 

template<typename T> 
void show_helper(...) { } 

show稱他們是這樣的:

show_helper<CustomWidget>(0); 

第一個重載被實例化,只有在表達尾隨返回類型形成良好,即當T已得到show方法。

這被稱爲表達式SFINAE,並且比pmr的答案中的pre-C++ 11版本短得多。它也更加靈活,因爲它可以讓您更輕鬆地指定show的簽名。另一個答案可以給你積極的結果,只有發現你不能無需調用show。選擇你的毒藥。的

Live example.

+0

是的,在某些時候,我需要開始使用這種新技術。這只是我反思性地選擇較舊的那個。 – pmr

+0

非常好的解決方案!謝謝。 – Khurshid

1

你可以得到一個SFINAE特質類來檢查,然後用它來發送一個close_impl。或者,您也可以使用特質類與enable_if組合來選擇close的正確版本。

#include <iostream> 
#include <type_traits> 

template <typename T> 
class has_close 
{ 
    typedef char one; 
    typedef long two; 

    template <typename C> static one test(decltype(&C::close)) ; 
    template <typename C> static two test(...); 
public: 
    enum { value = sizeof(test<T>(0)) == sizeof(char) }; 
}; 

struct X { void close() {} }; 
struct X1 { }; 

template<typename T> 
struct XX { 
    T t; 

    void close() { 
    close_impl(std::integral_constant<bool, has_close<T>::value>{}); 
    } 

    void close_impl(std::true_type) { std::cout << "call close" << std::endl;t.close(); } 
    void close_impl(std::false_type) { std::cout << "no close" << std::endl;} 
}; 

int main() 
{ 
    XX<X> x; x.close(); 
    XX<X1> x1; x1.close(); 
    return 0; 
}