Копирование объектов и интерфейс icioneable
Иногда бывает необходимо сделать копию объекта. Если при этом копируются объекты, которые содержат другие объекты или указатели на них, то для корректной реализации этого процесса необходимо понимать его особенности. Ниже мы сравним копирование указателя, поверхностное почленное копирование и детальное копирование. Мы увидим, что в зависимости от реализации интерфейса ICloneable, используемого для копирования объектов, существует возможность как поверхностного, так и детального копирования.
Напомним, что в .NET Framework есть значащие типы данных и ссылочные типы. Значащие типы данных представляют собой непосредственно данные, а ссылочные типы всего лишь указывают местонахождение данных. Если значение одной переменной-указателя скопировать в другую переменную того же типа, обе переменные будут указывать на один и тот же объект. Если с помощью первого указателя этот объект будет изменен, то изменится и объект, на который ссылается второй указатель. Иногда требуется именно такое поведение, а иногда другое.
Интерфейс ICloneable
Интерфейс ICloneable является исходным и имеет единственный метод – Clone (Клон). Данный метод может быть реализован для выполнения как поверхностного, так и детального копирования, но указатель на Object (Объект), возвращаемый методом, должен указывать на объект того же (или совместимого) типа, для которого реализован интерфейс ICloneable. Обычно метод Clone (Клон) реализуют так, чтобы он создавал новый объект. Однако бывает, например в случае класса String (Строка), что метод Clone (Клон) просто возвращает указатель на исходный объект.
_gc _interface ICloneable // сборщик мусора – ICloneable { Object* Clone(); // Клон };
Поверхностная и детальная копии
Неуправляемые структуры и классы в C++ автоматически реализуют почленное копирование содержимого, которое будет актуальным до тех пор, пока не будет произведена подмена конструктора копирования. Почленное копирование называют также поверхностным копированием. В базовом классе Object (Объект) также есть защищенный (protected) метод, MemberwiseClone, выполняющий почленное копирование управляемых структур или классов.
Если среди членов структуры или класса есть указатели, такое почленное копирование может быть не тем, что вам требуется. Результатом этого копирования будет то, что указатели разных объектов будут ссылаться на одни и те же данные, а не на их независимые копии. Для фактического копирования данных следует сделать детальную копию. Детальное копирование может быть обеспечено на уровне языка или на уровне библиотек. В обычном C++ детальное копирование осуществляется на уровне языка с использованием конструктора копирования. В управляемом C++ оно осуществляется .NET Framework с помощью интерфейса Idoneable, который можно реализовывать в создаваемых классах специально для того, чтобы эти классы могли выполнять детальное копирование.
Следующими тремя вариантами исчерпываются возможные виды копирования, как для управляемых классов и структур, с использованием интерфейса Idoneable или без него, так и для неуправляемых классов и структур.
- Присваивание значения одного указателя другому (будь то указатели на управляемые или неуправляемые классы или структуры) приводит к простому копированию указателей. Это не поверхностное, и не детальное копирование, а простое присваивание указателей.
- Преобразование одного нессылочного (неуказательного) типа в другой, причем типы эти могут быть неуправляемыми классами, неуправляемыми структурами или значащими типами данных, является поверхностным копированием, автоматически осуществляемым C++.
- Присваивание новому указателю значения, возвращаемого методом Clone (Клон) (конечно, это значение должно быть также указателем) и являющегося управляемым классом или структурой с реализованным интерфейсом ICloneable, представляет собой поверхностное либо детальное копирование, в зависимости от реализации метода Clone (Клон).