2010-07-17 9 views

Respuesta

5

Pavel Minaev's answer from another discussion:

Otros ya han explicado sobre MemberwiseClone, pero nadie dio la explicación de por qué está protegido. Trataré de dar el razonamiento.

El problema aquí es que MemberwiseClone simplemente copia ciegamente el estado. En muchos casos, esto es indeseable. Por ejemplo, el objeto puede tener un campo privado que es una referencia a una Lista. Una copia superficial, como lo que hace MemberwiseClone, daría como resultado un nuevo objeto que apunta a la misma lista, y la clase podría escribirse sin esperar que la lista se comparta con nadie más.

O un objeto puede tener algún tipo de campo ID, generado en el constructor; de nuevo, cuando lo clona, ​​obtiene dos objetos con la misma ID, lo que puede dar lugar a todo tipo de fallas extrañas asumiendo que ID es único.

O supongamos que tiene un objeto que abre un socket o una secuencia de archivos, y almacena una referencia a eso. MemberwiseClone solo copiará la referencia, y puede imaginarse que dos objetos que intentan intercalar llamadas al mismo flujo no terminarán bien.

En resumen, "clonación" no es una operación bien definida para objetos arbitrarios. El hecho de que memberwise operator = se proporcione para todas las clases de forma predeterminada en C++ es más una molestia, ya que con demasiada frecuencia las personas olvidan que está allí y no lo desactivan para las clases para las que copiar no tiene sentido, o es peligroso (y sorprendentemente hay muchas clases similares).

1

Si MemberwiseClone no existiera, no habría otro medio, salvo el uso de Reflection, para que una clase heredable sea compatible con una operación de clonación polimórfica, excepto que requiera que cada clase derivada proporcione explícitamente una. La falla de una clase derivada para proporcionar una operación de clonación resultaría en un comportamiento inesperado. Por ejemplo, suponga que Vehicle, Car y ToyotaCar proporcionan métodos de clonación explícitos, pero ToyotaCorolla no. Si alguien tiene un objeto de tipo Toyota Corolla e intenta clonarlo, el objeto resultante sería un ToyotaCar. Dado que hay situaciones en las que se requiere la clonación polimórfica, y sería inconveniente requerir que cada clase derivada de una clase clonable brinde apoyo explícito, MemberwiseClone es una parte necesaria del marco.

Por otro lado, MemberwiseClone también puede ser peligroso. Realizar un MemberwiseClone en un objeto con frecuencia producirá un objeto roto; intentar usar cualquier propiedad o método del objeto roto puede dañar el original.

Es una pena que Microsoft no defina mejor una buena práctica para la clonación. Es posible, y no excesivamente difícil, diseñar un patrón de clonación polimórfica que no requiera que las clases heredadas hagan nada explícitamente a menos que agreguen campos que requieren un manejo especial, o a menos que un llamante espere que el tipo de retorno declarado del método Clone sea la clase derivada. Si bien la última situación con frecuencia será un requisito, la falla al implementar explícitamente el método necesario producirá un error en tiempo de compilación, en lugar de un comportamiento defectuoso en tiempo de ejecución.

Por cierto, Microsoft parece pensar que hay algo confuso acerca de la clonación profunda frente a la superficial. No hay Llamar a "Clonar" en un objeto debe clonar el objeto a la profundidad que sea necesaria para obtener su semántica definida. La clonación de un FileCabinet (Of T) debería producir un nuevo FileCabinet que, a los fines de los métodos de FileCabinet, es independiente del original, pero debe contener las mismas instancias de T que el original.Dado que el propósito de un archivador es contener instancias de T, pero no hacer nada con ellas, clonar el gabinete no debe implicar la clonación del contenido (pero implicaría clonar cualquier arreglo que el propio Gabinete use para contener los contenidos).

Por cierto, si tuviera mi druthers, habría una interfaz en .Net, implementada por String y tipos primitivos (y muchos otros), llamada DeepClonableIfMutable. Cuando se aplica a una Cadena u otra primitiva, el método DeepCloneIfMutable simplemente devolvería el objeto original. Los objetos inmutables definidos por el usuario podrían implementar DeepClonableIfMutable para que se comporte de manera similar, mientras que los objetos mutables se clonarían a fondo ellos mismos y cualquier instancia DeepClonableIfMutable anidada.

2
  • Muchas cosas no tienen sentido para clonar; cualquier cosa que habla con un mango no administrado, por ejemplo
  • mayoría de los objetos no necesitan una instalación clon
  • -copia completa algo adecuadamente es realmente difícil si vas fuera de algunos casos simples
  • en muchos casos, hay mejores metáforas que los clones ciegos
  • adición manual de una instalación clon a sus tipos que lo necesitan es trivialmente fácil

Para mí, entonces, es una obviedad que esto debería no se agregará a la API pública de forma predeterminada.

Cuestiones relacionadas