dynamic_cast和static_cast区别

 

传统的A* a = (A*)p强制类型转换相当于static_cast,得到的总是一个内存地址,而dynamic_cast则更安全,转换失败会得到NULL。

dynamic_cast和static_cast区别用如下例子程序非常容易理解:

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

class A : public Base
{
};

class B : public Base
{
};

int main()
{
    Base *a = new A();
    Base *b = new B();
    if (A *p = dynamic_cast<A*>(b)) {
        cout << "A instance" << endl;
    }

    if (B *p = dynamic_cast<B*>(a)) {
        cout << "B instance" << endl;
    }

    return 0;
}

上面例子不会打印出任何内容,将dynamic_cast后的a和b进行掉换就能正确打印了。

改成static_cast也是能正确打印的,但会是危险的,因为明显a强制转换成了B*指针,而b强制转换成了A*指针:

int main()
{
    Base *a = new A();
    Base *b = new B();
    if (A *p = static_cast<A*>(b)) {
        cout << "A instance" << endl;
    }

    if (B *p = static_cast<B*>(a)) {
        cout << "B instance" << endl;
    }

    return 0;
}

有了dynamic_cast这个特性,我们就可以用来进行类型识别了,将基类指针依次尝试转换成各种子类指针。

特别注意:基类Base里必须要有虚函数,任何虚函数都可以,不一定要是虚析构函数。否则编译会不过:

error: cannot dynamic_cast ‘b’ (of type ‘class Base*’) to type ‘class A*’ (source type is not polymorphic)
     if (A *p = dynamic_cast<A*>(b)) {

可见虚函数表,即vtable,里有存储类继承关系信息。获取vtable信息,可以使用如下命令:

g++ -fdump-class-hierarchy test.cpp  -std=c++11

 可查生成的文件test.cpp.002t.class,里面有简单的类信息和vtable信息,截取如下:

Vtable for A
A::_ZTV1A: 3u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI1A)
16    (int (*)(...))Base::foo

Class A
   size=8 align=8
   base size=8 base align=8
A (0x0x7f3a51579c30) 0 nearly-empty
    vptr=((& A::_ZTV1A) + 16u)
  Base (0x0x7f3a513ab000) 0 nearly-empty
      primary-for A (0x0x7f3a51579c30)

 

发表于 2015年11月05日 10:50   评论:0   阅读:2375  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo