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

Posted

技术标签:

【中文标题】如何正确检查对象是不是实现接口【英文标题】:How to correctly check if an object implements an interface如何正确检查对象是否实现接口 【发布时间】:2015-07-07 17:34:45 【问题描述】:

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

为此,让我的项目(从 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 孩子身上。我没有崩溃

QWidget::insertAction: Attempt to insert null action

正是测试if(item1 == NULL) 给出了该信息...

如何正确检查我的物品是否实现了SomeInterface

注意:item 不能为空。

【问题讨论】:

请注意,如果item 为空,那么您将在item1 上调用function2(),这也将为空。 item 不能为空 你遇到什么样的崩溃?您是否尝试测试 item 是否为空?这似乎是它崩溃的唯一方法。 dynamic_cast 是测试对象是否已实现接口的常规方法。 在小部件本身上修复某些内容后,我不再收到错误。我无法解释为什么之前取消测试也没有给出错误...谢谢您查看我的问题,但似乎我根据症状解决了错误的问题 【参考方案1】:

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

【讨论】:

【参考方案2】:

一个简单的通用模板可以使代码更具可读性和更易于实现。

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 ) ) ...

是一个宏,用于在运行时检查接口合规性(如果需要)。 但是,请谨慎使用。 如果您在很长一段时间内不止一次这样做,您的代码很可能需要重构。

【讨论】:

【参考方案3】:

那么简单的事情呢:

class SomeInterface

    virtual void function2() = 0;
    virtual qint32 role() =0;
;

并为自定义行为返回不同的 int ?

【讨论】:

这没有回答问题,并引入了对启动幻数的依赖。

以上是关于如何正确检查对象是不是实现接口的主要内容,如果未能解决你的问题,请参考以下文章

检查值是不是实现接口的说明

检查物品是不是已被处置的正确方法

如何检查对象是不是实现了接口? [复制]

该对象的 Typescript 接口是不是正确?

Angular 7检查JSON解析是不是返回特定对象的正确方法[关闭]

effectiveJava覆盖equals方法