Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to accomplish covariant return types when returning a shared_ptr?

using namespace boost;

class A {};
class B : public A {};

class X {
  virtual shared_ptr<A> foo();
};

class Y : public X {
  virtual shared_ptr<B> foo();
};

The return types aren't covariant (nor are they, therefore, legal), but they would be if I was using raw pointers instead. What's the commonly accepted idiom to work around this, if there is one?

like image 981
Kyle Avatar asked Apr 22 '10 02:04

Kyle


2 Answers

I think that a solution is fundamentally impossible because covariance depends on pointer arithmetic which is incompatible with smart pointers.

When Y::foo returns shared_ptr<B> to a dynamic caller, it must be cast to shared_ptr<A> before use. In your case, a B* can (probably) simply be reinterpreted as an A*, but for multiple inheritance, you would need some magic to tell C++ about static_cast<A*>(shared_ptr<B>::get()).

like image 148
Potatoswatter Avatar answered Nov 07 '22 20:11

Potatoswatter


Not directly, but you can fake it by making the actual virtual functions inaccessible from outside the class and wrapping the virtual function call into a non-virtual function. Downside is that you'll have to remember to implement this wrapper function on each derived class. But you could get around this by puting both the virtul function declaration and the wrapper into the macro.

using namespace boost; // for shared_ptr, make_shared and static_pointer_cast.

// "Fake" implementation of the clone() function.
#define CLONE(MyType) \
    shared_ptr<MyType> clone() \
    { \
        shared_ptr<Base> res = clone_impl(); \
        assert(dynamic_cast<MyType*>(res.get()) != 0); \
        return static_pointer_cast<MyType>(res); \
    }

class Base 
{
protected:
    // The actual implementation of the clone() function. 
    virtual shared_ptr<Base> clone_impl() { return make_shared<Base>(*this); }

public:
    // non-virtual shared_ptr<Base> clone();
    CLONE(Base)
};

class Derived : public Base
{
protected:
    virtual shared_ptr<Base> clone_impl() { return make_shared<Derived>(*this); }

public:
    // non-virtual shared_ptr<Derived> clone();
    CLONE(Derived)
};


int main()
{
    shared_ptr<Derived> p = make_shared<Derived>();
    shared_ptr<Derived> clone = p->clone();

    return 0;
}
like image 43
sdkljhdf hda Avatar answered Nov 07 '22 20:11

sdkljhdf hda