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

implement virtual method conditional in c++11

本文关键字:方法 条件 虚拟 实现 C++11      更新时间:2023-10-16

说实话,我不喜欢虚拟调度,接口类。出于这个原因,我希望在没有任何基本抽象类的情况下实现自己的类。为了图像,我正在实现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();
}

的问题很简单:我如何实现(1)和(2)虚拟方法?

编辑:我看到这个问题已经得到了回答。让我改变我的问题。Q2:(1)和(2)方法是"最终的",在基类中它们被声明为纯虚拟,在这种情况下,编译器可以优化虚拟表,并避免它?我对GCC,CLang和Visual Studio 2013很有趣。

您可以将这些放在代理类的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的答案中的C++11之前的版本短得多。它也更加灵活,因为它可以让您更轻松地指定show的签名。另一个答案可以给你积极的结果,只是发现你不能在没有参数的情况下调用show。选择你的毒药。

活生生的例子。

您可以获取 SFINAE 特征类进行检查,然后使用它来调度close_impl。或者,您也可以将 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;
}