我有类模板作为派生类的基类。这个想法是利用静态多态性"静态多态"通过CRTP技巧。
#include <iostream>
template <typename T>
class BASE
{
public:
void write() {static_cast<T*>(this)->write(); }
};
class DER1 : public BASE<DER1>
{
public:
void write(){
std::cout << "Calling write() inside DER1 " << number << std::endl;}
private:
int number = 11;
};
我尝试了两种不同的实例化派生类对象的方法,并且我发现这两种方法中的一种方法不正确。但我无法理解为什么。
int main(void) {
BASE<DER1> der1_objA ;
der1_objA.write();
DER1 der1_objB ;
der1_objB.write();
return 0;
}
事实上,我得到了输出
Calling write() inside DER1 1880535040 [ random number]
Calling write() inside DER1 11 [correct number ]
有人可以解释我的问题在哪里吗? 非常感谢你提前。
答案 0 :(得分:2)
在BASE<DER1>
实例中没有DER1
实例,但只有BASE
试图将自己投射到不是它的东西。
答案 1 :(得分:1)
当你定义一个BASE类型的对象时,它只是一个BASE,但在它里面,你指的是它不是(DER1)的东西,并继续使用它通过那个无效指针。这是未定义的行为,垃圾是正常的后果。 CRTP工作的唯一时间是对象的动态类型实际上是传递给基类的模板参数。也就是说,如果BASE认为它确实是DER1,它实际上必须是DER1。当它仅为BASE并且使用该指针进行DER1操作时将其自身转换为DER1是未定义的行为,与此相同:
int x = 42;
std::string * sptr = (std::string*)&x; // extremely questionable
sptr->clear(); // undefined behavior
您应该考虑让BASE构造函数具有&#34; protected&#34;访问级别,以防止简单的滥用情况。这样,基础构造函数只能由派生对象调用,因此您不能意外地单独实例化基础:
template <typename T>
class BASE
{
protected:
BASE() = default;
BASE(BASE const&) = default;
public:
void write() {static_cast<T*>(this)->write(); }
};
然后你得到:
而不是垃圾BASE<DER1> objA ;
objA.write();
error: 'BASE<T>::BASE() [with T = DER1]' is protected within this context
BASE<DER1> base;