堆栈对象的动态转换失败

use*_*326 3 c++ dynamic-cast reference object-slicing

前几天我遇到了一个实例,我有一个函数,它指向一个基类型,然后我需要向上转换为派生类型以访问一些额外的功能.然而,dynamic_cast失败了,这很奇怪,因为我的类型肯定继承了基类型.

为了了解正在发生的事情的底部,我创建了以下测试程序,我认为它复制了我所看到的:

void cast(TestClass *baseType)
{
    if (dynamic_cast<Derived *>(baseType))
        TRACE("cast was sucessful");
    else
        TRACE("cast failed");
}

int main(int argc, char *argv[])
{
    Derived *test1 = new Derived();
    TestClass *test2 = new TestClass();
    TestClass test3;

    test1->identify(); // prints: this is a Derived class
    test2->identify(); // prints: this is a TestClass

    cast(test1); // succesful
    cast(test2); // fail - expected

    // reassign test2 to test1
    test2 = test1;
    test2->identify(); // prints: this is a Derived class

    cast(test2); // succesful

    // the interesting part, the test3 object (created on stack), does not cast
    // despite that it would seem possible from the cast method.
    test3 = *test1;
    test3.identify(); // prints: this is a TestClass
    cast(&test3); // fails?

    return a.exec();
}
Run Code Online (Sandbox Code Playgroud)

这很有趣,因为如果你只看到我调用的方法cast(),你会期望可以投射传入的对象.我已经证明情况并非如此; 它取决于最初创建对象的方式.令人困惑的是,为什么可以投射一个已经通过引用而不是通过值重新分配的对象.此外,static_cast只要我们保证类型兼容,会使用工作吗?

Att*_*ila 7

test3是类型TestClass(我假设是Derived的父级),因此动态转换失败.

即使您指定*test1它,分配也只复制TestClass部分(也称为切片).为指针指定指针时,不会发生切片.

您可以将派生对象视为具有其基础的一部分:

*test1:
|--------------|
|TestClass part|
|--------------|
|Derived part  |
|--------------|

test3:
|--------------|
|TestClass part|
|--------------|
Run Code Online (Sandbox Code Playgroud)

当你指定一个指针(test2=test1),对象本身不会改变,你只是通过一个不同的玻璃(通过一个指针TestClass)来看它,因此投射工作.

当您指定一个对象本身(test3=*test1)时,destination(test3)只有一个TestClass对象的空间,因此该副本会带走额外的Derived部分.