简体   繁体   English

在c ++ 11中实现条件虚拟方法

[英]implement virtual method conditional in c++11

To be honest, I dislike virtual dispatching, Interface class. 老实说,我不喜欢虚拟调度Interface类。 For that reason I want implement own classes without any base abstract class. 因此,我想实现自己的类而没有任何基本抽象类。 To be image, I am implementing MyCustomWidget and its some methods have been implemented, others no, because it's not necessary. 为了形象起见,我正在实现MyCustomWidget,并且已经实现了其中的一些方法,而没有实现,因为没有必要。

// 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();
}

My Question is simple: how me implement that (1) and (2) virtual methods ? 我的问题很简单:我如何实现(1)和(2)虚方法?

Edit: I see that question already has been answered. 编辑:我看到这个问题已经得到解答。 Let me change my question. 让我改变我的问题。 Q2: (1) and (2) methods are 'final' and in base class they were declared as pure virtual, for this situation compiler can optimize virtual table, and avoid it ? 问题2:(1)和(2)方法是“最终的”,并且在基类中将它们声明为纯虚拟的,对于这种情况,编译器可以优化虚拟表,并避免使用它? I'm interesting in GCC, CLang and Visual Studio 2013. 我对GCC,CLang和Visual Studio 2013感兴趣。

You can put these in the private section of proxy class: 您可以将它们放在代理类的private部分中:

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

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

and call them like this from show : 并从show这样称呼他们:

show_helper<CustomWidget>(0);

The first overload gets instantiated only if expression in trailing return type is well formed, that is, when T has got show method. 仅当尾随返回类型的表达式格式正确,即T具有show方法时,才会实例化第一个重载。

This is called expression SFINAE and is much shorter than pre-C++11 version from pmr's answer. 这称为表达式SFINAE,比pmr的答案比C ++ 11之前的版本短得多。 It's also more flexible as it lets you specify the signature of show more easily. 它还使您可以更轻松地指定show的签名,因此更加灵活。 The other answer can give you positive result only to discover that you can't call show without arguments. 另一个答案只能给您带来积极的结果,就是发现您无法在没有参数的情况下调用show Pick your poison. 选择你的毒药。

Live example. 现场示例。

You can get a SFINAE traits class to check and then use this to dispatch on an close_impl . 您可以获取SFINAE traits类进行检查,然后使用它来对close_impl进行调度。 Alternatively, you also use the traits class in combination with enable_if to chose the right version of close . 另外,您也可以将traits类与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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM