为什么我可以使用 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
,但它没有。
我对这些结果感到非常惊讶。感谢您帮助澄清我的疑惑!
当 T
与 this
指向的对象的真实类型不匹配时,用于调用 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
访问的数据成员,您将看到截然不同的结果(即,代码可能会崩溃,或报告垃圾等)。
考虑以下 类,它采用了 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
,但它没有。
我对这些结果感到非常惊讶。感谢您帮助澄清我的疑惑!
当 T
与 this
指向的对象的真实类型不匹配时,用于调用 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
访问的数据成员,您将看到截然不同的结果(即,代码可能会崩溃,或报告垃圾等)。