I'd need to create a type erasure pattern which would allow to retrieve all the contained objects inheriting from a given base class. As far as I know, a popular type erasure like boost::any allows to retrieve an object with any_cast only if the requested and contained classes matches exactly, so it won't fit my needs.
I could solve the problem with template class which mimicks the inheritance relationship of the template argument. For example, TemplateClass<Derived> should be a child of TemplateClass<Base>, so that the following example would work:
// Suppose all clases have virtual destructors so that vtable and RTTI info are available
class ObjectWrapperBase {
}
template<class DataType>
class ObjectWrapperT: public ObjectWrapperBase {
public:
ObjectWrapperBase(T* ptr): dataObjPtr(ptr){}
DataType *dataObjPtr;
}
class Base{}
class Derived: public Base{}
class NotDerivedFromBase{}
int main(){
std::vector<ObjectWrapperBase*> v;
v.push_back(new ObjectWrapperT<Base>(new Base));
v.push_back(new ObjectWrapperT<Derived>(new Derived));
v.push_back(new ObjectWrapperT<NotDerivedFromBase>(new NotDerivedFromBase));
// Now suppose I want to retrieve all the Base and children objects in v
// If ObjectWrapperT<Derived> is a child of ObjectWrapperT<Base> I can write:
for(int i = 0; i < v.size(); i++){
ObjectWrapperT<Base> *wPtr = dynamic_cast<ObjectWrapperT<Base>*>(v[i]);
if(wPtr){
Base *basePtr = wPtr->dataObjPtr;
}
}
}
Is there a pattern to achieve this behavior? Or eventually another solution?
Thanks.
You cannot do exactly what you want, but you can get something closer with templates and operators.
As a minimal, working example:
#include<type_traits>
template<typename D>
struct S {
S(D *d): d{d} {}
template<typename B, typename = std::enable_if_t<std::is_base_of<B, D>::value>>
operator S<B>() {
return {d};
}
private:
D *d;
};
struct B {};
struct D: B {};
struct A {};
int main() {
S<D> sd{new D};
S<B> sb = sd;
// S<A> sa = sd;
}
If you toggle the comment to the last line, it won't compile anymore for A is not a base of B.
I don't know if it is what you're looking for but you can do something like this:
template <typename T>
class Derived : public T
{
};
And then instantiate it with a mother class named Base like this:
Derived<Base> object;
You will finally get this from Base:
class Derived : public Base
{
};
Related
I have a class template Base<int,int>. This class template also comes with a pure virtual method baseMethod that does not use or require the specific template values.
From this template I create multiple classes with specific template values. Those derived classes also inherit from OtherBase.
I instantiate a bunch of objects from those classes. Then all this ends up in multiple arrays of pointers to these objects, declared as arrays of pointers to objects of class OtherBase. These arrays are retrieved later, and I call baseMethod on the objects they contain. This is achieved by using a static_cast of each object in the array from OtherBase to some specific Base<int,int> e.g. Base<0,2> - because for each array, I know by design the template values of the class of the objects inside.
HERE'S THE ACTUAL QUESTION :
But what if I know want to do this more generically, i.e. for any object (so in any array) call the baseMethod of all the objects inside, knowing they are some kind of Base<int,int> but not knowing the actual template values of their class ?
Said in code :
template <int a, int b> class Base
{
public:
void baseMethod();
};
class OtherBase {};
class Foo : Base<0,1>, OtherBase {};
class Bar : Base<2,3>, OtherBase {};
OtherBase* foos[10];
OtherBase* bars[10];
OtherBase* foosOrBars[10];
/* This works. */
for(int i=0; i < 10; i++)
{
Base<0,1>* pFoo = static_cast<Base<0,1>*>foos[i];
pFoo->baseMethod();
}
/* This works. */
for(int i=0; i < 10; i++)
{
Base<0,1>* pBar= static_cast<Base<2,3>*>bars[i];
pBar->baseMethod();
}
/* How to do this though ? */
for(int i=0; i < 10; i++)
{
Base<x,x>* pFooOrBar = static_cast<Base<x,x>*>foosOrBars[i];
pFooOrBar->baseMethod();
}
Instantiations of template classes are different classes. A template is just, well, a template used to "generate" classes that "share" logic. But they aren't sharing some sort of "base" you can use as a parameter type.
If you need to write a function treating multiple classes generically, you would:
either write a template function:
(tailored to your question)
template<int a, int b>
void do_stuff(Base<a,b> b)
{
...
}
which only works for known instantiations of your Base<int,int> class:
do_stuff(Base<2,7>()); // works
or you would have to make a non-template base class:
#include <iostream>
class BaseIntInt
{
public:
virtual ~BaseIntInt() = default;
virtual void baseMethod() = 0;
};
template<int a,int b>
class Base : public BaseIntInt
{
public:
void baseMethod() override { std::cout << a << " - " << b << std::endl;}
};
void someFunctionTakingBase(BaseIntInt& b)
{
b.baseMethod();
}
int main()
{
Base<5,6> b56;
someFunctionTakingBase(b56);
}
The non-template base class is imho the better solution to your problem. It's less generated binary and way more flexible.
I don't really understand why you use a template class which have fixed data types (int in your case). Why don't simply deal a and b as data of your class. This way evrything fall inisde a simple class hieararcy:
class Base
{
public:
Base(int aa, int bb)
{
a = aa;
b = bb;
}
int a;
int b;
virtual someMethod() = 0;
};
class Derived : public Base
{
virtual void someMethod() { //some code here }
};
Consider a file main.cc with the following code:
template<typename Commodity>
class Shop
{
public:
Shop(){}
~Shop(){}
};
template<typename FuelType>
class Car
{
public:
Car(){}
virtual ~Car(){}
};
template<typename FuelType>
class Volkswagen : public Car<FuelType>
{
public:
Volkswagen(){}
~Volkswagen(){}
};
int main()
{
// this is fine...
Car<int>* myCar = new Volkswagen<int>();
delete myCar;
// ...but this isn't
Shop<Car<int>>* myCarShop = new Shop<Volkswagen<int>>();
return 0;
}
When I try to compile, I get an error:
cannot convert 'Shop<Volkswagen<int> >*' to 'Shop<Car<int> >*' in initialization...'
Now, I understand why I get this error. It's because Shop<Volkswagen<T>> in general does not have to inherit from Shop<Car<T>>.
My question is: How can I implement a structure like this? Is there a better way with classes and templates or should I, when I'm absolutely certain that Shop<Volkswagen<T>> always is a Shop<Car<T>>, attempt to explitly cast the pointer?
Edit 1: One solution could be to add a class
template<typename FuelType>
class VolkswagenShop : public Shop<Volkswagen<FuelType>>, public virtual Shop<Car<FuelType>>
{
public:
VolkswagenShop(){}
~VolkswagenShop(){}
};
and then write
Shop<Car<int>>* myCarShop = new VolkswagenShop<int>();
This compiles, but the structure has gotten complicated to a point where I, with my very limited c++ ability, am not sure if this won't cause any problems.
So, risking being too vague, will the above solution cause any obvious problems?
Template instantiation is not inheritance! foo<A> and foo<B> are two distinct and unrelated types. If you want all Shop<CARTYPE<T>> to inherit from Shop<Car<T>> then you can do that.
If it is ok to change the declaration of Shop to take 2 template parameters (and if you are not scared of template template parameters) you can do this:
template<typename FuelType>
class Car
{
public:
Car(){}
virtual ~Car(){}
};
template<typename FuelType>
class Volkswagen : public Car<FuelType>
{
public:
Volkswagen(){}
~Volkswagen(){}
};
template <template<class> class CarType,typename Commodity>
class Shop : public Shop<Car,Commodity>
{
public:
using Car_t = CarType<Commodity>;
Shop(){}
virtual ~Shop(){}
};
template <typename Commodity>
class Shop<Car,Commodity> {
virtual ~Shop(){}
};
int main()
{
// this is fine...
Car<int>* myCar = new Volkswagen<int>();
delete myCar;
// this also
Shop<Car,int>* myCarShop = new Shop<Volkswagen,int>();
delete myCarShop;
return 0;
}
However, template specialization is also not inheritance! You will need to repeat all methods in the general template and in the template <typename Commodity> class Shop<Car,Commodity> {}; specialization. To avoid code duplication you could write a ShopBase class that is not a template and provides the interface you want to use polymorphically on all shops.
PS: Mixing compile time and runtime polymorphis is possible, but I would reconsider what you really need. Taking a look at CRTP might give you some inspiration.
If one wants to implement Clone pattern in C++, he might not be sure about safety, because derived class may forget to override it:
struct A {
virtual A* Clone() const {
return new A(*this);
}
}
struct B : A {
int value;
};
int main() {
B b;
// oops
auto b_clone = b.Clone();
delete b_clone;
}
What are the possible ways to improve Clone pattern in C++ in this regard?
A more general question has been asked:
Forcing a derived class to overload a virtual method in a non-abstract base class
However, it seems to be too general to have a good solution in C++ -- the discussion is about possible ways to enforce method override. I'm more interested in discovering a useful pattern, which might help in the exact case of using Cloneable pattern.
This is an elaboration of one of the answers, suggesting runtime check using typeid:
Forcing a derived class to overload a virtual method in a non-abstract base class
Using CRTP, one can come up with the following basic idea:
Create class Cloneable<Derived>, which manages cloning for Derived, and adds all the needed runtime checks (seems like that compile-time checks are not possible even with CRTP).
However, it is not trivial, and one also has to manage inheritance through Cloneable, as described:
#include <memory>
#include <cassert>
#include <type_traits>
#include <typeinfo>
class CloneableInterface {
public:
virtual std::unique_ptr<CloneableInterface> Clone() const = 0;
};
template <class... inherit_from>
struct InheritFrom : public inherit_from... {
};
template <class Derived, class AnotherBase = void, bool base_is_cloneable = std::is_base_of_v<CloneableInterface, AnotherBase>>
class Cloneable;
// three identical implementations, only the inheritance is different
// "no base is defined" case
template <class Derived>
class Cloneable<Derived, void, false> : public CloneableInterface {
public:
std::unique_ptr<CloneableInterface> Clone() const override {
assert(typeid(*this) == typeid(Derived));
return std::make_unique<Derived>(static_cast<const Derived&>(*this));
}
};
// Base is defined, and already provides CloneableInterface
template <class Derived, class AnotherBase>
class Cloneable<Derived, AnotherBase, true> : public AnotherBase {
...
};
// Base is defined, but has no CloneableInterface
template <class Derived, class AnotherBase>
class Cloneable<Derived, AnotherBase, false> : public AnotherBase, public CloneableInterface {
...
};
Usage example:
class Base : public Cloneable<Base> {
};
// Just some struct to test multiple inheritance
struct Other {
};
struct Derived : Cloneable<Derived, InheritFrom<Base, Other>> {
};
struct OtherBase {
};
struct OtherDerived : Cloneable<OtherDerived, InheritFrom<OtherBase>> {
};
int main() {
// compiles and runs
auto base_ptr = std::make_unique<Base>();
auto derived_ptr = std::make_unique<Derived>();
auto base_clone = base_ptr->Clone();
auto derived_clone = derived_ptr->Clone();
auto otherderived_ptr = std::make_unique<OtherDerived>();
auto otherderived_clone = otherderived_ptr->Clone();
}
Any critics and improvement suggestions are welcome!
C++17 and newer offers an std::any. You could in theory, then, make a clone function that returns an std::any* instead:
struct A {
virtual std::any* Clone() const {
return new A(*this);
}
}
struct B : A {
int value;
// I suppose it doesn't have to be virtual here,
// but just in case we want to inherit the cloning capability from B as well
virtual std::any* Clone() const { // Note: you still need to override this function
return new B(*this); // in the lower levels, though
}
};
// Note: I'm still on MSVS2010, so this C++17 code is untested.
// Particularly problematic could be this main
int main() {
B b;
// Here is the clone
auto b_clone = std::any_cast<B*>(b.Clone());
delete b_clone;
}
Again, this is untested, but it should work in theory.
I have the following hierarchy pattern in various places in the codebase:
enum DerivedType {
A, B, C };
class Base {
public:
static Base* Create(DerivedType t);
};
template <DerivedType T>
class Derived : public Base {
};
The Create method returns a new object of class Derived<A>, Derived<B>, or Derived<C>, depending on its argument:
Base* Base::Create(DerivedType t) {
switch (t) {
case A: return new Derived<A>;
case B: return new Derived<B>;
case C: return new Derived<C>;
default: return NULL;
}
}
The problem is that there are many such Base -> Derived hierarchies, with essentially the same implementation of Create() copy-pasted all over the place. Is there an elegant, yet easy-to-understand way to avoid duplication here?
We can abstract away the Factory details, and rely on the client to provide us the mapping of enum to class type:
template<typename ENUM, typename T>
struct Factory
{
typedef std::map<ENUM, T*(*)()> map_type;
static map_type factoryMapping_;
static T* Create(ENUM c)
{
return factoryMapping_[c]();
}
static void Init(map_type _mapping)
{
factoryMapping_ = _mapping;
}
};
template<typename ENUM, typename T>
typename Factory<ENUM, T>::map_type Factory<ENUM,T>::factoryMapping_;
Now it's the client's job to provide us methods for creating a Base* given some enum value.
If you're willing and able to abstract away the creation of a derived class with a template, then you can save a fair bit of typing.
What I mean is, let's create a templated function to create a derived class (without any real checking for correctness):
template<typename Base, typename Derived>
Base* CreateDerived()
{
return new Derived();
}
Now I can define an enum and associated class hierarchy:
enum ClassType {A, B};
struct Foo
{
virtual void PrintName() const
{
std::cout << "Foo\n";
}
};
typedef Factory<ClassType, Foo> FooFactory ;
struct DerivedOne : public Foo
{
virtual void PrintName() const
{
std::cout << "DerivedOne\n";
}
};
struct DerivedTwo : public Foo
{
virtual void PrintName() const
{
std::cout << "DerivedTwo\n";
}
};
And then use it like so:
// set up factory
std::map<ClassType, Foo*(*)()> mapping;
mapping[A] = &CreateDerived<Foo, DerivedOne>;
mapping[B] = &CreateDerived<Foo, DerivedTwo>;
FooFactory::Init(mapping);
// Use the factory
Foo* f = FooFactory::Create(A);
f->PrintName();
Live Demo
Of course this simplifies your problem a bit, namely moving the factory details out of the base class and ignoring for a minute that the children themselves are templated. Depending on how hard it is in your domain to create a good CreateDerived function for each type, you may not end up saving a ton of typing.
EDIT: We can modify our Create function to return NULL by taking advantage of std::map::find. I omitted it for brevity. If you concerned about performance, then yes, an O(log n) search is slower asymptotically than a simple switch, but I strongly doubt this will wind up being the hot path.
You could make it a template
template<typename Base, typename Derive, template<Derive> class Derived>
Base* Base::Create(Derive t) {
switch (t) {
case Derive::A: return new Derived<Derive::A>;
case Derive::B: return new Derived<Derive::B>;
case Derive::C: return new Derived<Derive::C>;
default: return nullptr;
}
}
but that assumes that there are only ever A, B, and C in struct enum Derive.
Instead of using a C++ style enum you could use a Java style enum where each value is a singleton of a class derived from a common base.
Then define a set of pure virtual functions on the base class that create the desired flavour of derived class, and implement them appropriately in each of the singletons.
Then instead of switch (t) ... you can use t->createDerived().
Or to put it more succinctly: replace switch with polymorphism.
I have code like this:
class RetInterface {...}
class Ret1: public RetInterface {...}
class AInterface
{
public:
virtual boost::shared_ptr<RetInterface> get_r() const = 0;
...
};
class A1: public AInterface
{
public:
boost::shared_ptr<Ret1> get_r() const {...}
...
};
This code does not compile.
In visual studio it raises
C2555: overriding virtual function return type differs and is not
covariant
If I do not use boost::shared_ptr but return raw pointers, the code compiles (I understand this is due to covariant return types in C++). I can see the problem is because boost::shared_ptr of Ret1 is not derived from boost::shared_ptr of RetInterface. But I want to return boost::shared_ptr of Ret1 for use in other classes, else I must cast the returned value after the return.
Am I doing something wrong?
If not, why is the language like this - it should be extensible to handle conversion between smart pointers in this scenario? Is there a desirable workaround?
Firstly, this is indeed how it works in C++: the return type of a virtual function in a derived class must be the same as in the base class. There is the special exception that a function that returns a reference/pointer to some class X can be overridden by a function that returns a reference/pointer to a class that derives from X, but as you note this doesn't allow for smart pointers (such as shared_ptr), just for plain pointers.
If your interface RetInterface is sufficiently comprehensive, then you won't need to know the actual returned type in the calling code. In general it doesn't make sense anyway: the reason get_r is a virtual function in the first place is because you will be calling it through a pointer or reference to the base class AInterface, in which case you can't know what type the derived class would return. If you are calling this with an actual A1 reference, you can just create a separate get_r1 function in A1 that does what you need.
class A1: public AInterface
{
public:
boost::shared_ptr<RetInterface> get_r() const
{
return get_r1();
}
boost::shared_ptr<Ret1> get_r1() const {...}
...
};
Alternatively, you can use the visitor pattern or something like my Dynamic Double Dispatch technique to pass a callback in to the returned object which can then invoke the callback with the correct type.
There is a neat solution posted in this blog post (from Raoul Borges)
An excerpt of the bit prior to adding support for mulitple inheritance and abstract methods is:
template <typename Derived, typename Base>
class clone_inherit<Derived, Base> : public Base
{
public:
std::unique_ptr<Derived> clone() const
{
return std::unique_ptr<Derived>(static_cast<Derived *>(this->clone_impl()));
}
private:
virtual clone_inherit * clone_impl() const override
{
return new Derived(*this);
}
};
class concrete: public clone_inherit<concrete, cloneable>
{
};
int main()
{
std::unique_ptr<concrete> c = std::make_unique<concrete>();
std::unique_ptr<concrete> cc = c->clone();
cloneable * p = c.get();
std::unique_ptr<clonable> pp = p->clone();
}
I would encourage reading the full article. Its simply written and well explained.
You can't change return types (for non-pointer, non-reference return types) when overloading methods in C++. A1::get_r must return a boost::shared_ptr<RetInterface>.
Anthony Williams has a nice comprehensive answer.
What about this solution:
template<typename Derived, typename Base>
class SharedCovariant : public shared_ptr<Base>
{
public:
typedef Base BaseOf;
SharedCovariant(shared_ptr<Base> & container) :
shared_ptr<Base>(container)
{
}
shared_ptr<Derived> operator ->()
{
return boost::dynamic_pointer_cast<Derived>(*this);
}
};
e.g:
struct A {};
struct B : A {};
struct Test
{
shared_ptr<A> get() {return a_; }
shared_ptr<A> a_;
};
typedef SharedCovariant<B,A> SharedBFromA;
struct TestDerived : Test
{
SharedBFromA get() { return a_; }
};
Here is my attempt :
template<class T>
class Child : public T
{
public:
typedef T Parent;
};
template<typename _T>
class has_parent
{
private:
typedef char One;
typedef struct { char array[2]; } Two;
template<typename _C>
static One test(typename _C::Parent *);
template<typename _C>
static Two test(...);
public:
enum { value = (sizeof(test<_T>(nullptr)) == sizeof(One)) };
};
class A
{
public :
virtual void print() = 0;
};
class B : public Child<A>
{
public:
void print() override
{
printf("toto \n");
}
};
template<class T, bool hasParent = has_parent<T>::value>
class ICovariantSharedPtr;
template<class T>
class ICovariantSharedPtr<T, true> : public ICovariantSharedPtr<typename T::Parent>
{
public:
T * get() override = 0;
};
template<class T>
class ICovariantSharedPtr<T, false>
{
public:
virtual T * get() = 0;
};
template<class T>
class CovariantSharedPtr : public ICovariantSharedPtr<T>
{
public:
CovariantSharedPtr(){}
CovariantSharedPtr(std::shared_ptr<T> a_ptr) : m_ptr(std::move(a_ptr)){}
T * get() final
{
return m_ptr.get();
}
private:
std::shared_ptr<T> m_ptr;
};
And a little example :
class UseA
{
public:
virtual ICovariantSharedPtr<A> & GetPtr() = 0;
};
class UseB : public UseA
{
public:
CovariantSharedPtr<B> & GetPtr() final
{
return m_ptrB;
}
private:
CovariantSharedPtr<B> m_ptrB = std::make_shared<B>();
};
int _tmain(int argc, _TCHAR* argv[])
{
UseB b;
UseA & a = b;
a.GetPtr().get()->print();
}
Explanations :
This solution implies meta-progamming and to modify the classes used in covariant smart pointers.
The simple template struct Child is here to bind the type Parent and inheritance. Any class inheriting from Child<T> will inherit from T and define T as Parent. The classes used in covariant smart pointers needs this type to be defined.
The class has_parent is used to detect at compile time if a class defines the type Parent or not. This part is not mine, I used the same code as to detect if a method exists (see here)
As we want covariance with smart pointers, we want our smart pointers to mimic the existing class architecture. It's easier to explain how it works in the example.
When a CovariantSharedPtr<B> is defined, it inherits from ICovariantSharedPtr<B>, which is interpreted as ICovariantSharedPtr<B, has_parent<B>::value>. As B inherits from Child<A>, has_parent<B>::value is true, so ICovariantSharedPtr<B> is ICovariantSharedPtr<B, true> and inherits from ICovariantSharedPtr<B::Parent> which is ICovariantSharedPtr<A>. As A has no Parent defined, has_parent<A>::value is false, ICovariantSharedPtr<A> is ICovariantSharedPtr<A, false> and inherits from nothing.
The main point is as Binherits from A, we have ICovariantSharedPtr<B>inheriting from ICovariantSharedPtr<A>. So any method returning a pointer or a reference on ICovariantSharedPtr<A> can be overloaded by a method returning the same on ICovariantSharedPtr<B>.
Mr Fooz answered part 1 of your question. Part 2, it works this way because the compiler doesn't know if it will be calling AInterface::get_r or A1::get_r at compile time - it needs to know what return value it's going to get, so it insists on both methods returning the same type. This is part of the C++ specification.
For the workaround, if A1::get_r returns a pointer to RetInterface, the virtual methods in RetInterface will still work as expected, and the proper object will be deleted when the pointer is destroyed. There's no need for different return types.
maybe you could use an out parameter to get around "covariance with returned boost shared_ptrs.
void get_r_to(boost::shared_ptr<RetInterface>& ) ...
since I suspect a caller can drop in a more refined shared_ptr type as argument.