如何正确检查对象是不是实现接口
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 ?
【讨论】:
这没有回答问题,并引入了对启动幻数的依赖。以上是关于如何正确检查对象是不是实现接口的主要内容,如果未能解决你的问题,请参考以下文章