Конструктор копий
Вызов конструктора копий происходит при создании копии объекта, когда его передают функции по значению, а также при создании объекта из другого, уже существующего. Компилятор предоставляет стандартный конструктор копий, но для достаточно сложных объектов он не всегда ведет себя адекватно. Стандартный конструктор копий (поставляемый компилятором по умолчанию) просто копирует каждую переменную-член переданного ему объекта в переменные-члены нового объекта. Такое копирование называется поверхностным (shallow сору). Хоть оно и подходит для большинства случаев, могут возникнуть серьезные проблемы, если переменные- члены являются указателями на объекты в динамической памяти.
В результате поверхностного копирования создаются точные копии значений всех переменных-членов одного объекта в другом. Указатели в обоих объектах будут указывать на одну и ту же область памяти. Глубокое копирование переносит значения, находящиеся в динамической памяти, во вновь созданные участки.
Задания 5. Создание конструктора копий с глубоким копированием
#include <vcl.h>
# include <iostream.h>
#include <conio.h>
using namespace std;
class Cat
{ private:
int *itsAge;
int *itsWeight;
public:
Cat (); // конструктор по умолчанию
Cat (const Cat &); // конструктор копий.
~Cat();
int GetAge() const {return *itsAge;}
int GetWeight() const {return *itsWeight;}
int SetAge(int age) {*itsAge = age;}
};
Cat::Cat()
{
itsAge=new int;
itsWeight=new int;
*itsAge=5;
*itsWeight=9;
}
Cat::Cat (const Cat& rhs)
{
itsAge=new int;
itsWeight=new int;
*itsAge=rhs.GetAge(); // Openning access
*itsWeight=*(rhs.itsWeight); // Closeing access
}
Cat::~Cat()
{
delete itsAge;
itsAge=0;
delete itsWeight;
itsWeight=0;
}
int main(int argc, char* argv[])
{
Cat frisky;
cout << "frisky's age: " << frisky.GetAge() << endl ;
cout << "Setting frisky to 6 ... \n";
frisky.SetAge(6);
cout << "Create object(cat) boots from frisky \n";
Cat boots(frisky);
cout << "frisky's age: " << frisky.GetAge() << endl ;
cout << "boots's age: " << boots.GetAge() << endl ;
cout << "Setting frisky to 7 ... \n";
frisky.SetAge(7);
cout << "frisky's age: " << frisky.GetAge() << endl ;
cout << "boots's age: " << boots.GetAge() << endl ;
getch();
return 0;
}
Объявленые две переменные-члена в создаваемом классе, представляют собой указатели на целочисленные значения. Обычно так не поступают, хранить в переменных-членах класса указатели на тип int абсолютно бессмысленно, здесь это сделано исключительно для примера манипулирования переменными-членами в динамической памяти.
Стандартный конструктор выделяет в динамической памяти область для двух переменных типа int и инициализирует их.
В конструкторе копий обратите внимание на параметр rhs. В качестве параметра конструктора копий принято использовать объект rhs, название которого является сокращением от right-hand side (стоящий справа).
Конструктор копий работает следующим образом: выделяются области в динамической памяти, новым областям присваиваются значения существующего объекта класса САТ.
Параметр rhs, передаваемый в конструктор копий в качестве постоянной ссылки, соответствует объекту классу САТ. Являясь объектом класса САТ, rhs содержит все переменные-члены, присущие объекту класса САТ.
Каждый объект класса САТ может получать доступ к закрытым переменным-членам любого другого объекта класса САТ, но обычно для этого принято создавать открытые методы доступа. Функция-член rhs.GetAge(), например, возвращает значение переменной- члена itsAge объекта rhs.
Когда объекты класса САТ выйдут из области действия, автоматически будут вызваны их деструкторы. Для обоих указателей, itsAge и itsWeight, выполняется оператор delete, освобождая выделенную для них память. Кроме того, в целях безопасности обоим указателям присвоено значение NULL.