Когда используются присваивание и копирующий конструктор
Решение проблемы
В таких классах обязательно нужно предусматривать копирующий деструктор и перегруженную операцию присваивания.
Копирующий конструктор (объявление в определении класса):
. . .
Function(const Function&);
. . .
Копирующий конструктор должен:
- Выделить новую память для создаваемого экземпляра класса,
- Скопировать в нее состояние существующего экземпляра класса.
Реализация:
Function::Function(const Function &f)
{
size = f.size;
xPtr = new float[size];
yPtr = new float[size];
for(int i = 0; i < size; i++){
xPtr[i] = f.xPtr[i];
yPtr[i] = f.yPtr[i];
}
}
Перегруженный оператор присваивания (объявление в определении класса; функция-член класса):
. . .
Function& operator =(const Function&);
. . .
Перегруженный оператор присваивания должен:
- Освободить память, занимаемую экземпляром класса – адресата оператора присваивания (указанного слева от присваивания),
- Выделить новую память для нового значения экземпляра класса – адресата,
- Скопировать в нее значение экземпляра класса, указанного справа от присваивания (параметр оператора присваивания),
- Проверить возможность записи присваивания типа x = x.
Реализация:
Function& Function::operator =(const Function &f)
{
if(this != &f){ // проверка ситуации x = x
;
delete [] xPtr;
delete [] yPtr;
xPtr = yPtr = NULL;
if(size = f.size){ // проверка ситуации, когда у объекта f нет памяти
xPtr = new float[size];
yPtr = new float[size];
for(int i = 0; i < size; i++){
xPtr[i] = f.xPtr[i];
yPtr[i] = f.yPtr[i];
}
}
}
return *this;
}
Перегруженный оператор присваивания работает всегда, когда в программе явно указывается оператор присваивания. Его использование не вызывает затруднений.
Копирующий конструктор работает всегда, когда требуется создать новый экземпляр класса, являющийся копией существующего. Такие ситуации могут возникнуть явно и неявно:
1.Явное создание временных экземпляров класса с использованием копирующего конструктора – при объявлении в программе экземпляров класса с инициализацией их другим экземпляром класса, например:
Function f1(5); // работает инициализирующий конструктор
Function f2(f1), // работает копирующий конструктор
f3 = f1; // работает копирующий конструктор
2.Неявное создание временных экземпляров класса с использованием копирующего конструктора – при использовании функции, аргументами которой являются экземпляры класса (не ссылки и не указатели) и которая возвращает в качестве результата значение экземпляра класса, например:
Function myfunc(Function f)
{
Function tmp;
. . .
return tmp;
}
Если в программе есть такая функция и выполняется действие f1 = myfunc(f2), тогда:
- при вызове функции, т.к. аргументы функции передаются в нее по значению, значение f1 копируется в стек (работает копирующий конструктор);
- когда функция завершает свою работу и выполняет оператор return, значение tmp копируется для замещения вызова функции (опять работает копирующий конструктор);
- параметры функции и объявленная в ней временная переменная tmp разрушаются (работает деструктор);
- и, наконец, работает перегруженный оператор присваивания.