【问题标题】:Multiple inheritance of interfaces in C++C++中接口的多重继承
【发布时间】:2013-02-07 02:41:42
【问题描述】:

我有一个对象接口和一个派生对象可能想要支持的开放式接口集合。

// An object
class IObject
{
    getAttribute() = 0
}

// A mutable object
class IMutable
{
    setAttribute() = 0
}

// A lockable object 
class ILockable
{
    lock() = 0
}

// A certifiable object 
class ICertifiable
{
    setCertification() = 0
    getCertification() = 0
}

一些派生对象可能如下所示:

class Object1 : public IObject, public IMutable, public ILockable {}
class Object2 : public IObject, public ILockable, public ICertifiable {}
class Object3 : public IObject {}

这是我的问题:有没有一种方法可以编写只采用这些接口的某些组合的函数?例如:

void doSomething(magic_interface_combiner<IObject, IMutable, ILockable> object);

doSomething( Object1() )  // OK, all interfaces are available.
doSomething( Object2() )  // Compilation Failure, missing IMutable.
doSomething( Object3() )  // Compilation Failure, missing IMutable and ILockable.

我发现最接近的是 boost::mpl::inherit。我取得了一些有限的成功,但它并没有完全满足我的需要。

例如:

class Object1 : public boost::mpl::inherit<IObject, IMutable, ILockable>::type
class Object2 : public boost::mpl::inherit<IObject, ILockable, ICertifiable>::type
class Object3 : public IObject

void doSomething(boost::mpl::inherit<IObject, ILockable>::type object);

doSomething( Object1() )  // Fails even though Object1 derives from IObject and ILockable.
doSomething( Object2() )  // Fails even though Object2 derives from IObject and ILockable.

我认为类似于 boost::mpl::inherit 的东西可能会生成一个具有所提供类型的所有可能排列的继承树。

我也很好奇解决这个问题的其他方法。理想情况下,编译时检查而不是运行时检查(即没有 dynamic_cast)。

【问题讨论】:

  • 您是指 AND 组合还是 OR 组合?
  • 如果我错了请纠正我,但是你的抽象函数不需要标记virtual以及=0吗?
  • 我认为使用模板是错误的答案?
  • 在新的 C++11 标准中,有很多新的type traits,例如std::is_base_of。可以与std::enable_if结合使用。
  • 为什么需要doSomething 才能同时通过这么多接口?您的问题可能暗示存在设计缺陷。

标签: c++ inheritance interface multiple-inheritance boost-mpl


【解决方案1】:

也许这不是最优雅的方式,因为它是用 C++03 语法完成的

template <typename T, typename TInterface>
void interface_checker(T& t)
{
    TInterface& tIfClassImplementsInterface = static_cast<TInterface&>(t);
}

这是给你精神的绝招。 现在在你的情况下:

template <typename T, typename TInterface1, typename TInterface2, typename TInterface3 >
void magic_interface_combiner(T& t)
{
    TInterface1& tIfClassImplementsInterface = static_cast<TInterface1&>(t);
    TInterface2& tIfClassImplementsInterface = static_cast<TInterface2&>(t);
    TInterface3& tIfClassImplementsInterface = static_cast<TInterface3&>(t);
}

我想使用 C++11 类型特征可以做得更智能。

