• Advertisement
Sign in to follow this  

[C++] Covariant return types + smart pointers

This topic is 4258 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Is there any way to combine convariant return types with smart pointers? I currently have some code that is similar to this:
struct base
{
public:
    virtual base* clone()const = 0;
};

struct derived : base
{
    derived* clone()const
    {
        return new derived;
    }
};


I wanted to change the return type of the clone() function to use a smart pointer, but I can't get it to compile because the compiler/language doesn't recognise the covariance as it would for raw pointers...
struct base
{
public:
    virtual std::auto_ptr<base> clone()const = 0;
};

struct derived : base
{
    std::auto_ptr<derived> clone()const
    {
        return new derived;
    }
};


Does anyone know of a technique to bypass this limitation?

Share this post


Link to post
Share on other sites
Advertisement
Even though Base and Derived are related, auto_ptr<Base> and auto_ptr<Derived> aren't. You cannot use covariant returns.

I do not know of any workarounds. Use auto_ptr<Base>.

Share this post


Link to post
Share on other sites
So it's choice between passing about raw pointers to dynamically allocated memory and having to dynamic_cast the result of clone() in some situations.

I'll probably choose to leave clone() as it is and just be careful to store the result in an auto_ptr of an appropriate type.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster

#include

class base {
virtual base* do_clone() const = 0;
public:
typedef std::auto_ptr base_ptr;
base_ptr clone() const {
return base_ptr(do_clone());
}
virtual ~base() {}
};

class derived : public base {
derived* do_clone() const { return new derived; }
};


snk_kid here to annoy.

Share this post


Link to post
Share on other sites
Covariant return types in C++ are quite limited in that you can only replace the base class type by a derived class type. So they are not a solution here.

However, you may use the following contraption with only a little higher cost:

class Base {
protected:
virtual Base * cloneImpl() const = 0;
public:
std::auto_ptr<Base> clone() const { return std::auto_ptr<Base>( this->cloneImpl() ); }
};

class Derived : public Base {
protected:
virtual Derived * cloneImpl() const { return new Derived; }
public:
std::auto_ptr<Derived> clone() const { return std::auto_ptr<Derived>( this->cloneImpl() ); }
};




This way, covariant types are used through pointers in a protected area while fake covariant types are simulated by overriding.

EDIT: snk_kid, you may be faster but I put those two minutes to good use in formatting my answer! [grin] and you forgot the virtual and protected: details [rolleyes]

Share this post


Link to post
Share on other sites
This is what I have so far. Can anyone see any problem / potential improvements?


class cloneable
{
public:
virtual ~cloneable(){}

std::auto_ptr<cloneable> clone()const
{
return auto_clone<cloneable>();
}

protected:
template <class T>
std::auto_ptr<T> auto_clone()const
{
// checks that we aren't object slicing
T* ptr = cloneImpl();
assert( typeid(*ptr) == typeid(*this) );
return std::auto_ptr<T>(ptr);
}

private:
//virtual clone operation
virtual cloneable* cloneImpl()const=0;
};



I've added in a check to prevent object slicing in the case where a child class forgets to implement a cloneImpl function when one of it's ancestor classes has implemented cloneImpl. Unfortunatley it's only a run-time check, I don't think it's possible to do the check at compile time.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement