简体   繁体   English

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

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

Consider the following classes, which employ the Curiously Recurring Template Pattern (CRTP): 请考虑以下类,这些类采用了好奇重复模板模式(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';
    }
};

When I execute the following: 当我执行以下命令时:

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

I obtain these results, which make sense to me: 我获得了这些结果,这对我来说很有意义:

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

Clearly, the call to hello inside of callFuncOfTemplateParam succeeds because the this pointer points to an instance of Derived , which is why I am able to cast the this pointer from the type Base<Derived>* to the type Derived* . 显然,对callFuncOfTemplateParam内部的hello调用成功,因为this指针指向Derived的实例,这就是为什么我能够将this指针从Base<Derived>*类型转换为Derived*类型的原因。

Now, my confusion arises because when I execute the following: 现在,由于执行以下命令而引起混乱:

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

I obtain the following results: 我得到以下结果:

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

The types of this and *this make sense, but I don't understand how the call to hello succeeds. this*this的类型是合理的,但我不了解呼叫hello如何成功的。 this doesn't point to an instance of Derived , so why am I able to cast the type of this from Base<Derived> to Derived ? this并不指向的实例Derived ,所以为什么我能够施展的类型, thisBase<Derived>Derived

Note that I also replaced the call to static_cast<T*>(this)->hello(); 注意,我还替换了对static_cast<T*>(this)->hello();的调用static_cast<T*>(this)->hello(); with a call to dynamic_cast<T*>(this)->hello(); 调用dynamic_cast<T*>(this)->hello(); , and I still obtain the same results. ,但我仍然获得相同的结果。 I expected the dynamic_cast to return a nullptr , but it doesn't. 我期望dynamic_cast返回nullptr ,但是没有。

I am very surprised by these results. 这些结果令我感到非常惊讶。 Thank you for any help clarifying my doubts! 感谢您为澄清我的疑问提供的帮助!

The cast used to call hello() has undefined behavior when T does not match the true type of the object that this points to. 用于调用演员hello()未定义行为的时候T不符合真正的类型,对象的this指向。 But hello() isn't accessing anything via this , so it doesn't really matter what this actually points to. 但是, hello()不访问任何通过this ,所以它并没有真正的问题是什么this实际上指向。 You could just as easily do reinterpret_cast<T*>(12345)->hello() and it would still "work". 您可以轻松地执行reinterpret_cast<T*>(12345)->hello() ,它仍然可以“正常工作”。 However you decide to cast this wont make any difference since hello() simply ignores the result (in the case of dynamic_cast , see Does calling a method on a NULL pointer which doesn't access any data ever fail? ). 但是,您决定强制执行this不会有任何区别,因为hello()只会忽略结果(对于dynamic_cast ,请参见在不访问任何数据的NULL指针上调用方法会失败吗? )。

Change your classes to introduce data members that hello() tries to access via this , and you will see very different results (ie, the code will likely crash, or report garbage, etc). 更改您的类以引入hello()试图通过this访问的数据成员,您将看到非常不同的结果(即,代码可能会崩溃或报告垃圾等)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM