Suppose I have a base class which cloning of derived classes:
class Base
{
public:
virtual Base * clone()
{
return new Base();
}
// ...
};
I have a set of derived classes which are implemented using a curiously recurring template pattern:
template <class T>
class CRTP : public Base
{
public:
virtual T * clone()
{
return new T();
}
// ...
};
And I attempt to derive from that further like this:
class Derived : public CRTP<Derived>
{
public:
// ...
};
I get compilation errors to the effect of:
error C2555: 'CRTP<T>::clone': overriding virtual function return type differs and is not covariant from 'Base::clone'
I realize this is probably a result of the compiler not fully knowing the inheritance tree for Derived when instantiating CRTP. Furthermore, replacing the return type (T*) with (Base*) also compiles. However, I would like to know if there is a work around which retains the above semantics.
A not-so-pretty workaround.
class Base
{
protected:
virtual Base * clone_p()
{
return new Base();
}
};
template <class T>
class CRTP : public Base
{
protected:
virtual CRTP* clone_p()
{
return new T;
}
public:
T* clone()
{
CRTP* res = clone_p();
return static_cast<T*>(res);
}
};
class Derived : public CRTP<Derived>
{
public:
};
Use dynamic_cast<> instead of static if you feel it's safer.
If you can live with having to use a different syntax for specifying complete types, you might do the following (warning: untested code):
Let's first start with the machinery:
// this gives the complete type which needs to be used to create objects
// and provides the implementation of clone()
template<typename T> class Cloneable:
public T
{
public:
template<typename... U> Cloneable(U&&... u): T(std::forward<U>(u) ...) {}
T* clone() { return new Cloneable(*this); }
private:
// this makes the class complete
// Note: T:: to make it type dependent, so it can be found despite not yet defined
typename T::CloneableBase::CloneableKey unlock() {}
};
// this provides the clone function prototype and also makes sure that only
// Cloneable<T> can be instantiated
class CloneableBase
{
template<typename T> friend class Cloneable;
// this type is only accessible to Clonerable instances
struct CloneableKey {};
// this has to be implemented to complete the class; only Cloneable instances can do that
virtual CloneableKey unlock() = 0;
public:
virtual CloneableBase* clone() = 0;
virtual ~CloneableBase() {}
};
OK, now the actual class hierarchy. That one is pretty standard; no CRTP intermediates or other complications. However no class implements the clone function, but all inherit the declaration (directly or indirectly) from CloneableBase.
// Base inherits clone() from CloneableBase
class Base:
public CloneableBase
{
// ...
};
// Derived can inherit normally from Base, nothing special here
class Derived:
public Base
{
// ...
};
Here's how you then create objects:
// However, to create new instances, we actually need to use Cloneable<Derived>
Cloneable<Derived> someObject;
Derived* ptr = new Cloneable<Derived>(whatever);
// Now we clone the objects
Derived* clone1 = someObject.clone();
Derived* clone2 = ptr->clone();
// we can get rid og the objects the usual way:
delete ptr;
delete clone1;
delete clone2;
Note that a Cloneable<Derived> is-a Derived (it is a subclass), therefore you need to use Cloneable only for construction, and can otherwise pretend to work with Derived objects (well, tyepinfo will also identify it as Cloneable<Derived>).
Related
I'm not exactly sure what to call this inheritance scheme, but I'm trying to use a cloneable interface with a default implementation. I'm having some issues getting the correct scheme though.
I'm basing this somewhat on the cloneable interface defined in C#.
First I have my interface and default implementations:
template<class BaseType>
class ICloneable
{
public:
virtual std::shared_ptr<BaseType> Clone() const = 0;
};
template<class BaseType, class DerivedType>
class Cloneable : public ICloneable<BaseType>
{
public:
virtual std::shared_ptr<BaseType> Clone() const
{
return std::shared_ptr<BaseType>(new DerivedType(*(DerivedType*)this));
}
};
My desire is to have the following scheme.
// A pure virtual base interface
class Base : public ICloneable<Base>
{
public:
virtual void SomeFunc() = 0;
}
// Another implementation
class Imp1 : public Base, Cloneable<Base, Imp1>
{
public:
virtual void SomeFunc() {}
}
// An implementation
class Imp2 : public Cloneable<Base, Imp2>
{
public:
virtual void SomeFunc() {}
}
If I have a list of `std::shared_ptr' objects, I can invoke the Clone function when I want to make a deep copy without having to manually write the function in every one of the implementations.
Right now I get that Imp is an abstract class, which doesn't surprise me. Anyone know how I can get this default implementation idea to work? The point is to not have to manually write the clone function for every one of the implementations. It might not be doable but I'm out of ideas to try.
You could do the following:
#include <memory>
template<typename InterfaceType_>
struct ICloneable
{
using InterfaceType = InterfaceType_;
virtual ~ICloneable() = default;
virtual std::shared_ptr<InterfaceType> clone() const = 0;
};
template<typename T, typename Base = ICloneable<T>>
struct CloneableMixin : public Base
{
using InterfaceType = typename Base::InterfaceType;
// With the following line uncommented, code does not compile in MSVC
//using typename Base::InterfaceType;
std::shared_ptr<InterfaceType> clone() const override
{ return std::make_shared<T>(*static_cast<const T*>(this)); }
};
Now, this can be used as follows:
struct SomeBaseClass : public CloneableMixin<SomeBaseClass> { /*...*/ };
struct SomeDerivedClass : public CloneableMixin<SomeDerivedClass, SomeBaseClass> { /*...*/ };
Two notes:
In order to be able to access InterfaceType_ template parameter of ICloneable, you need to make it a template alias, and then use using typename Base::InterfaceType (as it is template parameter dependent type).
I've provided default type for Base template parameter of CloneableMixin - this allows to use it for base classes, for which you want to have clone implemented.
Moreover, two unrelated comments:
You don't need to type virtual - it's implied. It's a good idea to add override at the end (this makes sure that the method actually overrides something, otherwise a compiler will report an error).
You might consider using std::make_shared instead of new.
Suppose I want to implement abstract behavior in a base class that is inherited by all derived classes. For example, a function that clones an object, applies some modification to it and returns the cloned and modified object (e.g. transposition, duplication, etc). The following code uses an even simpler function that merely returns the object itself:
class Base
{
public:
virtual Base* yourself ()
{
return this;
}
};
class Derived : public Base
{
public:
...
};
void main()
{
Derived d;
auto result = d.yourself();
}
If I didn't miss something, result will be of type Base*, where the intention clearly is to get an object of type Derived*.
Is there a way to have yourself() return the intended value for all derived classes without overriding it in all places (actually the whole point of inheritance is to implement each behavior only once)?
This issue is fairly common, and you can get around it using templates. Something like this:
template <class T>
class Base
{
public:
virtual T* yourself ()
{
return dynamic_cast<T*>(this);
}
};
class Derived : public Base<Derived>
{
public:
...
};
It's called the Curiously recurring template pattern (CRTP)
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:
usage of owning pointers instead of raw pointers considered good practice in C++, and because smart pointers are not covariant this affects the signatures
correct use of = 0 and override, as well as const
an example of the static downcast which is kind of a signature of CRTP that didn't come up with your example
I run into a trouble with templates and inheritance. Consider following code:
#include <iostream>
using namespace std;
class TemplateBase {
public:
TemplateBase() {}
};
class TemplateA: public TemplateBase {
public:
TemplateA():TemplateBase() {}
};
template <class T>
class Base {
public:
Base() {}
};
class Derived: public Base<TemplateA> {
public:
Derived(): Base() {}
};
int main()
{
Base<TemplateBase>* a = new Base<TemplateBase>(); // ok
Base<TemplateA>* b = new Derived(); // ok
Base<TemplateBase>* c = new Derived(); // error: cannot convert ‘Derived*’ to ‘Base<TemplateBase>*’ in initialization
}
The problem is the assignment of pointer c, which fails from unknown reason for me. I am trying to assign the Derived<AnotherDerived> to Base<AnotherBase>, is this possible?
Thank you for any help.
Your Derived is a non-template class derived from Base<TemplateA>. In the line
Base<TemplateBase>* c = new Derived();
you are trying to refer to a Derived object via a pointer to Base<TemplateBase>. For the compiler, there is no relation between Base<TemplateBase> and Derived, hence it fails. The only possible base to use is Base<TemplateA> from which Derived is derived.
A possible solution is to templatize the Derived, like
template<typename T>
class Derived: public Base<T> {
public:
Derived(): Base<T>() {}
};
then use as
Base<TemplateBase>* c = new Derived<TemplateBase>;
See a live example here.
vsoftco gives a good outline of why this is invalid. An example of why this is the case in C++ is that although TemplateBase and TemplateA are related, Base<TemplateBase> and Base<TemplateA> are completely different. We could even specialize Base in a way which makes them have an incompatible interface:
template<>
struct Base<TemplateBase>
{
Base() = delete;
Base(int i) {}
}
Now it's obvious that Base<TemplateBase> and Base<TemplateA> can't be used in the same way, because one is default-constructable and one isn't. As such, it's impossible to use them polymorphically, because the compiler won't know what code to generate.
Polymorphism says a base class pointer can point to a derived class object.
But the same can't happen for templates.
Since Polymorphism is a dynamic feature and bound at run-time.
Templates are a static feature and bound at the compile time.
You make a common mistake, you think that relation between classes:
class A {};
class B : public A {};
Will propagate this relation to templates:
template <class T>
class Tmpl {};
Tmpl<A> a; Tmpl<B> b;
a = b; // fails!
So you expected that Tmpl<A> would be a parent to Tmpl<B> but that is not the case. To simulate that you would need to make a constructor, that allows such conversion:
template <class T>
class Tmpl {
T data;
public:
Tmpl() : data() {}
template<class Parent>
Tmpl( const Tmpl<Parent> &t ) : data( t.data ) {}
};
Tmpl<A> a; Tmpl<B> b;
a = b; // works!
For details you should look into smart pointer implementation, there is similar problem there - assignment from pointer to child from base needs to work.
The Derived class is derived from Base<TemplateA> so Base<TemplateBase>* c = new Derived() is equivalent to saying
Base<TemplateBase>* c = new Base<TemplateA>() which is incorrect because Base<TemplateA> is a different class altogether.
TemplateBase is a base class for TemplateA but same does not hold true for Base<TemplateBase> and Base<TemplateA>.
I searched around and seems in order to perform this I need to change my Base class and want to know if this is the best approach.
For example,
I have a Base class:
class Base {}
Then a long line of derived classes:
class Derived_1:: public Base {}
class Derived_2:: public Derived_1{}
...
...
class Derived_n:: public Derived_M{}
And then I have another class:
class DeepCopy
{
Base * basePtr;
public:
DeepCopy(DeepCopy & dc) {}
}
Assuming the Base class and Derived_x class copy constructors are properly coded, what is the best way to write the copy constructor for DeepCopy. How can we know about the class that is in the basePtr of the object we are going to copy?
Only way I can think of is using RTTI, but using a long list of dynamic_casts seems not right. Besides it requires DeepCopy to know about the inheritance hierarchy of Base class.
The other method I saw is here. But it requires Base and Derived classes implement a clone method.
So is there a much easier, standard way of doing this?
You need to use the virtual copy pattern: provide a virtual function in the interface that does the copy and then implement it across the hierarchy:
struct base {
virtual ~base() {} // Remember to provide a virtual destructor
virtual base* clone() const = 0;
};
struct derived : base {
virtual derived* clone() const {
return new derived(*this);
}
};
Then the DeepCopy object just needs to call that function:
class DeepCopy
{
Base * basePtr;
public:
DeepCopy(DeepCopy const & dc) // This should be `const`
: basePtr( dc.basePtr->clone() )
{}
};
Using an approach that employs a clone() function is a good solution. Note using the CRTP (the curiously recurring template pattern) can save you some of the work. The way you do it is by introducing an intermediate level (called BaseCRTP below) which is a template and implements the clone() function. When you derive your actual classes, use them as the template argument of the base they are derived from. They will get the clone() function implemented for them automatically. Make sure the derived classes implement a copy constructor (or be sure the default is what you need).
/* Base class includes pure virtual clone function */
class Base {
public:
virtual ~Base() {}
virtual Base *clone() const = 0;
};
/* Intermediate class that implements CRTP. Use this
* as a base class for any derived class that you want
* to have a clone function.
*/
template <typename Derived>
class BaseCRTP : public Base {
public:
virtual Base *clone() const {
return new Derived(static_cast<Derived const&>(*this));
}
};
/* Derive further classes. Each of them must
* implement a correct copy constructor, because
* that is used by the clone() function automatically.
*/
class Derived1 : public BaseCRTP<Derived1> {
/*... should have an ordinary copy constructor... */
};
class Derived2 : public BaseCRTP<Derived2> {
/*... should have an ordinary copy constructor... */
};
You can then obviously implement the DeepCopy class in the usual way:
class DeepCopy
{
Base *basePtr;
public:
DeepCopy(const DeepCopy &dc)
: basePtr(dc.basePtr->clone())
{}
};
I think that templates are the best way to go in this situation:
template<typename Sub>
class DeepCopy
{
Base *base;
DeepCopy(Sub *sub)
{
base = new Sub(*sub); // use copy constructor
}
}
This does mean that DeepCopy's are un-assignable to each other, but that's the price you pay with C++.