如何正确检查对象是否实现了接口

How to correctly check if an object implements an interface

本文关键字:实现 接口 是否 对象 何正确 检查      更新时间:2023-10-16

我想为某些对象实现自定义行为。

为此,让我的项目(从QGraphicsItem继承)实现一些接口。

class SomeParentItem 
{ 
    SomeParentItem(bool x) { x = true; } 
    void function1() {}
};
class SomeInterface
{
    virtual void function2() = 0;
};
class XYZItem : public QGraphicsXYZItem, public SomeParentItem, public SomeInterface
{
    XYZItem(bool x):SomeParentItem(x) {}
    virtual void function2() { x = false; }
};
class MPQItem : public QGraphicsMPQItem, public SomeParentItem
{
    MPQItem (bool x):SomeParentItem(x) {}
};

从外面看,我认为我只是做了

SomeInterface* item1 = dynamic_cast<SomeInterface*>(item);
if(item1 == NULL)
    item->function1(); 
else
    item1->function2();  

不幸的是这个崩溃了…通常…所以我创建了一个旗子来测试,如果旗子是真的,只有那时才敢投射。

但我一直在想,它不应该崩溃。所以我鼓起勇气再次尝试,这次是在一个QWidget子程序中。不是crash而是

QWidget::insertAction: Attempt to insert null action

是测试if(item1 == NULL)给出了这个消息…

如何正确检查我的项目是否实现了SomeInterface ?

备注:item不能为空。

可能有一个编译器开关禁用运行时类型信息,在这种情况下,它将解释行为。否则item1只能是非空的,如果dynamic_cast有效

一个简单的泛型模板可以使代码更容易读,更容易实现。

template < class T > 
        bool is_SomeParentItem( T& P)                                                                                                                                                                      
        {                                                                                                                                                                                             
          if ( dynamic_cast<SomeParentItem*>(&P) ) 
              return true;                                                                                                                                             
          else 
              return false;                                                                                                                                                                               
        }
template < class T > 
        bool is_SomeInterface( T& I)                                                                                                                                                                      
        {                                                                                                                                                                                             
          if ( dynamic_cast<SomeInterface*>(&I) ) 
              return true;                                                                                                                                             
          else 
              return false;                                                                                                                                                                               
        }
template < class T >
    void function( T& X)
      {
         if ( isSomeInterface(X) )
         { 
             dynamic_cast<SomeInterface*>(&X)->function2();
             return;
         }
         if ( isSomeParentItem(X) )
             dynamic_cast<SomeParentItem*>(&X)->function1();
      } 

您需要第二个函数模板来避免尝试调用在不实现它的类上使用function2。如果您尝试这样做:

 if ( isSomeInterface(instance) ) instance.function2(); 

上没有实现function2的类,编译器将执行因为它不能绑定到该实例的function2,也就是说正确,但不直观,因为它看起来不会从左到右逻辑调用。然而,编译器无法在编译时知道isSomeInterface将返回什么。

这种技术被许多人认为不是一种"好风格"的编程,因为它可能导致c++面条和代码膨胀,并且变得难以维护和调试。dynamic_cast通常用于区分类层次结构中的同名函数,特别是基类和子类方法,以及在方法签名重叠的多重继承情况下,确定地为情况选择正确的方法。

    // safe implements                                                                                                                                                                            
#define implements( C, I ) (    __extension__ ({                                                                                                                                             
        static bool impl=(dynamic_cast<I*>(&C))? true : false;                                                                                                                               
        impl;                                                                                                                                                                                
      })) 
     if ( implements( instance, SomeInterface ) ) ...
如果需要,

是一个宏,用于在运行时检查接口遵从性。但是,要节约使用。如果你在一段时间内不止一次这样做,你的代码很可能需要重构

这样简单:

class SomeInterface
{
    virtual void function2() = 0;
    virtual qint32 role() =0;
};

和返回一个不同的int自定义行为?