Return Type Covariance with Smart Pointers

You can’t do it directly, but there are a couple of ways to simulate it, with the help of the Non-Virtual Interface idiom.

Use covariance on raw pointers, and then wrap them

struct Base
{
private:
   virtual Base* doClone() const { ... }

public:
   shared_ptr<Base> Clone() const { return shared_ptr<Base>(doClone()); }

   virtual ~Base(){}
};

struct Derived : Base
{
private:
   virtual Derived* doClone() const { ... }

public:
   shared_ptr<Derived> Clone() const { return shared_ptr<Derived>(doClone()); }
};

This only works if you actually have a raw pointer to start off with.

Simulate covariance by casting

struct Base
{
private:
   virtual shared_ptr<Base> doClone() const { ... }

public:
   shared_ptr<Base> Clone() const { return doClone(); }

   virtual ~Base(){}
};

struct Derived : Base
{
private:
   virtual shared_ptr<Base> doClone() const { ... }

public:
   shared_ptr<Derived> Clone() const
      { return static_pointer_cast<Derived>(doClone()); }
};

Here you must make sure that all overrides of Derived::doClone do actually return pointers to Derived or a class derived from it.

Leave a Comment