堆栈对象的动态转换失败

3

前几天我遇到了这样一个情况:我有一个函数,它接受一个指向基本类型的指针,然后我需要将其向上转换为派生类型以访问一些额外的功能。然而,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();
}

很有趣,因为如果只给你 cast() 这个方法,你会期望可以转换传入的对象。我已经展示了这不是情况;它取决于对象最初的创建方式。令人困惑的是,为什么可以转换被引用重新赋值的对象却不能转换被值重新赋值的对象。此外,只要我们保证类型兼容,使用 static_cast 会起作用吗?

1个回答

7
test3TestClass 类型的(我假设它是 Derived 的父类),因此动态转换失败。
即使你将 *test1 分配给它,赋值只会复制 TestClass 部分(也称为切片)。当你将指针分配给另一个指针时,不会发生切片。
你可以认为派生对象有一个基础部分:
*test1:
|--------------|
|TestClass part|
|--------------|
|Derived part  |
|--------------|

test3:
|--------------|
|TestClass part|
|--------------|

当你分配一个指针 (test2=test1) 时,对象本身不会改变,你只是通过 TestClass 的指针查看它,因此转换有效。
当你分配对象本身 (test3=*test1) 时,目标 (test3) 只有容纳 TestClass 对象的空间,所以拷贝会去掉额外的 Derived 部分。

非常清楚的回答,谢谢。所以一旦一个实例被切片,就没有办法“恢复”派生类型了吗? - user975326
@user975326 - 正确的。请注意,您可以使用引用而不是类型,它将像指针一样起作用,但语法与您使用堆栈分配的对象相同。 - Attila

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接