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.
Related
I have two class hierarchies which have a 1:1 relationship: some normal classes A, B which have a common Root interface, and a WrapperRoot<T> interface with two concrete instantiations WrapperA<T> and WrapperB<T>. I am now looking to implement a function auto wrap<T>(Root& elem) -> unique_ptr<WrapperRoot<T>> that maps each normal class to its wrapper class.
The exact type of the wrappers is important as they will have virtual methods, and the exact type of the Root objects is not statically known.
Attempted solutions
My first idea was to declare a template virtual method in Root:
class Root {
...
public:
template<typename T>
virtual auto wrap() -> unique_ptr<WrapperRoot<T>> = 0;
}
which could then be implemented in the child classes as
class A : public Root {
...
template<typename T>
virtual auto wrap() -> unique_ptr<WrapperRoot<T>> override {
return make_unique<WrapperA<T>>();
}
}
As I was to find out, C++ does not allow templates for virtual methods. I did some further research and found the technique of type erasure, which allows us to break through this virtual vs. template dichtomy. Perhaps it might be possible to have each class select their wrapper type by passing in a visitor-like object that has erased the template parameter <T>? However, I am still fairly new to C++, and all my attempts to implement this have only moved the problem into another level, but not solved them.
This is especially frustrating since other languages which I am familiar with have no problem expressing this structure. E.g. in Java it is no problem to define a virtual method <T> WrapperRoot<T> wrap() { return new WrapperA<T>(); }, but that is because Java implements templates via reinterpreting casts. Java's implementation would be phrased in C++ as:
template<typename T>
WrapperRoot<T>* wrap() { return reinterpret_cast<WrapperRoot<T>*>(wrapper_impl()); }
virtual void* wrapper_impl() { return new WrapperA<void*>() }
However, I would like to work with the C++ type system rather than violating it by casting void pointers around.
Test Case
To phrase my problem unambiguously, I have created the below test case. Once wrap is implemented correctly, it should output this:
WrapperA
WrapperB
The main method should not be modified, but arbitrary methods, helper types, and an implementation for the wrap function may be added.
#include <iostream>
#include <memory>
using namespace std;
// the Root hierarchy
class Root {
public:
virtual ~Root() {}
};
class A : public Root {};
class B : public Root {};
// the Wrapper hierarchy
template<typename T>
class WrapperRoot {
public:
virtual ~WrapperRoot() {}
virtual T name() = 0;
};
template<typename T>
class WrapperA : public WrapperRoot<T> {
public:
virtual T name() { return T("WrapperA\n"); }
};
template<typename T>
class WrapperB : public WrapperRoot<T> {
public:
virtual T name() { return T("WrapperB\n"); }
};
// the "wrap" function I want to implement
template<typename T>
auto wrap(Root& ) -> unique_ptr<WrapperRoot<T>>;
// util
template<typename T, typename... Args>
auto make_unique(Args... args) -> unique_ptr<T> {
return unique_ptr<T>(new T(forward<Args>(args)...));
}
int main() {
unique_ptr<Root> a = make_unique<A>();
unique_ptr<Root> b = make_unique<B>();
cout << wrap<string>(*a)->name()
<< wrap<string>(*b)->name();
}
How can I make this work? Or do I need to resort to type-violating hacks?
The simplest way to get this to work would just be dynamic_casting the Root& to work out what the runtime type of it is:
template<typename T>
auto wrap(Root& root) -> unique_ptr<WrapperRoot<T>>
{
if (dynamic_cast<A*>(&root)) {
//root is an A, return a WrapperA
return make_unique<WrapperA<T>>();
}
else if (dynamic_cast<B*>(&root)) {
//root is a B, return a WrapperB
return make_unique<WrapperB<T>>();
}
throw std::runtime_error("No wrapper for that type");
}
Demo
As it turns out, this can be solved with type erasure, the Visitor Pattern, and a bit of indirection. The solution is clean, and does not require us to re-implement dynamic dispatch inside the wrap function.
The core idea is to introduce a WrapperSelector visitor interface:
class WrapperSelector {
public:
virtual auto visit(A&) -> void = 0;
virtual auto visit(B&) -> void = 0;
};
The Root hierarchy needs to be modified a bit to accept this visitor, and to perform the double dispatch:
class Root {
public:
virtual ~Root() {}
virtual auto accept(WrapperSelector&) -> void = 0;
};
class A : public Root {
public:
virtual auto accept(WrapperSelector& wrapper) -> void {
wrapper.visit(*this);
}
};
class B : public Root {
public:
virtual auto accept(WrapperSelector& wrapper) -> void {
wrapper.visit(*this);
}
};
So far, this is the bog-standard Visitor Pattern in C++. What we now do is introduce a templated class WrapperSelectorImpl<T> : public WrapperSelector. Since it is templated but only used through the un-templated interface, this implements type erasure. Internally, we construct this WrapperSelectorImpl as a container for a borrowed WrapperRoot<T> pointer, into which we write the selected wrapper. After the accept/visit sequence has ended, that pointer will be filled with the wrapper, so no virtual method needs to return a template-parameterized type. Also, the accept method does nothing but select the corresponding visit method, so the types in the Root hierarchy don't need to know about the WrapperRoot hierarchy – a concrete WrapperSelector will handle this mapping.
template<typename T>
class WrapperSelectorImpl : public WrapperSelector {
unique_ptr<WrapperRoot<T>>& _wrapper;
public:
explicit WrapperSelectorImpl(unique_ptr<WrapperRoot<T>>& wrapper)
: _wrapper(wrapper)
{}
virtual auto visit(A&) -> void override {
_wrapper = make_unique<WrapperA<T>>();
}
virtual auto visit(B&) -> void override {
_wrapper = make_unique<WrapperB<T>>();
}
};
Our wrap function must now set up a pointer, a WrapperSelectorImpl which borrows that pointer, let the given object in the Root hierarchy select the wrapper through the WrapperSelector, and return the now-populated pointer:
template<typename T>
auto wrap(Root& obj) -> unique_ptr<WrapperRoot<T>> {
unique_ptr<WrapperRoot<T>> wrapper;
WrapperSelectorImpl<T> wrapper_selector(wrapper);
obj.accept(wrapper_selector);
return wrapper;
}
Generalization
The above technique can be used to implement arbitrary templated virtual methods, or the visitor pattern with arbitrary return types. The prerequisites for this is minimal support for the Visitor Pattern`:
some Subject class or class hierarchy with a virtual void accept(SubjectVisitor& v) { v.visit(*this); }.
some SubjectVisitor interface with virtual void visit(S&) = 0 methods for each class S in the Subject class hierarchy.
Now assume we wish to implement a method with the following pseudo-signature in the Subject hierarchy:
class Subject {
...
template<typename R, typename T, typename... Args>
virtual R frobnicate(Args... args) = 0;
}
We can then use the following steps to implement this:
First, we create a wrapper function that exposes the public interface of our dispatching logic. This might be a non-virtual templated method in Subject, or a free function. The internals are the same as in the above example: Set-up of the return value, set-up of the visitor (borrowing a reference to the return value), doing the dispatch, and returning the value.
Since this is so general, we can pack this into a reusable templated function:
// most general implementation
template<typename ReturnType, typename Subject, typename Visitor, typename... Args>
auto manage_visitor(Subject& subject, Args... args) -> ReturnType {
ReturnType return_value;
Visitor visitor(return_value, std::forward(args)...);
subject.accept(visitor);
return return_value;
}
class Subject {
...
template<typename R, typename T, typename... Args>
R frobnicate(Args... args) {
return manage_visitor<R, Subject, ConcreteSubjectVisitor<R, T>>(*this, std::forward(args)...);
}
};
Note that this assumes the return value to be default-constructible. If this is not the case, substituting unique_ptr<ReturnType> for ReturnType could be a solution.
We now have to provide a class ConcreteSubjectVisitor : public SubjectVisitor that provides the actual implementation.
template<typename ReturnType, typename T>
class ConcreteSubjectVisitor : public SubjectVisitor {
ReturnType& return_value;
ArgType something;
public:
ConcreteSubjectVisitor(ReturnType& ret, ArgType& other_arg) : return_value(ret), something(other_arg) {}
virtual void visit(S1&) override { ... }
virtual void visit(S2&) override { ... }
...
};
The only thing which matters is that it can write to the return value. Note that the visitor can take additional arguments through the constructor, which makes it somewhat related to the std::bind function or to constructing a lambda. The visit definitions then contain the actual code, which has access to all type parameters of the visitor, and all constructor arguments of the visitor.
Open problems:
handling of return types that are not default-constructible (pointers or custom defaults)
specialization for void return type (problem decays to “normal” visitor pattern)
generalization to full multi-methods (trivial if method is in curried form)
providing a convenient interface
const-correctness (must be applied on a per-visitor basis, Subject::accept can be provided as const and non-const).
I want to implement a class hierarchy for object dispatching. Different classes dispatch different elements, and each class can dispatch its element represented as different data types.
It is better understood through a (faulty) example. This is what I would like to have if virtual function templating was allowed:
class Dispatcher {
template <class ReturnType>
virtual ReturnType getStuffAs();
};
So that I can implement subclasses as:
class CakeDispatcher : public Dispatcher {
template <>
virtual Recipe getStuffAs(){ ... }
template <>
virtual Baked getStuffAs(){ ... }
};
class DonutDispatcher : public Dispatcher {
template <>
virtual Frozen getStuffAs(){ ... }
template <>
virtual Baked getStuffAs(){ ... }
}
So that I can do the following later on:
void function( Dispatcher * disp ) {
// Works for Donut and Cake, but result will be a different Baked object
Baked b = disp->getStuffAs<Baked>();
// works if disp points to a DonutDispatcher
// fails if it is a CakeDispatcher
// can be compiling/linking time error or runtime error. I don't care
Frozen f = disp->getStuffAs<Frozen>();
}
Requirements/constraints:
All possible return types are not known beforehand. That's why I "need" templates.
Each class can provide just some return types.
Classes must have a common ancestor, so that I can store objects through a pointer to parent class and invoke functions through this pointer.
EDIT: I CAN'T use C++11 features, but I CAN use boost library.
Things I've thought about, but are not a solution:
Obviously, virtual template functions
Curiously Recurring Template Pattern: breaks the condition of common ancestor
Using some kind of traits class containing the functionality of children classes, but it does not work because a non-virtual implementation in the parent class does not have access to this information
I could maybe store some typeid info in the parent class, passed by children on construction. This makes possible for the non-virtual parent dispatching method to dynamic-cast itself to the children type... but it appears to be ugly as hell, and I don't know if this can cause some kind cycle-referencing problem.
class Dispatcher {
private:
typeid(?) childType;
public:
Dispatcher(typeid childT) : childType(childT) {}
// NOT VIRTUAL
template <class ReturnType>
ReturnType getStuffAs()
{
// or something equivalent to this cast, which I doubt is a correct expression
return dynamic_cast<childType *>(this)->childGetStuffAs<ReturnType>();
}
};
Then child classes would implement childGetStuffAs functions, which are not virtual too.
I've read like 5-10 related questions, but none of the provided solutions seems to fit this problem.
Can any of you come up with a better solution?
Is there a standard pattern/technique for solving this problem?
EDIT: The real problem
In the real problem, I have physical models with properties that can be represented in multiple ways: functions, matrices, probability distributions, polynomials, and some others (for example, a non-linear system can be represented as a function but not as a a matrix, while a linear system can be transformed to both).
There are also algorithms which can use those models indistinctly, but they could require specific representations for some model features. That's the reason for the "getStuffAs" function. The whole think is a bit complicated --too much to explain it here properly--, but I can guarantee that in this context the interface is well defined: input, computation and output.
My intention was to make this possible assuming that the number of possible representations is fully defined beforehand, and making it possible to transform the products to already existing types/classes that cannot be modified.
However, i'm starting to realize that this is, indeed, not possible in a simple way --I don't want to write a library just for this problem.
#include <cstdio>
// as a type identifier
struct stuff {
virtual void foo() {}
};
template <typename T>
struct stuff_inh : stuff {
};
struct Dispatcher {
template <typename T>
T* getStuffAs() {
return (T*)((getStuffAsImpl( new stuff_inh<T>() )));
}
virtual void* getStuffAsImpl(void*) = 0;
virtual void type() {printf("type::dispatcher\n");}
};
struct Cake : public Dispatcher {
void* getStuffAsImpl(void* p) {
stuff* s = static_cast<stuff*>(p);
printf("cake impl\n");
if (dynamic_cast<stuff_inh<Cake>*>(s) == NULL) {
throw "bad cast";
}
return (void*)(new Cake());
}
virtual void type() {printf("type::Cake\n");}
};
struct Rabbit : public Dispatcher {
void* getStuffAsImpl(void* p) {
stuff* s = static_cast<stuff*>(p);
printf("rabbit impl\n");
if (dynamic_cast<stuff_inh<Rabbit>*>(s) != NULL) {
return (void*)(new Rabbit());
}
else if (dynamic_cast<stuff_inh<Cake>*>(s) != NULL) {
return (void*)(new Cake());
}
else {
throw "bad cast";
}
}
virtual void type() {printf("type::Rabbit\n");}
};
void foo(Dispatcher* d) {
d->getStuffAs<Cake>()->type();
d->getStuffAs<Rabbit>()->type();
}
int main() {
Rabbit* r = new Rabbit;
foo(r);
Cake* c = new Cake;
foo(c);
}
I an not sure about the correctness of this ugly solution, may it be helpful for you. >_<
deletion of resource is not coded for a clearer look.
My solution is a combination of recurring template and diamond inheritance.
At least it's working. :)
#include <iostream>
class Dispatcher
{
public:
template<class T>
T getStuff()
{
return T();
}
};
template<class T>
class Stuffer : public Dispatcher
{
public:
template<class TT=T>
TT getStuff(){
return reinterpret_cast<TT>(this);
}
};
class Cake{
public:
Cake(){}
void print()
{
std::cout << "Cake" << std::endl;
}
};
class Recipe
{
public:
Recipe(){}
void print()
{
std::cout << "Recipe" << std::endl;
}
};
class CakeRecipe : public Stuffer<Cake>, public Stuffer< Recipe >
{
public:
};
int main()
{
Dispatcher* cr = reinterpret_cast<Dispatcher*>(new CakeRecipe());
cr->getStuff<Cake>().print();
cr->getStuff<Recipe>().print();
getchar();
return 1;
}
I'm having some trouble figuring out if I can use templated generic constraints in C++/CLI. here's an example
template<typename T>
public ref class wrapped
{
public:
T* t;
T doTthing(){return *t;}
};
Here's a simple templated managed class, wrapping an unmanaged type T. I can use this class as a constraint for a generic
// works
generic<class genclass> where genclass : wrapped<int>
public ref class testclass3
{
public:
genclass gc;
int test()
{
return gc->doTthing();
}
};
This works fine. What I can't figure out is how to preserve both the templating and the generic, i.e.
//Does Not Work!
template<typename T>
generic<class genclass> where genclass : wrapped<T>
public ref class testclass4
{
public:
genclass gc;
T test()
{
return gc->doTthing();
}
};
Is this kind of thing possible?
You can't mix templates with generics in the same declaration.
The class should either be templated or generic. See: Managed Templates
Templates are mush more expressive, so i would suggest you use them instead.
If you want to simulate a constraint (same technique would work in c++ by the way..) you could do:
template<class T, class GENCLASS>
public ref class testclass4
{
private:
typedef typename GENCLASS::wrapped<T> Constraint1;
public:
genclass gc;
T test()
{
return gc->doTthing();
}
};
If the class does not inherit from wrapped<T> then the typedef declaration will fail saying that "wrapped is not a member of GENCLASS".
This is best described in pseudo-code:
class Thing {};
interface ThingGetter<T extends Thing> {
T getThing();
}
class Product extends Thing {};
class ProductGetter<Product> {
Product getThing() {
// Some product code
}
}
class SpecialProductGetter extends ProductGetter {
Product getThing() {
p = ProductGetter::getThing();
// Do some special stuff;
return p;
}
}
class NeatProductGetter extends ProductGetter {
Product getThing() {
p = ProductGetter::getThing();
// Do some neat stuff;
return p;
}
}
I will have other "things" with other getters for those as well.
I've tried codifying this in C++ but it doesn't like :
template <> class ThingGetter <Product> {
nor:
class NeatProductGetter : public ThingGetter <Product> {
Can you model this in C++ without making getThing return a Thing and then having to cast it like crazy?
If so, how? If not, what is the best way to do this?
Thanks!
Since the question comes from someone with a Java background, I will interpret it in Java terms. You want to define a generic interface that will return an object derived from T:
template<typename T>
struct getter
{
virtual T* get() = 0; // just for the signature, no implementation
};
Note the changes: the function is declared virtual so that it will behave polimorphically in derived objects. The return value is a pointer instead of an object. If you keep an object in your interface, the compiler will slice (cut the non-base part of the returned object) the return. With some metaprogramming magic (or resorting to boost) you can have the compiler test the constraint that T derives from a given type.
Now the question is why you would like to do so... If you define a non-generic interface (abstract class) that returns a Thing by pointer you can just get the same semantics more easily:
struct Thing {};
struct AnotherThing : public Thing {};
struct getter
{
virtual Thing* get() = 0;
};
struct AnotherGetter : public getter
{
virtual AnotherThing* get() { return 0; }
};
struct Error : public getter
{
int get() { return 0; } // error conflicting return type for get()
};
struct AnotherError : public getter
{
};
int main() {
AnotherError e; // error, AnotherError is abstract (get is still pure virtual at this level)
}
The compiler will require all instantiable classes derived from getter to implement a get() method that returns a Thing by pointer (or a covariant return type: pointer to a class derived from Thing). If the derived class tries to return another type the compiler will flag it as an error.
The problem, as you post it is that if you use the interface, then the objects can only be handled as pointers to the base Thing class. Now, whether that is a problem or not is another question... In general, if you have correctly designed your hierarchy, you should be able to use the returned objects polimorphically without having to resort to down casting.
Note that if you are using the different getters at the most derived level in the hierarchy, each get() method returns the most derived element from the Thing hierarchy, at that point you will not need to down cast at all. Only if you use the different getters through the base getter interface you will get the same return type for all (Thing*)
It is important to note that templates are resolved completely at compile time. That means that trying to use templates to solve the need (do you really need it?) to downcast will not help you if you use the different getters through the interface (reference/pointers to the basic getter).
Maybe posting a little more details on your specific domain, where and how you intend to use this code, can help in providing more useful responses.
In C++, this would look like this:
(I've changed "class" to "struct" to avoid a bunch of "public:" declarations. It's the same thing, though.)
class Thing { };
template <typename T>
struct ThingGetter {
T getThing();
};
struct Product : public Thing { };
struct ProductGetter : public ThingGetter<Product>{
Product getThing() { return Product(); }
};
struct SpecialProductGetter : public ProductGetter {
Product getThing() {
Product p = this->ProductGetter::getThing();
return p;
}
};
struct NeatProductGetter : public ProductGetter {
Product getThing() {
Product p = ProductGetter::getThing();
return p;
}
};
...
SpecialProductGetter spg;
spg.getThing();
NeatProductGetter npg;
npg.getThing();
Another solution is to use template specialization:
struct Thing { };
struct Widget { };
template <typename T>
struct Getter {
T getIt() = 0;
};
template <>
struct Getter<Thing> {
Thing getIt() { return Thing(); }
};
template <>
struct Getter<Widget> {
Widget getIt() { return Widget(); }
};
typedef Getter<Widget> WidgetGetter;
struct SpecialWidgetGetter : public WidgetGetter {
Widget getIt() { return this->WidgetGetter::getIt(); }
};
struct FizzledWidgetGetter : public WidgetGetter {
Widget getFizzledWidget() { return getIt().fizzle(); }
};
...
Getter<Thing> tg;
tg.getIt();
WidgetGetter wg;
wg.getIt();
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.