dynamic_cast理解

时间:2014-03-08 20:09:46

标签: c++ class inheritance dynamic-cast

我最近开始使用dynamic_cast和static_cast。我确实理解了static_cast中发生的事情,但没有理解dynamic_cast中发生的情况。我所知道的最多的是static_cast可用于转换数据类型,不检查编译时但dynamic_cast会检查。我也使用动态强制转换编写了代码,但我不确定它们是如何相关的。 这是我的代码

#include <iostream>
using namespace std;

class Base{
public:
    virtual void setting(){
        cout << "Hello, I am a function from the base class" << endl;
    }
    virtual void say(){
        cout << "Base class says hi" << endl;
    }
};

class Child:public Base{
public:
    void setting(){
        cout << "Hello, I am a function from the child class" << endl;
    }
    void say(){
        cout << "Child class says hi" << endl;
    }
};

class Child2:public Base{
public:
    void setting(){
        cout << "Hello, I am a function from the child2 class" << endl;
    }
    void say(){
        cout << "Child class says Wazuppppp" << endl;
    }
};
void start(Base* bp){ //here is where I get confused
    Child* it_is_Child= dynamic_cast<Child*>(bp);
    if(it_is_Child){
        it_is_Child->say();
        it_is_Child->setting();
    }
    Child2* it_is_child2= dynamic_cast<Child2*>(bp);
    if(it_is_child2){ //then
        it_is_child2->say();
        it_is_child2->setting();
    }
};

int main(){
    Child cp1;
    Child2 cp2;
    start(&cp2);
    cout << endl;
    start(&cp1);
    system("pause");


    return 0;
 }

混淆是,如何将Child cp1和Child2 cp2与启动功能相关联,以及它们如何工作。另外,编译器如何决定选择哪一个。

3 个答案:

答案 0 :(得分:3)

如果关联的类不相关(其中一个是从另一个继承的,或者两者都是从一个共同的祖先继承),

static_cast将在编译期间生成错误。

如果转换类不是转换对象的确切类,

dynamic_cast将在运行时返回空指针。

为了使dynamic_cast起作用,转换类必须至少声明一个虚函数。这是因为dynamic_cast使用转换对象的V-Table指针,并且只有当对象声明虚函数时,对象才有V-Table指针。

例如,Child* it_is_Child = dynamic_cast<Child*>(bp)场景是:

if (bp->__vfptr == Child::vftable)
    return (Child*)bp;
return nullptr;

请注意,在某些编译器上,您还需要在项目设置中启用RTTI。

答案 1 :(得分:0)

决定哪一个不是编译器。使用RTTI,编译器在Child对象内添加一些记录对象实际类的额外信息(另一个隐式属性)。可以使用typeid检索此额外信息。然后是电话

Child* child = dynamic_cast<Child*>(bp);

编译器生成一些指令,由于这些信息,在运行时,决定返回指向实际对象的指针,如果类不正确,则返回NULL。像

这样的东西
if (typeid(*bp) == typeid(Child))
    child = reinterpret_cast<Child*>(bp)
else
    child = NULL;

注意:我在此简化过程。实际上dynamic_cast在超类的整个格子中做了更复杂的事情。

答案 2 :(得分:0)

在这种特殊情况下,如果你没有使用dynamic_cast,你会得到完全相同的结果(事实上,当你有从基类继承的对象时,这就是你通常所做的)。换句话说:

void start(Base* bp){ //here is where I get confused
   bp->say();
   bp->setting();
};

会拨打正确的saysetting。 (当然,在这种情况下,如果您使用base对象调用它,也会从base输出。

例如,child2具有与其他类不同的功能集的情况会更有趣。

所以,如果我们这样做:

class Child2:public Base{
public:
    void setting(){
        cout << "Hello, I am a function from the child2 class" << endl;
    }
    void say(){
        cout << "Child class says Wazuppppp" << endl;
    }
    void special() {
        cout << "Special function called" << endl;
    }
};

现在,如果我们执行此操作,special中的函数base不可用,但我们可以这样做:

 Child2 *it_is_child2 = dynamic_cast<Child2*>(bp);

 if (it_is_child2)
 {
     it_is_child2->special();
 }

dynamic_cast的工作方式是编译器生成的代码在运行时“查看”输入并确定它是否是“正确的类型”(即,类是否与正确相关)通往你所投的班级的方法。通常,为了方便起见,它通过查看对象vtable来实现这一点,因为具有相同基类的类具有可以匹配的vtable。在某些实现中,使用RTTI(运行时类型信息),但大多数实现使用“vtable”方法。

通常,在使用继承时,dynamic_cast(以及类型之间的其他转换)应该谨慎使用(并且“总是”检查结果)。