MyTetra Share
Делитесь знаниями!
Конструктор копирования в C++: объяснение и пример использования
Время создания: 13.08.2015 01:25
Текстовые метки: c++, конструктор копирования, пример
Раздел: Компьютер - Программирование - Язык C++ (Си++)
Запись: xintrea/mytetra_syncro/master/base/1439414710chs6b1xcrf/text.html на raw.github.com

Конструктор копирования

Продолжая начатую тему Конструктор копирования, я приведу пример случая, в котором необходимо создании конструктора копирования. Пример почти такой же, как в википедии куда я ранее ссылался, но чуть проще и немного понятнее для новичков в программировании.


Внимание! Не следует путать конструктор копирования и реализацию оператора присваивания (operator=), это разные вещи!


Зачем нужен конструктор копирования


Вначале нужно показать код:



#include <iostream.h>

#include <stdlib.h>


/*СТРУКТУРА МАССИВ*/

struct Array

{

int *element; // Указатель на int

Array(int N); // Конструктор структуры, принимающий параметр типа int

~Array(); // Деструктор структуры для освобождения памяти

};


// Описание конструктора вне структуры

Array::Array(int N)

{

// При каждом новом вызове будет выделяться новый участок памяти

// размером согласно принимаемому параметру

element=new int[N];

}


// Описание деструктора вне структуры

Array::~Array()

{

// Освобождаю память, выделенную внутри конструктора

delete []element;

}

int main()

{

system("CLS");


// Объявляю переменную v, тип которой наша структура и выделяю память для 3 элементов int

Array v(3);


// Записываю в переменную v значения

v.element[0]=20;

v.element[1]=30;

v.element[2]=40;

// Объявляю переменную x, тип которой наша структура и копирую туда данные из v

Array x=v;

cout<<x.element[0]<<" "<<x.element[1]<<" "<<x.element[2]<<endl; // Элементы x


// Например, появилась необходимость изменить объект v

v.element[0]=100;

cout<<x.element[0]<<" "<<x.element[1]<<" "<<x.element[2]<<endl; // Элементы x

cin.get();

return 0;

}


Если вы плохо знакомы с указателями, то выполнение этого кода может произойти слегка не так, как вы ожидали. Несмотря на то, что и в первом и во втором случае, я вывожу на экран только данные второго созданного мною объекта, не изменяя его напрямую, данные в нем изменились после изменения данных в первом объекте. Такое поведение работы программы объясняется тем, что срабатывает конструктор копирования по умолчанию. Этот конструктор копирования копирует указатель как указатель и получается, что в обоих объектах оба указателя указывают на один и тот же адрес. То есть если изменить данные, расположенные на том адресе, то и первый и второй объект будут получать те измененные данные. Думаю, суть вы должны уловить. Вот в таких случаях и возникает вопрос безопасного копирования данных из одного объекта в другой. Безопасное копирование в этом случае обозначает, что изменения одного из объектов не должны влиять на другой объект. Для решения этого вопроса как раз и используют конструктор копирования.


Код с конструктором копирования


#include <iostream.h>

#include <stdlib.h>


/*СТРУКТУРА МАССИВ*/

struct Array

{

int *element; // Указатель на int

int size; // Размер массива

Array(int N); // Конструктор принимает параметр, по которому определяет количество элементов для массива

Array(Array &obj); // Конструктор копирования

~Array(); // Деструктор для освобождения памяти

};


// Описание конструктора с параметром типа int вне класса

Array::Array(int N)

{

element=new int[N]; // При каждом новом вызове выделяю память для N элементов типа int

size=N; // Запоминаю размер согласно указанному параметру

}


// Описание конструктора копирования вне класса

Array::Array(Array &obj)

{

// Выделяю память для элемента объекта

element=new int[obj.size];


// Поэлементно копирую каждый элемент из принимаемого объекта в текущий

for (int i=0;i<obj.size;i++)

element[i]=obj.element[i];


// Скопировать нужно каждый кусочек класса, сами они не копируются

size=obj.size;

}


// Описание деструктора вне класса

Array::~Array()

{

delete []element; // Освобождение памяти

}


int main()

{

system("CLS");


// Объявил объект v и указал, что он содержит три элемента

Array v(3);


// Записал данные в объект

v.element[0]=20;

v.element[1]=30;

v.element[2]=40;


// Объявляю второй объект и копирую в него данные из первого

Array x=v;

cout<<x.element[0]<<" "<<x.element[1]<<" "<<x.element[2]<<endl; // Данные второго объекта


v.element[0]=100; //Меняю одно поле первого объекта

cout<<x.element[0]<<" "<<x.element[1]<<" "<<x.element[2]<<endl; // Данные второго объекта

cin.get();

return 0;

}


В самый конец вы можете дописать вывод данных первого объекта на экран. В этом коде был использован прием, благодаря которому каждый объект будет обладать своим уникальным указателем. В первом случае была проблема в том, что оба указателя указывают на одно и то же место, значит, чтобы решить проблему, нужно сделать два указателя, которые не будут зависимы друг от друга и будут указывать на разные адреса. Кроме этого нужно учитывать, что при копировании размеры объектов должны совпадать. Чтобы размеры объектов совпадали, я при выделении памяти взял размер из принимаемого объекта и выделил столько памяти, сколько выделено для принимаемого объекта. Не нужно забывать, что при явном использовании конструктора копирования, выполнение копирования наша забота, поэтому копируем необходимые данные своими силами. Я выполнил поэлементное копирование одного массива в другой.

После выполнения таких не хитрых операций легко можно работать с обоими объектами, не беспокоясь за то, что изменяя один объект мы навредим внутри другого. Это и есть ответ на вопрос: “Зачем нужен конструктор копирования”

Я натыкался на примеры с деструкторами, но мне такие примеры давали больше воды, чем пользы. Такой пример немного нагляднее, понятнее и самое главное хорошо дает понять основные причины использования конструктора копирования. Но примеры ориентированные на деструкторы тоже полезны и нужны.


Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования