What's wrong with Copy Constructors? Why use Cloneable interface?
Asked Answered
S

6

14

When programming C++ we used to create copy constructors when needed (or so we were taught). When switching to Java a few years ago, I noticed that the Cloneable interface is now being used instead. C# followed the same route defining the ICloneable interface. It seems to me that cloning is part of the definition of OOP. But I wonder, why were these interfaces created, and the copy constructor seems to have been dropped?

When I thought about it, I came to the thought that a copy constructor would not be useful if one needs to make a copy of an object whose type is not known (as in having a reference to a base type). This seems logical. But I wonder whether there are other reasons that I do not know of, for which the Cloneable interfaces have been favored over copy constructors?

Suprarenal answered 23/12, 2008 at 6:30 Comment(0)
H
18

I think it's because there is no such inherent need for a copy constructor in Java and in C# for reference types. In C++ objects are named. You can (and you will most often) copy (and in C++1x move) them around e.g when returning from functions, since returning pointers require you to allocate dynamic memory which would be slow and painful to manage. The syntax is T(x) so it makes sense to make a constructor taking a T reference. C++ couldn't make a clone function, since that would require returning an object by value again (and thus another copy).

But in Java, objects are unnamed. There are only references to them, which can be copied, but the object itself isn't copied. For the cases when you actually need to copy them, you can use the clone call (but i read in other anwers clone is flawed. i'm no java programmer so i cannot comment that). Since not the object itself is returned, but rather a reference to it, a clone function will suffice. Also a clone function can be overriden. That's not going to work with copy constructors. And incidentally, in C++ when you need to copy a polymorphic object, a clone function is required too. It's got a name, the so-called virtual copy constructor.

Horten answered 23/12, 2008 at 6:49 Comment(5)
I think you mean "incidentally," not "accidentally."Bourbon
darn. i thought finally i could finish one answer withouth having that ugly "edited" label. hehe thanks for telling me 'bout it :)Horten
May I ask what's the difference? (English is not my first language.)Suprarenal
accidentally means that it happened without purpose, but it's bad. incidentally means that it happened, but it's randomly. u say "incidentally" if you want to say "oh, and by the way...". note im no native english speaker either. i hope im right with thisHorten
Accidentally refers to an event and means something happened unintentionally and usually has connotations of being undesirable; incidentally, when referring to an event means something happened as a byproduct and has neutral connotations. In the usage above, incidentally means "by the way", that is, as a side note, off the main topic.Sandglass
P
4

Because C++ and Java (and C#) aren't the same thing. C++ has no built-in interfaces because interfaces aren't part of the language. You can fake them with abstract classes but they aren't how you think about C++. Also, in C++ assignment is normally deep.

In Java and C# assignment just involves copying the handle to the internal object. Basically when you see:

SomeClass x = new SomeClass();

in Java or C#, there's a level of indirection builtin that doesn't exist in C++. In C++, you write:

SomeClass* x = new SomeClass();

Assignment in C++ involves the dereferenced value:

*x = *another_x;

In Java you can get access to the "real" object as there is no dereference operator like *x. So to do a deep copy, you need a function: clone(). And both Java and C# wrapped that function into an interface.

Pullen answered 23/12, 2008 at 6:42 Comment(0)
S
3

It's the issues of final type and of cascading the clone operation through the super classes which is not addressed by copy constructors - they are not extensible. But the Java clone mechanism is widely considered badly broken too; especially problems where a subclass does not implement clone(), but inherits from a superclass that implements cloneable.

I strongly recommend you research cloning carefully, whatever path you choose - you will likely choose the clone() option, but make sure you know exactly how to do it properly. It's rather like equals() and hashCode() - looks simple on the surface, but it has to be done exactly right.

Sandglass answered 23/12, 2008 at 6:40 Comment(0)
F
2

I think you haven't get the right point. I give you my two cents.

Fundamentally there's a problem: creating a clone of a class without knowing the exact class type. If you use copy constructor, you cannot.

Here is an example:

class A {
public A(A c) { aMember = c.aMember }
    int aMember;
}

class B : A {
public B(B c) : base(c) { bMember = c.bMember }
    int bMember;
}

class GenericContainer {
public GenericContainer(GenericContainer c) {
    // XXX Wrong code: if aBaseClass is an instance of B, the cloned member won't 
    // be a B instance!
    aBaseClass = new A(c.aBaseClass);
}
    A aBaseClass;
}

The Clone method, if declare virtual, could create the right class instance of the generic member.

An this problem is common to every language, C# C++ or Java...

Maybe this is what you was meaning, but I cannot understand this from any answer.

Favin answered 19/12, 2009 at 11:9 Comment(0)
H
1

Just wanted to add that in Java the copy constructor is not completely useless.

There are cases where your class has a private instance variable of a mutable non-final type, e.g. Date, and has a setter and getter for the variable. In the setter, you should make a copy of the given date, because the caller could modify it later and thereby manipulate your object's internal state (usually by accident, but maybe intentional). In the getter, the same precaution is required.

The defensive copy could be implemented by calling clone() (the class Date is cloneable), but a malicious caller could call the setter with a subclass of Date which overrides the clone() method with {return this;}, and so the caller might still be able to manipulate your object. This is where the copy constructor comes into play: By calling new Date(theDate), you are sure to get a fresh Date instance with the same timestamp as the given date, without any connection between the two date instances. In the getter, you could use the clone method, because you know the private variable will be of class Date, but for consistency, usually the copy constructor is used there, too.

Also note that the copy constructor would note be required if the Date class was final (calling clone() were safe) or immutable (no copy required).

Harlem answered 2/4, 2011 at 17:40 Comment(0)
B
0

I think its only because once u have defined a copy constructor, you could never pass the reference itself again. (Unless it would have a function that does that...but thats not any easier than using the clone() method.) In C++ its not a problem: you can pass the whole object or its reference.

Brassard answered 11/1, 2010 at 4:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.