In order to copy an object, you have to know at compile time the
object's type, because the type is the "name" of the copy constructor:
1 2 3 4
|
void copy_me( const std::string& s ) {
std::string s_copy( s );
std::string* p_s_copy = new std::string( s );
}
|
I know at compile time that s has type "std::string" because it says
so in the parameter list. But what if type of s was a base class?
1 2 3 4 5 6
|
class Base {};
class Derived : public Base {};
void copy_me( const Base& b ) {
Base b_copy( b ); // ????
}
|
That doesn't quite work, because I can call copy_me() with a derived
class instance, in which case the function would want to instantiate
a Derived object, not a Base object. But at compile time there is
simply no way for me to know that. Indeed, I could even call copy_me()
with Base instances in one place, Derived in another, and something
else (derived from Base or Derived) in a third.
How can this problem be solved?
The clone pattern was implemented for exactly this reason. The
clone pattern looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
// Depending upon your needs, you might not require a base class
// clonable concept. It would only be needed if you need to store
// clonable objects polymorphically.
struct clonable {
virtual ~clonable() {}
virtual clonable* clone() const = 0;
};
class Base : public clonable {
public:
virtual Base* clone() const
{ return new Base( *this ); }
};
class Derived : public Base {
public:
virtual Derived* clone() const
{ return new Derived( *this ); }
};
|
And now, copy_me looks like:
1 2 3 4
|
void copy_me( const Base& b ) {
Base* clone = b.clone();
// delete clone;
};
|
And I've successfully invoked Base's copy constructor if the
"real type" of b is Base, and Derived's copy constructor if the
"real type" of b is Derived.
It is worth mentioning here that this technique exploits the fact that
the compiler does not consider the return type of the function when
determining whether or not a derived class virtual method has overridden
a base class one with the same name.