Вчера я задал вопрос о копировании объектов в C#, и большинство ответов сфокусировалось на различии между глубокой копией и мелкой копией и тем, что это должно быть ясно дано понять, какой из обоих вариантов копии реализует данный конструктор копии (или оператор или функция). Я нахожу это нечетным.
Я записал много программного обеспечения в C++, язык, который в большой степени полагается на копирование, и мне никогда не были нужны несколько вариантов копии. Единственный вид операции копии, которую я когда-либо использовал, является тем, который я называю "глубокой копией". Это делает следующее:
Теперь, мой вопрос является трехкратным:
Большинство программистов на C ++ не используют термины «неглубокая копия» и «глубокая копия» по той очень веской причине, что обычно существует только один способ скопировать объект. Это особенно верно в C ++, потому что компилятор использует конструктор копирования во многих ситуациях, когда программист может сказать ему, какой конструктор копирования использовать - например:
void f( std::string s );
нет способа сообщить компилятору, как копировать строку.
Объекту нужно только скопировать то, что ему нужно скопировать. Хотя этот вопрос помечен как независимый от языка, и вы упомянули C ++, я предпочитаю объяснять в терминах C # (поскольку это то, с чем я наиболее знаком). Однако концепции похожи.
Типы значений подобны структурам. Они живут непосредственно в экземпляре объекта. Следовательно, при копировании объекта у вас нет другого выбора, кроме как скопировать тип значения. Так что обычно вам не о чем беспокоиться.
Ссылочные типы похожи на указатели, и здесь это становится непростой задачей. В зависимости от того, какой тип ссылки, вам может понадобиться глубокая копия, а может и нет. Общее практическое правило состоит в том, что если ссылочный тип (как член объекта) зависит от состояния внешнего объекта, его следует клонировать. Если нет и никогда не будет, этого не должно быть.
Другой способ мышления состоит в том, что объект, переданный вашему объекту извне, вероятно, НЕ следует клонировать. Объект, созданный вашим классом, должен быть.
Хорошо, я соврал, я воспользуюсь C ++, так как он лучше всего объясняет, что я имею в виду.
class MyClass {
int foo;
char * bar;
char * baz;
public: MyClass(int f, char * str) {
this->foo = f;
bar = new char[f];
this->baz = str;
}
};
С этим объектом нужно иметь дело с двумя строковыми буферами. Первый, bar
, создается и управляется самим классом. Когда вы клонируете объект, вы должны выделить новый буфер.
baz
, с другой стороны, быть не должно. Фактически, вы не можете, поскольку у вас недостаточно информации для этого. Указатель надо просто скопировать.
И, конечно же, foo
- это просто число. Просто скопируйте его, больше не о чем беспокоиться :)
В общем, чтобы ответить на ваши вопросы напрямую: