// Remove "x" to invoke feature.
#define xTEST_ABSTRACT_CLONE
#if defined( CPP11 )
# define OVERRIDE override
# define IS_DELETED = delete
# include <memory>
template< class Type >
struct Ownership { using Ptr = std::unique_ptr<Type>; };
#else
# define OVERRIDE
# define IS_DELETED
# include <memory> // Note: std::auto_ptr is deprecated.
template< class Type >
struct Ownership { typedef std::auto_ptr<Type> Ptr; };
#endif
//---------------------------------------------------------------------------
#include <assert.h> // assert
#include <iostream> // std::wcout, std::wcerr, std::endl
#include <memory> // std::unique_ptr
#include <string> // std::string
#include <typeinfo> // std::typeinfo, i.e. typeid usage.
using namespace std;
class Cloneable
{
private:
virtual Cloneable* virtualClone() const = 0;
protected:
virtual ~Cloneable() {}
};
template< class DerivedClass, class BaseClass >
class WithCloningOf_
: public BaseClass
{
private:
WithCloningOf_& operator=( WithCloningOf_ const& ) IS_DELETED;
virtual WithCloningOf_* virtualClone() const
{
assert( typeid( *this ) == typeid( DerivedClass ) );
return new DerivedClass( *static_cast<DerivedClass const*>( this ) );
}
DerivedClass* derivedClassClone() const
{
return static_cast<DerivedClass*>( virtualClone() );
}
public:
typename Ownership<DerivedClass>::Ptr clone() const
{
return typename Ownership<DerivedClass>::Ptr( derivedClassClone() );
}
WithCloningOf_(): BaseClass() {}
template< class Arg1 >
WithCloningOf_( Arg1 const& a1 )
: BaseClass( a1 )
{}
template< class Arg1, class Arg2 >
WithCloningOf_( Arg1 const& a1, Arg2 const& a2 )
: BaseClass( a1, a2 )
{}
};
class Person
: public WithCloningOf_<Person, Cloneable>
{
typedef WithCloningOf_<Person, Cloneable> Base;
private:
string name_;
Person& operator=( Person const& ) IS_DELETED;
public:
string name() const { return name_; }
Person( string const& name )
: name_( name )
{}
};
class Student
: public WithCloningOf_<Student, Person>
{
typedef WithCloningOf_<Student, Person> Base;
private:
int studentId_;
Student& operator=( Student const& ) IS_DELETED;
public:
int studentId() const { return studentId_; }
Student( string const& name, int const studentId )
: Base( name ), studentId_( studentId )
{}
};
wostream& operator<<( wostream& stream, string const& s )
{
return (stream << s.c_str());
}
int main()
{
Person a( "Hillary Clinton" );
Student b1( "John Smith", 12345 );
Student b2( "Mary Jones", 88888 );
Person& bAsPerson = b1; // OK.
Ownership<Person>::Ptr pClone;
wcout
<< "Name: " << b1.name()
<< ". Student id: " << b1.studentId() << "."
<< endl;
#ifdef TEST_ABSTRACT_CLONE
pClone = bAsPerson.clone(); // OK, clones John Smith the Student.
#else
pClone = b2.clone(); // More obviously (?) OK, clones Mary.
#endif
Student& studentRef = dynamic_cast<Student&>( *pClone );
wcout
<< "Name: " << studentRef.name()
<< ". Student id: " << studentRef.studentId() << "."
<< endl;
}