Re: C++ language: Cloneable classes
On 9 Mai, 05:31, Krzysztof Czainski <1czaj...@gmail.com> wrote:
My final approach:
[code]
/** Cloneable interface for classes.
* @author Krzysztof Czainski
* @created 2008.05.04
*/
#pragma once
#include <memory>
#include <boost/assert.hpp>
#include <boost/cast.hpp>
/////////////////////////////////////////////////////////////////////////////
/** Inherit virtually. Base class for Cloneable<> and
NaturallyCloneable<> */
class CloneableBase
{
public:
/** @safety AC- */
virtual ~CloneableBase() {};
protected:
/** @returns new copy of *this
* @safety aCI */
virtual CloneableBase* doClone() const = 0 ;
};
/////////////////////////////////////////////////////////////////////////////
/** class User : public Cloneable<User> */
template < typename Derived >
class Cloneable : public virtual CloneableBase
{
public:
typedef std::auto_ptr<Derived> AutoPtr;
/** @safety aCI */
AutoPtr clone() const
{
return
AutoPtr( boost::polymorphic_downcast<Derived*>( doClone() ) );
}
};
/////////////////////////////////////////////////////////////////////////////
/** class UserFinal : public NaturallyCloneable<UserFinal> */
template < typename Derived >
class NaturallyCloneable : public virtual CloneableBase
{
protected:
/** @override CloneableBase
* @safety aCI */
virtual CloneableBase* doClone() const
{
// prevent slicing and assert corectnes of static_cast
BOOST_ASSERT( typeid(*this) == typeid(Derived) );
return new Derived( static_cast< const Derived& >(*this) );
}
};
[/code]
I won't use the improved version of Daniel Kr?gler's code, because in
the example below class NaturallyCloneable<B> wouldn't provide
implementation for Cloneable<A>::doClone, which would make it
abstract.
This is true. In my recent reply, I just wanted to present you the
most
similar approach given your original idea. As expressed in my OP, I
also think that CloneableBase should have a protected doClone()
member function, otherwise the class name does not make much
sense from a user perspective.
I still think that it would be fine to add:
protected:
virtual Cloneable* doClone() const = 0;
to your most recent Cloneable definition to exclude some corner
cases statically (boost::polymorphic_downcast will catch these
of-course for debug builds).
An interesting enhancement proposal for Cloneable could be to
add one further template parameter as smart-pointer policy like
this:
template <typename Derived, typename PtrPolicy =
std::auto_ptr<Derived> >
class Cloneable : public virtual CloneableBase
{
// Compile-time check of the smart pointer:
BOOST_STATIC_ASSERT((boost::is_same<Derived, typename
PtrPolicy::element_type>::value));
// Alternatively you could make the compile check a bit more
tolerant:
BOOST_STATIC_ASSERT((boost::is_base_of<Derived, typename
PtrPolicy::element_type>::value));
public:
typedef PtrPolicy Ptr;
Ptr clone() const {
return
Ptr( boost::polymorphic_downcast<Derived*>( doClone() ) );
}
protected:
virtual Cloneable* doClone() const = 0;
};
Example:
[code]
class A : public Cloneable<A> {}; // abstract base for B and C
class B : public A, public NaturallyCloneable<B> {};
class C : public A { virtual A* doClone() const { /* return hand-made
copy of *this */ } };
[/code]
Yes, this is fine. And by means of the virtual inheritance you
simulate what other languages usually call "interface" (but
you know that). And if you use Cloneable<D, boost::shared_ptr<D> >
this will match the style of those languages even more ;-)
Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]