【问题标题】:c++ checking at runtime if object implements interfacec ++在运行时检查对象是否实现接口
【发布时间】:2012-05-01 16:31:18
【问题描述】:

我前段时间问过这些问题: Multiple inheritance casting from base class to different derived class

但我仍然不确定我是否理解答案。 问题是:下面的代码有效吗?

#include <iostream>

using namespace std;

struct Base
{
    virtual void printName() 
    {
        cout << "Base" << endl;
    }
};

struct Interface
{
    virtual void foo()
    {
        cout << "Foo function" << endl;
    }
};

struct Derived : public Base, public Interface
{
    virtual void printName()
    {
        cout << "Derived" << endl;
    }
};

int main(int argc, const char * argv[])
{
    Base *b = new Derived();
    Interface *i = dynamic_cast<Interface*>(b);
    i->foo();

    return 0;
}

代码按我的意愿工作。但据我了解,根据前面的问题,它不应该。所以我不确定这样的代码是否有效。谢谢!

【问题讨论】:

  • 您上一个问题的答案中的 cmets 确实解释了 dynamic_cast 将适用于您的情况。

标签: c++ casting multiple-inheritance


【解决方案1】:

这是有效的代码。

为什么?
因为dynamic_cast 告诉您所指向的对象是否实际上是您要转换的类型。
在这种情况下,实际指向的对象是Derived 类型,Derived 类型的每个对象也是Interface 类型(因为Derived 继承自Interface),因此dynamic_cast有效且有效。

【讨论】:

  • 和我之前的问题有什么不同? (实在看不懂)
  • @Andrew:没有区别,Emilio Garavaglia 在上一个问题中给了你同样的答案。
  • @Andrew: dynamic_cast 仅当您在类中至少有一个 virtual 方法(又名多态类)时才有效。请参阅this。您之前的示例没有任何 virtual方法,因此无法使用dynamic_cast
  • 我是否正确理解 dynamic_cast 中涉及的所有类都必须是多态的?
  • @Andrew:是的。如果基类是多态的,那么所有派生类也将是多态的。你只需要在基类中有一个virtual 方法,它甚至可以是一个析构函数。
【解决方案2】:

只要涉及的类至少有一个虚拟方法(可以是虚拟析构函数),就可以使用dynamic_cast 既正确又可以在符合标准的编译器上工作。

static_cast 不同,dynamic_cast 可以允许对类型信息进行运行时检查。但是,这也意味着它可能会失败,并在使用它来转换指针时返回NULL。如果有任何可能不成功,则应检查转换结果。

在您问的上一个问题中,这些类没有任何虚拟方法,因此无法工作,因为 dynamic_cast 不能用于此类。

【讨论】:

    【解决方案3】:

    如果dynamic_cast成功,那么它是有效的。它已经在运行时执行了类型安全检查。

    【讨论】:

    • 虽然在这种情况下恰巧是这样,但我不喜欢开创“如果它有效,它就是正确的”的先例。
    • 好吧,因为它是dynamic_cast,这就是争论。我不想重新解释关于 SO 的 10 多个众所周知的问题中出现的内容
    • @UmNyobe:OP 遇到的问题是为什么会起作用?答案不是因为dynamic_cast 这么说。他已经知道dynamic_cast 是这么说的(OP 提供了一个制作精良的示例代码来演示它)真正的问题是为什么dynamic_cast 有效?
    【解决方案4】:

    考虑以下几点:

    Base *b = new B();
    Interface *i = dynamic_cast<Interface *>( b );
    

    这应该有效吗?不。为什么,因为BaseInterface 彼此不相关。但是,在指向Base 的指针指向同样从Interface 派生的对象的特殊情况下,您可以强制转换(阅读:诱使编译器将对象视为Interface 类型)@987654327 @ 指针并进一步使用dynamic_cast 运算符的结果。

    【讨论】:

      【解决方案5】:

      您的代码是有效的,因为标准在 5.2.7 第 4 段(C++ 2003 标准)中这样说:

      运行时检查逻辑执行如下:

      ——如果在 v 指向(引用)的最派生对象中,v 指向(引用)一个 T 对象的公共基类子对象,并且如果只有一个 T 类型的对象从该子对象派生-v 指向(引用)的对象,结果是指向该 T 对象的指针(左值引用)。

      — 否则,如果 v 指向(引用)最派生对象的公共基类子对象,并且最派生对象的类型具有类型为 T 的明确且公共的基类,则result 是指向最派生对象的 T 子对象的指针(左值引用)。

      ——否则,运行时检查失败。

      注意在运行时检查中使用“最衍生对象”。在您的示例中,Base *b 对象的“最衍生对象”是 Derived 对象。由于Derived 类公开继承自BaseInterface,因此在这种特殊情况下,Base* 对象可以转换为Interface*

      【讨论】:

        猜你喜欢
        • 2016-02-21
        • 1970-01-01
        • 2012-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多