views:

557

answers:

4

Here's a Clone() implementation for my class:

    MyClass^ Clone(){
        return gcnew MyClass(this->member1, this->member2);
    }

Now I have about 10 classes derived from MyClass. The implementation is the same in each case. Owing to the fact that I need to call gcnew with the actual class name in each case, I am required to create 10 nearly identical implementations of Clone().

Is there a way to write one single Clone() method in the base class which will serve all 10 derived classes?

Edit: Is there a way to invoke the constructor of a class via one of it's objects? In a way that will invoke the actual derived class constructor. Something like:

MyClass ^obj2 = obj1->Class->Construct(arg1, arg2);

I'm doing this on C++/CLI but answers from other languages are welcome.

A: 

Not in C++ that I'm aware of. As you say, you need to create an object of a different class in each implementation of Clone().

pjc50
A: 

Hm, I think you can use Factory pattern here. I.e.:

MyClass Clone(){
    return MyClassFactory.createInstance(this.getClass(), this.member1, this.member2, ...);
}

In the factory, you would have to create instance of subclass based on passed class type. So probably it has the same disadvantages as your approach.

audras
A: 

I would suggest using copy constructors instead (as derived classes can call the base implementation's copy constructor as well) -- also handy, as it will be familiar territory for C++ programmers.

You might be able to create a single Clone method that uses reflection to call the copy constructor on itself in this instance.

Possibly also worth noting that Jeffrey Richter said in the Framework Design Guidelines book, "The ICloneable interface is an example of a very simple abstraction with a contract that was never explicitly documented. Some types implement this interface's Clone method so that it performs a shallow copy of the object, whereas some implementations perform a deep copy. Because what this interface's Clone method should do was never fully documented, when using an object with a type that implements ICloneable, you never know what you're going to get. This makes the interface useless" (emphasis mine)

Rowland Shaw
+1  A: 

In plain old C++, you can do this with compile-time polymorphism (the curiously-recurring template pattern). Assuming your derived classes are copyable, you can just write:


class Base
{
public:
    virtual Base* Clone() const = 0;
//etc.
};
template <typename Derived>
class BaseHelper: public Base
{
    //other base code here

    //This is a covariant return type, allowed in standard C++
    Derived * Clone() const
    {
         return new Derived(static_cast<Derived *>(*this));
    }
};

Then use it like:


class MyClass: public BaseHelper<MyClass>
{
    //MyClass automatically gets a Clone method with the right signature
};

Note that you can't derive from a class again and have it work seamlessly - you have to "design in" the option to derive again by templating the intermediate classes, or start re-writing Clone again.

Doug