2014-02-18 4 views
0

Честно говоря, мне не нравится виртуальная диспетчеризация, класс интерфейса. По этой причине я хочу реализовать собственные классы без базового абстрактного класса. Чтобы быть образным, я реализую 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) виртуальные методы?

Редактировать: Я вижу, что на этот вопрос уже был дан ответ. Позвольте мне изменить свой вопрос. Q2: (1) и (2) методы являются «окончательными», а в базовом классе они объявлены как чистые виртуальные, для этой ситуации компилятор может оптимизировать виртуальную таблицу и избежать ее? Я заинтересован в GCC, CLang и Visual Studio 2013.

+0

возможно дубликат [Можно ли написать шаблон C++ для проверки существования некоторой функции в?] (Http://stackoverflow.com/questions/257288/is-it-possible-to-write -ac-template-to-check-for-a-functions-существования) – 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 и намного короче, чем версия pre-C++ 11 из ответа pmr. Это также более гибко, так как позволяет более легко определить подпись 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; 
}