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.
Related
I am using CRTP for performance reasons, so I have this hierarchy :
template <typename Derived>
class Base{
public:
double do_sthing(){
static_cast<Derived*>(this)->do_sthing();
}
};
class DerivedA : public Base<DerivedA>{
public:
inline double do_sthing(){ ... }
};
class DerivedB : public Base<DerivedB>{
public:
inline double do_sthing(){ ... }
};
But now I want to put objects of type DerivedA and DerivedB in a vector and do the following kind of code :
for(auto obj : my_vector) {
obj->do_sthing();
}
my solution was to create a common interface class from which Base will inherit :
class Interface {
virtual void do_sthing() = 0;
};
But in this case I am incurring the virtual call overhead, and I did all the CRTP to avoid it. Is there a manner to avoid that?
I thought of declaring the method do_sthing in Base as final.
template <typename Derived>
class Base{
public:
double do_sthing() override final{
static_cast<Derived*>(this)->do_sthing();
}
};
Do I suffer the virtual call cost in the above?
Indeed, if I use virtual methods and plain old polymorphism, my performance hit comes from the vtable look up but also from losing the inline in the case of templates
When you bring together different classes into a common structure known only at run time (like std::vector here), you can't avoid the virtual call overhead. This is a general C++ principle, for instance found also in std::function, std::any and so on. CRTP is no different in that respect.
Moreover CRTP (also known as static polymorphism) is primarily a tool for avoiding code repetition (without any performance overhead). It is not intended to speed up virtual function calls, because that is dynamic polymorphism stuff.
Beside this, you basically have two approaches to set up your classes:
One approach is to use a three-fold inheritance hierarchy, where I find it useful to separate the dynamic and static inheritance by different function names. Example:
struct Interface
{
virtual ~Interface() = default;
virtual double do_sthing_impl() = 0;
auto do_sthing() { return this->do_sthing_impl(); }
};
template<typename Derived>
struct Base<Derived> : public Interface
{
virtual double do_sthing_impl() const override { return this->do_sthing(); }
auto do_sthing() { return static_cast<Derived&>(*this).do_sthing(); }
};
struct DerivedA : public Base<DerivedA>
{
auto do_sthing() { /* ... */ }
};
Then:
std::vector<std::unique_ptr<Interface> > v;
v.push_back(std::make_unique<DerivedA>());
v.push_back(std::make_unique<DerivedB>());
Second alternative is type_erasure, e.g. via the following code (which is basically inventing an inheritance structure but without close coupling)
template<typename Derived>
struct Base{ /* ... */ };
struct DerivedA : public Base<DerivedA>{ /* ... */ };
struct type_erased
{
virtual double do_sthing() = 0;
};
template<typename Derived>
struct type_erased_impl : public type_erased
{
Derived d;
type_erasure_impl(Derived d) : d(std::move(d)) {}
virtual double do_sthing() const override { return d.do_sthing(); }
};
Then:
std::vector<std::unique_ptr<type_erased> > v;
v.push_back(std::make_unique<type_erased_impl<DerivedA> >(DerivedA{}));
v.push_back(std::make_unique<type_erased_impl<DerivedB> >(DerivedB{}));
I prefer the second alternative, because it's more flexible and doesn't introduce a fixed inheritance structure. Rather, you can implement several type erased versions of the same class where you, according to the actual need, expose only specific functions.
I usually try to find answers here before I post anything, but I'm not even sure how to formulate my question.
So here's what I want to do... I want to define a Base Interface, and a Derived Interface. Then, I want to implement the Base Interface, with extra variables and methods. Finally, I want to implemented a Derived class, from the implemented Base Interface BUT ALSO from the Derived Interface. I don't know about you, but my head hurts.
If I do something like below, I get Ambiguous definitions under the DerivedFloat code since that code "sees" both the GetBaseValue method from the IBase, inherited through IDerivedFloat, as well as the GetBaseValue inherited from Base.
Surely, there must be a way to derive a class which uses the expanded features of the Base Implementation, as well as making sure it implements the required IDerivedFloat methods.
Now... This is a dummy example to show what I'm conceptually trying to achieve. It's not a real life example.
template <typename VALUE_TYPE>
class IBase
{
public:
virtual VALUE_TYPE GetBaseValue() const = 0;
};
class IDerivedFloat : public IBase<FLOAT>
{
public:
virtual void SetBaseValue(const FLOAT & value) = 0;
};
// Implementation of Base
template <typename VALUE_TYPE>
class Base : public IBase<VALUE_TYPE>
{
public:
VALUE_TYPE GetBaseValue() const { return m_BaseValue; }
protected:
VALUE_TYPE m_BaseValue;
}
// Uses expanded Base AND implements IDerivedFloat
class DerivedFloat : public Base<FLOAT>, public IDerivedFloat
{
public:
void SetBaseValue(const FLOAT & value) { m_BaseValue = value };
}
You can use virtual inheritance to work around this problem:
class IDerivedFloat : virtual IBase<FLOAT>
{
public:
virtual void SetBaseValue(const FLOAT & value) = 0;
};
template <typename VALUE_TYPE>
class Base : virtual IBase<VALUE_TYPE>
{
public:
VALUE_TYPE GetBaseValue() const { return m_BaseValue; }
protected:
VALUE_TYPE m_BaseValue;
}
Using virtual inheritance gives the derive class one instance of the base class members, instead of one from each time it exists in the class hierarchy.
Multiple inheritance is an issue precisely because of the ambiguity issue you ran into, but there are ways to get around it. You have to explicitly tell the compiler which super you are calling the ambiguous functions from, by leading the function call with the super's name and a double colon.
Example:
- C inherits from A and B.
- A and B both have add() function.
- In C, you have to say A::add() or B::add() to tell the compiler which one to use.
Link for details and more complete implementation: http://www.cprogramming.com/tutorial/multiple_inheritance.html
I am playing around with the Visitor pattern, and I have the following bit of code which compiles:
class DerivedVisitee;
class Visitor
{
public:
void visit(DerivedVisitee &v);
};
class Visitee
{
public:
virtual void accept(Visitor &v) = 0;
};
class DerivedVisitee : public Visitee
{
public:
void accept(Visitor &v) { v.visit(*this); }
};
I would like to provide a default visit method for all descendants of Visitee. As such, I tried to do the following:
class DerivedVisitee;
class Visitor
{
public:
void visit(DerivedVisitee &v);
};
class Visitee
{
public:
virtual void accept(Visitor &v) { v.visit(*this); } // added implementation here
};
class DerivedVisitee : public Visitee
{
// removed overridden method
};
But compilation fails with 'void Visitor::visit(DerivedVisitee &)' : cannot convert argument 1 from 'Visitee' to 'DerivedVisitee &' (MSVC). Can you explain why this happens, and what is a correct method for doing what I'm trying to do?
EDIT: Visitor::visit needs to work on DerivedVisitee objects only; to put it another way, I intend to use multiple overloaded Visitor::visit methods with different implementations, for different descendants of Visitee.
The basic answer is: you cannot in pure object oriented code.
By nature the Visitor pattern is about passing to visit the derived type, and in Visitee said type is unknown (it's a runtime property).
In C++, there exists a pattern called CRTP:
template <typename Derived, typename Base>
class VisiteeHelper: public Base {
public:
virtual void accept(Visitor& v) override {
Derived& d = static_cast<Derived&>(*this);
v.visit(d);
}; // class VisiteeHelper
and then you can derive from this:
// And there we see the "Curiously Recurring" part:
class DerivedVisitee: public VisiteeHelper<DerivedVisitee, Visitee> {
}; // class DerivedVisitee
class MoreDerivedVisitee: public VisiteeHelper<MoreDerivedVisitee, DerivedVisitee> {
}; // MoreDerivedVisitee
It's up to you to decide whether you prefer the dead-simple boilerplate or the smart (but potentially confusing) CRTP solution.
Personally, unless you have multiple overloads of accept (up to 4 per type by overloading on const-ness), I would not bother. It's about as much work to write the accept by hand, and it's dead simple, and immediately understandable.
You should pass Visitee& instead of DerivedVisitee& as argument of visit method. This is the whole point of using public inheritance and Polymorphism. Any derived object can be used where a base object is expected. At runtime, the actual type will be deducted and appropriate method will be called on that object.
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>).
Say you have a base class Dep for a tree of classes. There is a virtual method Dep* Dep::create() that I want to be implemented by every single leaf class. Is there any way to enforce this?
Note: The problem here is that there could be intermediate classes (say class B : public A : public Dep) implementing this method (A::create) by accident or because they think they are leaf classes, but are in fact subclassed themselves.
The question ends here.
Context
If you are curious why I need this; I have a class Master which has Dep objects of unknown concrete type. If Master is duplicated, I need to come up with a matching clone of the Dep instance. Next best thing to do is the virtual constructor idiom, which introduces precisely this problem.
Additionally, I cannot even catch this (other then by crashing horribly), because for obscure reasons, people that have more to say than me, have outlawed dynamic_cast in this project (perhaps this is a good decision; But anyways a completely different discussion).
C++ provides no way to keep a class from inheriting from your class, and there is no way to make a particular class in the inheritance hierarchy implement a method. The only rule is that somewhere in the inheritance hierarchy above a particular class (not necessarily in the leaf) all virtual functions must have an implementation for that class to be instantiatable.
For instance, A could inherit from Def and implement all it's [pure] virtual methods. Then if B inherits from A, it doesn't have to implement anything. There's no way to keep that from happening.
So the answer is no, there is no way to enforce this.
Using curiously recurring template fun, you can achieve something quite similar:
template<typename T>
class Cloneable : public T, public Dep
{
private:
Cloneable<T>() : T() { }
public:
static Cloneable<T>* Create() { return new Cloneable<T>(); }
Cloneable<T>* clone() { return new Cloneable<T>(*this); }
};
Instead of deriving from Dep and instantiating via new MyType, use Cloneable<MyType>::Create. Since Cloneable<MyType> is derived from MyType, you can use the instance the same way you would use any MyType, except that it is now guaranteed to have Dep::clone.
Additionally your Master should not accept an instance of type Dep, but enforce that it is a Cloneable<T>. (Replace your orignial function by a simple function template that enforces this.) This guarantees that any Dep inside the master has a correctly implemented clone function.
Since Cloneable<MyType> has no public constructor, it cannot be inherited, however your actual MyType can be further inherited and used just as before.
Did TPTB outlaw all RTTI, or only dynamic_cast<>()? If you can use RTTI, then you can enforce the existence of the method as a postcondition of calling it:
#include <typeinfo>
#include <cassert>
#include <iostream>
#include <stdexcept>
class Base {
protected:
virtual Base* do_create() = 0;
virtual ~Base() {}
public:
Base* create() {
Base *that = this->do_create();
if( typeid(*this) != typeid(*that) ) {
throw(std::logic_error(std::string() +
"Type: " +
typeid(*this).name() +
" != " +
typeid(*that).name()));
}
return that;
}
};
class Derive1 : public Base {
protected:
Base* do_create() { return new Derive1(*this); }
};
class Derive2 : public Derive1 {};
void f(Base*p) { std::cout << typeid(*p).name() << "\n"; }
int main() {
Derive1 d1;
Base *pD1 = d1.create(); // will succeed with correct semantics
Derive2 d2;
Base *pD2 = d2.create(); // will throw exception due to missing Derive2::do_create()
}
If you control the base class AbstractDep then you can enforce that concrete leaf classes must be created by using a class template WithCloning. This leaf can then be sealed so that it cannot be inherited. Or more precisely, instances cannot be created of a derived class.
class AbstractDep
{
template< class Type > friend class WithCloning;
private:
enum FooFoo {};
virtual FooFoo toBeImplementedByLeafClass() = 0;
public:
virtual AbstractDep* clone() const = 0;
};
template< class Type > class WithCloning;
class Sealed
{
template< class Type > friend class WithCloning;
private:
Sealed() {}
};
template< class Type >
class WithCloning
: public Type
, public virtual Sealed
{
private:
AbstractDep::FooFoo toBeImplementedByLeafClass()
{
return AbstractDep::FooFoo();
}
public:
virtual WithCloning* clone() const
{
return new WithCloning( *this );
}
};
typedef WithCloning<AbstractDep> Dep;
class AbstractDerivedDep
: public AbstractDep
{
// AbstractDep::FooFoo toBeImplementedByLeafClass(); // !Not compile.
public:
};
typedef WithCloning<AbstractDerivedDep> DDep;
struct Foo: Dep {}; // !Does not compile if instantiated.
int main()
{
Dep d;
//Foo f;
}
If the classes require more than default construction then that most be solved additionally.
One solution is then to forward an argument pack from the WithCloning constructor (there is an example C++98 implementation on my blog, and C++0x supports that directly).
Summing up, to be instantiable the class must be WithCloning.
Cheers & hth.,
when you say that they are unknown, i presume they still inherit from a common base class /interface right?
only thing i can think of you can use to force is on the virtual base class add
virtual Base* clone() {
assert( 1==0 ); //needs to be overriden
}
so you are forced to override, but this is only detected at run-time when trying to call clone on a instance of a class that is missing the override
even if you are not allowed to use dynamic_cast or RTTI, you can still enable it for debug purposes locally on your build, if that will help you find the typeid of offending classes
it sounds like you are familiar with the clone pattern, but i'll post it quietly in here, and we can forget about it:
http://www.cplusplus.com/forum/articles/18757/