我一直在研究 CRTP,我不明白的是在 main() 中,我们创建了一个
Base<Derived>*
类型的对象并调用了 callDerived
,为什么 'this
' 是Base
,Derived
班的资料也都有吗?我了解 Derived 继承自 Base 但“Derived”是 Base 的突出模板,但 CRTP 的工作方式是双向继承:Derived
派生自 Base
和 Base
也派生自 Derived
而在此行 ' Base* pObjBase = new Base();' , 'Derived
' 只是Base
! 的模板
我想知道'this'拥有Derived的所有信息的幕后发生了什么!
#include <iostream>
template <typename T>
class Base {
public:
virtual ~Base() = default;
Base()
{
std::cout << " Base()\n";
}
void callDerived() {
T& refDerived = static_cast<T&>(*this);
refDerived.derivedMethod();
T* pDerived = static_cast<T*>(this);
pDerived->derivedMethod();
//T& obj3 = dynamic_cast<T>(*this); //Error
//T obj4 = dynamic_cast<T>(*this); //Error
//obj3.derivedMethod();
//obj4.derivedMethod();
}
};
class Derived : public Base<Derived> {
public:
Derived() :
Base()
{
std::cout << "Derived() \n";
}
void derivedMethod() {
std::cout << "Derived method gets invoked" << std::endl;
}
};
int main() {
Base<Derived>* pObjBase = new Base<Derived>();
pObjBase ->callDerived(); // Output: Derived method called
delete pObjBase ;
}
之所以有效,是因为您必须确保
T
是对象的实际类型。你不做一个 Base<Derived>
对象,因为那是错误的 T
并且它坏了,正如你所想的那样。你应该做的是制作一个 Derived
对象,它从 Base<Derived>
延伸,一切都很好。
您成功收到消息
Derived method gets invoked
的原因与模板或CRTP无关。仅仅是因为编译代码中的这个函数根本没有接触到对象。很有可能您可以在空指针或指向完全不相关的事物的指针上调用此函数,它仍会打印消息。 “它似乎工作正常”是一种允许的未定义行为。