派生类型的dynamic_cast "this":什么时候合法?

dynamic_cast "this" to derived type: when is it legal?

本文关键字:什么时候 this 派生 dynamic cast 类型      更新时间:2023-10-16

这是一个显然不起作用的代码,因为在构造函数中向下转换"this"是非法的:

#include <cassert>
class A {
protected:
        virtual ~A() {}
public:
        A();
};
class B : public A {
};
A::A() {
        assert(dynamic_cast<B*>(this));
}
int main(void) {
        B b;
        return 0;
}

正如预期的那样,使用 g++ 编译时,断言失败。

然而,这是另一个有效的代码(至少在 g++ 4.7 中,我没有尝试过其他编译器):

#include <cassert>
class A {
protected:
        virtual ~A() {}
public:
        A() {}
        void f();
};
class B : public A {
public:
        B() {
                f();
        }
};
void A::f() {
        assert(dynamic_cast<B*>(this));
}
int main(void) {
        B b;
        return 0;
}

我的问题是:第二个代码是否"合法",即我可以期望对于任何编译器来说,它会以这种方式工作吗?

我的直觉是,由于 f() 是从 B 的构造函数的主体中调用的,因此 "b" 已经很好地作为类型 B 的实例进行了格式化,这使得代码合法。然而,我仍然有点从构造函数中dynamic_casting"这个"......

(请注意,我的问题不是这是否是好的做法,只是它是否合法)。

是的,第二个示例定义良好,强制转换将成功。在B的构造函数中,对象的动态类型是B的,所以强制转换为B*将成功。

第一个示例中,正如您所说,在 A 的构造函数中,动态类型是 A ,因此强制转换为 B* 将失败。

我的问题是:第二个代码"合法"吗

是的,没关系。

我的直觉是,由于 f() 是从 B 的构造函数的主体调用的,因此"b"已经很好地作为类型 B 的实例,这使得代码合法

无论如何,这是合法的,但这就是断言成功而不是失败的原因:当你进入B构造函数的主体时,你有一个类型 B 的实例

然而,我仍然有点dynamic_casting构造函数的"这个"......

请注意,无论您从何处调用A::f,它都是静态格式良好的 - 如果从 A::A 调用,它只会动态失败断言。您还可以实例化一个A并直接在其上调用f(因为A不是抽象的) - 这仍然是格式良好的,但会使断言失败。