Jump to content
  • Advertisement
Sign in to follow this  

[C++] Covariant return types + smart pointers

This topic is 4345 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
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!