繁体   English   中英

dynamic_cast理解

[英]dynamic_cast understanding

我最近开始了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与启动功能以及它们如何工作有关。 另外,编译器如何决定选择哪一个。

如果关联的类不相关(其中一个从另一个继承,或者两个都从一个共同的祖先继承),则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。

决定哪一个不是编译器。 使用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在超类的整个网格中做了一些更复杂的事情。

在这种特殊情况下,如果不使用dynamic_cast ,则将获得完全相同的结果(实际上,当您具有从基类继承的对象时,通常这样做就是)。 换一种说法:

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

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

例如, child2具有与其他类不同的功能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;
    }
};

现在,如果执行此操作,则base不提供special功能,但是我们可以执行以下操作:

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM