dynamic_cast失败

时间:2009-02-26 12:30:21

标签: c++ dynamic-cast

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

我在以下代码中对派生类执行基类对象的dynamic_cast:

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文件,则转换成功。

可能导致什么?

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

6 个答案:

答案 0 :(得分:7)

你在Base有任何虚拟功能吗?否则它将不起作用。如果没有别的,让它的dtor虚拟。

不知道其他人是否已经删除了他的答案,但我相信它有所不同:你是否正在从基地的构造函数中进行dynamic_cast?如果是这样,那将无效。编译器会认为Base是派生类型最多的类型,类似于调用虚函数时它最终调用Base的版本。

答案 1 :(得分:5)

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

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

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

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

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

编辑:查看更新的代码

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

但在看到代码后,我唯一能想到的是gcc(错误地)内联所有内容并且不会为Derived生成vtable。对于它的价值,这运行良好编译与gcc 4.0

3.1现在已经超过7岁......如果有任何升级的可能性,我会选择它。

答案 2 :(得分:3)

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

某些编译器(读取:gcc)查找第一个遇到的非内联虚拟方法体,并使用它来决定放置虚方法表的位置。如果.cpp文件中没有包含实体的任何虚方法,则不会创建虚方法表。

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

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

答案 3 :(得分:0)

你是用Visual C ++做的吗?我认为您必须在编译器设置中启用运行时类型信息(RTTI)才能生效。

如果我错了,请不要激怒我。我用了C ++已经有一段时间了!!!

答案 4 :(得分:0)

在查看代码时,我没有看到任何继承。你忘记那样做了吗?派生不是来自任何事物。

答案 5 :(得分:0)

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

编辑:仅供参考,修改后的代码可以正常使用g ++ 3.4.5