我有以下课程:
class A {
public:
virtual std::string Serialize();
virtual void Deserialize(std::string);
template <typename T>
T* Clone()
{
std::string s = Serialize();
T* t = new T();
t->Deserialize(s);
return t;
}
};
class B : public A {
public:
std::string Serialize() { ... }
void Deserialize(std::string) { ... }
};
Run Code Online (Sandbox Code Playgroud)
现在,如果我想要克隆B,我会执行以下操作:
B b1;
B* b2 = b1.Clone<B>();
Run Code Online (Sandbox Code Playgroud)
有没有办法删除模板类型而不Clone在每个派生类中重新实现?
我想要这样的东西:
B b1;
B* b2 = b1.Clone();
Run Code Online (Sandbox Code Playgroud)
Nir*_*man 12
这样做的方法是使用CRTP:
class A {
public:
virtual std::string Serialize();
virtual void Deserialize(std::string);
virtual A* Clone() = 0;
};
template <class T>
class HelperA : public A {
T* Clone() override
{
std::string s = Serialize();
T* t = new T();
t->Deserialize(s);
return t;
}
};
class B : public HelperA<B> {
public:
std::string Serialize() { ... }
void Deserialize(std::string) { ... }
};
Run Code Online (Sandbox Code Playgroud)
这三个层次结构很常见.基本上,顶级类是纯接口,如前所述(注意:你应该= 0其他函数).中间类使用CRTP模式:它是在派生类型上模板化的.这个想法是通过静态访问派生类型,它可以自动实现类似的东西Clone.然后派生类型实现了一般无法完成的任何实现.
请注意,派生最多类型继承自模板化的CRTP类.这就是名称的来源(奇怪的重复模板模式).当然,由于继承是传递性的,B也从A继承,原来仍然可以实现同样的东西.
这是一个完整的工作示例,您可以执行:http://coliru.stacked-crooked.com/a/8f2b201a06b5abcc.我将答案中的代码尽可能地与问题类似,但在coliru示例中,存在一些小而重要的差异: