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

时间:2018-11-12 17:36:38

标签: c++ crtp dynamic-cast static-cast

请考虑以下使用好奇重复模板模式(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!

很明显,在hello内对callFuncOfTemplateParam的调用成功了,因为this指针指向Derived的一个实例,这就是为什么我可以强制转换{ {1}}从类型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,但不会。

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

1 个答案:

答案 0 :(得分:4)

hello()T指向的对象的真实类型不匹配时,用于调用this的强制转换具有未定义的行为。但是hello()不会通过this访问任何内容,因此this实际指向的内容并不重要。您可以轻松完成reinterpret_cast<T*>(12345)->hello(),但它仍然可以“工作”。但是,您决定强制转换this不会有任何区别,因为hello()只是忽略了结果(对于dynamic_cast,请参见Does calling a method on a NULL pointer which doesn't access any data ever fail?)。

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