【问题标题】:dynamic_cast failsdynamic_cast 失败
【发布时间】:2009-02-26 12:30:20
【问题描述】:

我有一个基类和一个派生类。每个类都有一个 .h 文件和一个 .cpp 文件。

我正在以下代码中将基类对象动态转换为派生类:

h 文件:

class Base
{
  public:
    Base();
    virtual ~Base();
};

class Derived : public Base
{
  public:
    Derived(){};
    void foo();
};

class Another
{
  public:
    Another(){};
    void bar(Base* pointerToBaseObject);
};

cpp 文件:

Base::Base()
{
    //do something....
}
Base::~Base()
{
    //do something....
}
void Derived::foo()
{
    Another a;
    a.bar(this);
}
void Another::bar(Base* pointerToBaseObject)
{
    dynamic_cast<Derived*>(pointerToBaseObject)
}

由于某种奇怪的原因,转换失败(返回 NULL)。但是,如果我将 Derived 类的构造函数的实现从 .h 移动到 .cpp 文件,则转换成功。

是什么原因造成的?

编译器是 gcc 3.1,在 Linux-SUSE 上。顺便说一句,我只在这个平台上看到这种行为,并且相同的代码在 Visual Studio 中运行良好。

【问题讨论】:

  • 可能是 gcc 3.1 的错误?尝试“-fdump-class-hierarchy”选项,看看它是否为你的两个类创建了一个 vtable

标签: c++ dynamic-cast


【解决方案1】:

Base 中有虚函数吗?否则它将无法正常工作。如果不出意外,请将其 dtor 设为虚拟。

不知道其他人是否已经问过删除了他的答案,但我相信这是不同的:你是在做基础构造函数的 dynamic_cast 吗?如果是这样,那就行不通了。编译器会认为 Base 是派生最多的类型,类似于调用虚函数并最终调用 Base 的版本。

【讨论】:

  • 我在 Base 中有虚函数。
【解决方案2】:

如果您在基类中有一个虚函数(正如 litb 所指出的),那么发布的代码应该不会失败。

但我相信每个当前的编译器都会生成一个“基类不是多态”的错误,如果你没有的话,那么这可能不会是问题。

我唯一能想到的是,由于一些奇怪的错误,所有内容都被内联并且没有生成任何 vtable。但如果你将构造函数放在 C++ 文件中,编译器会决定不内联所有内容,从而触发 vtable 的创建,从而使你的强制转换工作。

但这是非常疯狂的猜测,我认为任何编译器都不会出现这样的错误(?)

如果您想要一个明确的答案,请发布更多代码。以及使用的编译器/平台。

编辑:查看更新的代码

我认为你至少应该派生自 Base ;)(我想这是一个错字)

但是在看到代码之后,我唯一能想到的是 gcc(错误地)内联了所有内容并且没有为 Derived 生成 vtable。值得一提的是,它使用 gcc 4.0 编译运行良好

3.1 到现在已经 7 年多了……如果有升级的可能我会去。

【讨论】:

    【解决方案3】:

    将析构函数设为虚拟,并将其(或至少一种虚拟方法)置于 .cpp 文件中。

    一些编译器(读作:gcc)寻找第一次遇到的非内联虚方法体,并用它来决定把虚方法表放在哪里。如果您在 .cpp 文件中没有任何带有主体的虚拟方法,则不会创建虚拟方法表。

    您必须至少有一个虚拟方法才能使 dynamic_cast 工作。动态转换使用表来计算类型信息,如果没有虚方法,则不创建表。

    如果你有一个你希望被子类化的类并且它有一个析构函数,或者如果这个类有任何实例变量是带有析构函数的类,那么你真的希望你的析构函数是虚拟的(即使它有一个空的身体)。否则子类实例不会发生您期望的清理。

    【讨论】:

      【解决方案4】:

      您是否在 Visual C++ 中执行此操作?我认为您过去必须在编译器设置中启用运行时类型信息 (RTTI) 才能使其正常工作。

      如果我说错了,请不要喷我。好久没用C++了!!!

      【讨论】:

        【解决方案5】:

        在查看您的代码时,我没有看到任何继承。你忘了这样做吗? Derived 不是从任何东西派生的。

        【讨论】:

          【解决方案6】:

          在您发布的代码中,Derived 不是从 Base 派生的。

          编辑:仅供参考,修改后的代码适用于 g++ 3.4.5

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-06-10
            • 2011-07-04
            • 2017-01-11
            • 2012-12-16
            • 1970-01-01
            • 2018-11-26
            • 1970-01-01
            • 2020-08-21
            相关资源
            最近更新 更多