请考虑以下使用好奇重复模板模式(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
,但不会。
我对这些结果感到非常惊讶。感谢您为澄清我的疑问提供的帮助!
答案 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>