为什么我可以使用 CRTP 将基 class 的 this 指针转换为指向子 class 的指针?

Why am I able to cast the this pointer of a base class to a pointer to a child class using the CRTP?

考虑以下 类,它采用了 Curiously Recurring Template Pattern (CRTP):

template <typename T>
class Base
{
public:
    virtual ~Base() {}

    void typeOfThis()
    {
        cout << "Type of this:  " << typeid(this).name() << '\n';
        cout << "Type of *this: " << typeid(*this).name() << '\n';
    }

    void callFuncOfTemplateParam()
    {
        static_cast<T*>(this)->hello();
    }
};

class Derived : public Base<Derived>
{
public:
    void hello()
    {
        cout << "Hello from Derived!" << '\n';
    }
};

当我执行以下命令时:

Base<Derived> * basePtrToDerived = new Derived();
basePtrToDerived->typeOfThis();
basePtrToDerived->callFuncOfTemplateParam();

我得到了这些对我有意义的结果:

Type of this:  P4BaseI7DerivedE
Type of *this: 7Derived
Hello from Derived!

显然,在 callFuncOfTemplateParam 中对 hello 的调用成功了,因为 this 指针指向 Derived 的一个实例,这就是为什么我能够进行转换this 从类型 Base<Derived>* 到类型 Derived* 的指针。

现在,我的困惑出现了,因为当我执行以下命令时:

Base<Derived> * basePtrToBase = new Base<Derived>();
basePtrToBase->typeOfThis();
basePtrToBase->callFuncOfTemplateParam();

我得到以下结果:

Type of this:  P4BaseI7DerivedE
Type of *this: 4BaseI7DerivedE
Hello from Derived!

this*this的类型是有道理的,但我不明白hello的调用是如何成功的。 this 没有指向 Derived 的实例,那么为什么我可以将 this 的类型从 Base<Derived> 转换为 Derived

请注意,我还将对 static_cast<T*>(this)->hello(); 的调用替换为对 dynamic_cast<T*>(this)->hello(); 的调用,我仍然获得相同的结果。我希望 dynamic_cast 到 return 一个 nullptr,但它没有。

我对这些结果感到非常惊讶。感谢您帮助澄清我的疑惑!

Tthis 指向的对象的真实类型不匹配时,用于调用 hello() 的转换具有 未定义的行为到。但是 hello() 没有通过 this 访问任何东西,所以 this 实际指向什么并不重要。您可以轻松地执行 reinterpret_cast<T*>(12345)->hello(),它仍然会 "work"。然而,你决定施放 this 不会有任何区别,因为 hello() 只是忽略结果(在 dynamic_cast 的情况下,请参阅 Does calling a method on a NULL pointer which doesn't access any data ever fail?)。

更改您的 类 以引入 hello() 尝试通过 this 访问的数据成员,您将看到截然不同的结果(即,代码可能会崩溃,或报告垃圾等)。