Рассмотрим следующие классы, в которых используется шаблон любопытного повторения шаблона (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
, поэтому я могу привести указатель 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
вернет nullptr
, но это не так.
Я очень удивлен этими результатами. Спасибо за любую помощь, проясняя мои сомнения!