On 9 Mai, 05:31, Krzysztof Czainski <1czaj...@[EMAIL PROTECTED]
> wrote:
> My final approach:
>
> [code]
> /** Cloneable interface for cl*****.
> * @[EMAIL PROTECTED]
Krzysztof Czainski
> * @[EMAIL PROTECTED]
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:
>
> /** @[EMAIL PROTECTED]
AC- */
> virtual ~CloneableBase() {};
>
> protected:
>
> /** @[EMAIL PROTECTED]
new copy of *this
> * @[EMAIL PROTECTED]
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;
>
> /** @[EMAIL PROTECTED]
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:
>
> /** @[EMAIL PROTECTED]
CloneableBase
> * @[EMAIL PROTECTED]
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! ]


|