【讨论】:

    【解决方案2】:

    您应该使用static_assert 来检查函数中的类型:

    #include <type_traits>
    
    template< typename T >
    void doSomething( const T& t )
    {
       static_assert( std::is_base_of<IObject,T>::value, "T does not satisfy IObject" );
       static_assert( std::is_base_of<IMutable,T>::value, "T does not satisfy IMutable" );
    
       // ...
    }
    

    这会给你很好的错误信息,告诉你哪些接口不满意。如果你需要重载函数并且有一个只适用于某个接口组合的版本,你也可以使用enable_if

    #include <type_traits>
    
    template< typename T, typename... Is >
    struct HasInterfaces;
    
    template< typename T >
    struct HasInterfaces< T > : std::true_type {};
    
    template< typename T, typename I, typename... Is >
    struct HasInterfaces< T, I, Is... >
      : std::integral_constant< bool,
          std::is_base_of< I, T >::value && HasInterfaces< T, Is... >::value > {};
    
    template< typename T >
    typename std::enable_if< HasInterfaces< T, IObject, IMutable >::value >::type
    doSomething( const T& t )
    {
      // ...
    }
    

    当接口要求不满足时,会使函数从重载集中消失

    【讨论】:

    【解决方案3】:

    您可以使用递归可变参数继承编写接口检查类:

    template<typename... Interfaces>
    struct check_interfaces;
    template<>
    struct check_interfaces<> {
       template<typename T> check_interfaces(T *) {}
    };
    template<typename Interface, typename... Interfaces>
    struct check_interfaces<Interface, Interfaces...>:
    public check_interfaces<Interfaces...> {
       template<typename T> check_interfaces(T *t):
          check_interfaces<Interfaces...>(t), i(t) {}
       Interface *i;
       operator Interface *() const { return i; }
    };
    

    例如:

    struct IObject { virtual int getAttribute() = 0; };
    struct IMutable { virtual void setAttribute(int) = 0; };
    struct ILockable { virtual void lock() = 0; };
    
    void f(check_interfaces<IObject, IMutable> o) {
       static_cast<IObject *>(o)->getAttribute();
       static_cast<IMutable *>(o)->setAttribute(99);
    }
    
    struct MutableObject: IObject, IMutable {
       int getAttribute() { return 0; }
       void setAttribute(int) {}
    };
    
    struct LockableObject: IObject, ILockable {
       int getAttribute() { return 0; }
       void lock() {}
    };
    
    int main() {
       f(new MutableObject);
       f(new LockableObject);  // fails
    }
    

    请注意,check_interfaces 每个检查的接口占用一个指针;这是因为它对实际参数的声明类型执行类型擦除。

    【讨论】:

      【解决方案4】:

      只是为了让你稍微了解一下 C++11:

      没有递归的单一类型:

      template <typename... Ts>
      class magic_interface_combiner {
        typedef std::tuple<Ts*...> Tpl;
        Tpl tpl;
      
        template <typename T, int I>
        T *as_(std::false_type)
        {
          static_assert(I < std::tuple_size<Tpl>::value, "T not found");
          return as_<T, I+1>(std::is_same<T, typename std::tuple_element<I+1, Tpl>::type>{});
        }
        template <typename T, int I>
        T *as_(std::true_type) { return std::get<I>(tpl); }
      
      public:
        template <typename T>
        magic_interface_combiner(T * t) : tpl(static_cast<Ts*>(t)...) {}
      
        template <typename T> T * as() { return as_<T, 0>(std::false_type{}); }
      };
      
      // no template    
      void doSomething(magic_interface_combiner<IObject, IMutable, ILockable> object)
      {
      }
      

      两种类型但没有递归:

      template <typename T>
      class single_interface_combiner {
        T *p;
      public:
        single_interface_combiner(T *t) : p(t) {}
        operator T* () { return p; }
      };
      
      template <typename... Ts>
      struct magic_interface_combiner : single_interface_combiner<Ts>... {
        template <typename T>
        magic_interface_combiner(T* t) : single_interface_combiner<Ts>(t)... {}
      
        template <typename T>
        T * as() { return *this; }
      };
      

      【讨论】:

        【解决方案5】:

        使用std::enable_ifstd::is_base_of 的解决方案:

        #include <type_traits>
        
        // An object
        struct IObject
        {
            virtual void getAttribute() = 0;
        };
        
        // A mutable object
        struct IMutable
        {
            virtual void setAttribute() = 0;
        };
        
        // A lockable object 
        struct ILockable
        {
            virtual void lock() = 0;
        };
        
        // A certifiable object 
        struct ICertifiable
        {
            virtual void setCertification() = 0;
            virtual void getCertification() = 0;
        };
        
        struct Object1 : public IObject, public IMutable, public ILockable
        {
            void getAttribute() {}
            void setAttribute() {}
            void lock() {}
        };
        
        struct Object2 : public IObject, public ILockable, public ICertifiable
        {
            void getAttribute() {}
            void lock() {}
            void setCertification() {}
            void getCertification() {}
        };
        
        struct Object3 : public IObject
        {
            void getAttribute() {}
        };
        
        template<typename T>
        void doSomething(
            typename std::enable_if<
                std::is_base_of<IObject, T>::value &&
                std::is_base_of<IMutable, T>::value &&
                std::is_base_of<ILockable, T>::value,
                T>::type& obj)
        {
        }
        
        int main()
        {
            Object1 object1;
            Object2 object2;
            Object3 object3;
        
            doSomething<Object1>(object1);  // Works
            doSomething<Object2>(object2);  // Compilation error
            doSomething<Object3>(object3);  // Compilation error
        }
        

        【讨论】:

          猜你喜欢
          • 2022-08-12
          • 2012-05-13
          • 1970-01-01
          • 2013-11-25
          • 1970-01-01
          • 2013-03-31
          • 2011-03-02
          • 1970-01-01
          • 2017-03-24
          相关资源
          最近更新 更多