I have the following classes:
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) { ... }
};
Now, if I want to clone B, I do the following:
B b1;
B* b2 = b1.Clone<B>();
Is there any way to remove the template type without re-implementing Clone
in each and every derived classes?
I want something like this:
B b1;
B* b2 = b1.Clone();
The way to do this is with 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) { ... }
};
These 3 level hierarchies are quite common. Basically, the top class is pure interface, as before (note: you should = 0 the other functions too). The middle class uses the CRTP pattern: it is templated on the derived typed. the idea is that by having static access to the derived type, it can automatically implement things like Clone
. Then the derived type implements any implementation that cannot be done generically.
Notice that the derived-most type inherits from the CRTP class templated on itself. That's where the name comes from (Curiously Recurring Template Pattern). Of course, since inheritance is transitive B also inherits from A still, as originally, enabling the same sort of things.
Here is a full working example that you can execute: http://coliru.stacked-crooked.com/a/8f2b201a06b5abcc. I kept the code in the answer as similar to the question as possible, but in the coliru example there are a few small but important differences:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With