`dynamic_cast`从Base到Derived

时间:2012-04-02 09:15:13

标签: c++ dynamic-cast

是的,我知道如果dynamic_cast不是多态的,那么使用Base进行转发就无法编译,但我的问题与此无关。

class Base {
    public:
        virtual void bar()
        {
            cout << "bar\n";
        }
};

class Derived: public Base {
    public:
        void foo()
        {
            cout << "foo\n";
        }
};

int main()
{
    Base *pb;
    Derived *pd;

    pb = new Derived;  //Base* points to a Derived object
    pd = dynamic_cast<Derived*>(pb); 
    pd->foo();  //outputs foo

    pb = new Base;  //Base* points to a Base object
    pd = dynamic_cast<Derived*>(pb);  
    pd->foo();  //outputs foo, too. Why?
}

我想当pb = new Derived;时,pb实际上指向Derived对象位于堆中。在pd = dynamic_cast<Derived*>(pb);之后,pd也指向该Derived个对象,因此pd->foo()应该没问题。

但是当pb = new Base;pb指向堆中的Base对象时,pd = dynamic_cast<Derived*>(pb);之后,pd->foo()怎么办? dynamic_cast是否将堆中的Base对象转换为Derived对象?

4 个答案:

答案 0 :(得分:17)

在C ++中,类的每个实例都有自己的数据类型版本,但所有类在内存中共享相同的函数(除了内联函数)。在你的情况下,当你说出这样的话:

pd->foo();

你实际上是在调用Derived::foo,它是内存中的一个函数,编译器知道它在哪里。问题是,它完全不依赖于pd。但是,如果您有这样的事情:

class Derived : public Base {
    private:
        int a;

    public:
        Derived() { a = 100; }

        void foo() {
            std::cout<<a<<std::endl;
        }
 };

然后,pd->foo()将导致分段错误。在这里,您的动态广告已失败,并且在调用Derived::foo时,会将0作为this对象传递。在前一种情况下很好,因为this对象从未使用过。但是,在第二种情况下,它被使用,因此导致分段错误。

答案 1 :(得分:7)

在您的foo中,您无法访问this,在这种情况下应为NULL。这就是dynamic_cast在无法完成演员表时返回的内容。

基本上你在这里的“未定义行为”区域。

答案 2 :(得分:6)

您遇到了未定义的行为。您应该检查dynamic_cast的返回类型。

pd = dynamic_cast<Derived*>(pb);  

返回null,并在NULL指针上调用函数。任何事情都可能发生。

答案 3 :(得分:1)

在尝试使用之前,请务必先检查演员表是否成功。我猜它是使用铸造的优势。你可以检查一下是否成功。

pd = dynamic_cast<Derived*>(pb);  
if(pd!=NULL)
  pd->foo();

如果转换失败pd的值为NULL。除非您确定它具有值,否则请勿使用pd。然后只引用它