Реализация конструктора копирования 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Реализация конструктора копирования



 

Конструктор копирования вызывается, когда один объект создается через другой объект. Когда динамически распределяется пространство для членов класса, конструктор копирования ведет себя неадекватно, некорректно.

Пусть имеется 2 объекта типа Message, где один является копией другого.

Class Message

{private:

Char* pmessage;

Public:

Void ShowIt(){cout<<endl<<pmessage;}

Message(const char* text=”default message”)

{pmessage=new char(strlen(text)+1);

Strcpy(pmessage,text);}

~Message();

};

Messge::~Message()

{ cout<<”destructor called\n”;

Delete [] pmessage;}

 

Message mess1 (“visual studio 2010”);

Message mess2 (mess1);

 

Так как в классе Message не создан конструктор копирования, то для создания объекта Mess2, компилятор генерирует собственную версию конструктора копирования по умолчанию.

Как известно, эффект от конструктора копирования по умолчанию состоит в том, что копируется адрес, хранившийся в указателе-члене класса из mess1 в mess2. Это означает, что процесс копирования, реализованный конструктором копирования по умолчанию включает простое копирование значений, хранящихся в данных членах исходного объекта в новый объект. Следовательно, в нашем примере одна текстовая строка будет совместно использована двумя объектами.

Если строка в одном из двух объектов изменяется, она также изменяется и для другого, потому что оба объекта разделяют одну и ту же строку. Если mess1 уничтожается, то указатель в объекте mess2 указывает на область памяти, которая была уже освобождена и где-то уже используется и при попытке освободить память второго объекта компилятором, программа завершается аварийно.

Решение данной проблемы заключается в создании конструктора копирования, который заменит версию поумолчанию.

Пример:

Message (copy Message &initM) // ссылка необходима во избежание цикла

{pmessage=new char [strlen(initM.pmessage)+1];

Strcpy(pmessage, initM.pmessage);}

Для того, чтобы избежать бесконечного цикла конструкторов копирования, параметр должен быть специализирован как const_ссылка. Конструктор копирования сначала выделяет достаточную память, чтобы уместилась строка из объекта initM, сохраняя адрес в данном члене pmessage нового объекта, а затем, копирует текстовую строку из исходного объекта.

 

Второй случай, когда нужно создать конструктор копирования – передача в функцию в качестве аргумента объекта по значению, при этом данные объекты являются динамическими.

 

Void DisplayMessage(Message localMsg)

{cout<<endl<<”the message is ->”<<localMsg.ShowIt()<<endl;}

Message mess3(“I like programming in C++”);

DisplayMessage (mess3);

 

Функция DisplayMessage будет работать некорректно, т.к. параметр, который она принимает, является объектом и передается он по значению. При конструкторе копирования по умолчанию происходят следующие события:

1) Объект mess3 создается с местом для сообщения “I like programming in C++” с выделением динамической памяти.

2) Функция DisplayMessage вызывается и, поскольку аргумент передан по значению, копия аргумента localMsg создается конструктором копирования по умолчанию. И теперь указатель pmessage в копии указывает на ту же строку в свободном хранилище, что и в оригинальном объекте.

3) При завершении своей работы в функции DisplayMessage, объект выходит из области видимости и поэтому вызывается деструктор класса Message, который удаляет локальный объект, освобождая память, на которую указывает указатель pmessage.

4) При возврате из функции DisplayMessage, указатель на исходный объект, то есть mess3 все еще указывает на область памяти, которая уже была освобождена и в следующий раз, когда мы попытаемся использовать исходный объект, программа начинает себя вести странным образом. И даже если мы больше не используем исходный объект, то рано или поздно программа должна завершить свою работу, объект должен выходить из области видимости и удаляться деструктором. Поэтому рано или поздно программа должна закончиться аварийно.

 

Таким образом любой вызов функции, которая принимает по значению объект класса, имеющего динамический определенный член, приведет к проблемам. Отсюда возникает следующее правило: если имеется динамическое выделение памяти для члена класса, всегда следует реализовать конструктор копирования.

Перегрузка операции

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

Приоритет выполнения операций:

::

() [] {}

* /

+ -

=

> < >= <= ==

?:

 

Z=(a>b)?a:((a>=c)?b:((c<d)?d:a)))

 

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

1 -::

2 -?:

3 -. операция прямого доступа к членам класса

4 – sizeof

5 - * операция разыменования

Перегруженные операции могут быть либо методом класса, либо как обычные глобальные функции, однако следующие перегруженные операции могут быть только функциями-членами класса:

1 - = присваивание

2 – () операция вызова функции

3 – [] операция индексирования

4 - -> операция косвенного доступа к членам класса

Перегруженные операции определяются с помощью ключевого слова operator

<тип возврата> Operator <операция>(<список параметров>)

{тело функции}



Поделиться:


Последнее изменение этой страницы: 2017-02-07; просмотров: 86; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.144.233.150 (0.007 с.)