【问题标题】:Why am I able to cast the this pointer of a base class to a pointer to a child class using the CRTP?为什么我可以使用 CRTP 将基类的 this 指针转换为指向子类的指针?
【发布时间】:2018-11-12 17:36:37
【问题描述】:

考虑以下使用奇怪重复模板模式 (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 的一个实例,这就是我能够从@987654329 类型转换this 指针的原因@ 类型为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&lt;Derived&gt; 转换为Derived

请注意,我还将对static_cast&lt;T*&gt;(this)-&gt;hello(); 的调用替换为对dynamic_cast&lt;T*&gt;(this)-&gt;hello(); 的调用,我仍然获得相同的结果。我预计 dynamic_cast 会返回 nullptr,但它没有。

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

【问题讨论】:

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


    【解决方案1】:

    Tthis 指向的对象的真实类型不匹配时,用于调用hello() 的转换具有未定义的行为。但是hello() 没有通过this 访问任何东西,所以this 实际指向什么并不重要。你可以很容易地做到reinterpret_cast&lt;T*&gt;(12345)-&gt;hello(),它仍然会“工作”。但是,您决定投射 this 不会产生任何影响,因为 hello() 只是忽略了结果(在 dynamic_cast 的情况下,请参阅 Does calling a method on a NULL pointer which doesn't access any data ever fail?)。

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

    【讨论】:

    • 感谢您周到的回答雷米!我不知道在 nullptr 上调用方法实际上可以工作。这是经典的我,选择一个失败的测试作为理智检查哈哈哈。
    猜你喜欢
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-23
    • 2011-12-29
    • 2016-11-12
    相关资源
    最近更新 更多