Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
билеты информатика.rtf
Скачиваний:
39
Добавлен:
02.05.2015
Размер:
6.9 Mб
Скачать

Перегрузка операции присваивания копированием

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

  1. Получаем новые ресурсы

  2. Освобождаем старые ресурсы

  3. Присваиваем объекту значения нового ресурса

class My_Array

{

int * array;

int count;

public:

My_Array & operator = (const My_Array & other)

{

if (this != &other) // защита от неправильного самоприсваивания

{

// 1: выделяем "новую" память и копируем элементы

int * new_array = new int[other.count];

std::copy(other.array, other.array + other.count, new_array);

// 2: освобождаем "старую" память

delete [] array;

// 3: присваиваем значения в "новой" памяти объекту

array = new_array;

count = other.count;

}

// по соглашению всегда возвращаем *this

return *this;

}

...

};

Тем не менее, если успешный метод обмена доступен для всех членов и класс реализует конструктор копирования и деструктор (согласноПравилу трех), самым коротким путем реализации присваивание копированием будет следующий способ[2]:

public:

void swap(My_Array & other) // обмен члена-функции (неудачи быть не должно!)

{

// обмен всех членов (и базовых субобъектов, если возможно) с other

std::swap(array, other.array);

std::swap(count, other.count);

}

My_Array & operator = (My_Array other) // Примечание: аргумент передается по значению!

{

// обмен this с other

swap(other);

// по соглашению всегда возвращаем *this

return *this;

// other уничтожается, освобождая память

}

Причина, по которой операция = возвращает My_Array& вместо void, проста. Он разрешен для объединения назначений, как например:

array_1 = array_2 = array_3; // значение array_3 присваивается array_2

// затем значение array_2 присваивается array_1

Опе­ра­ция за­пя­тая в C++

Пре­жде все­го, сле­ду­ет знать, что не вся­кая за­пя­тая в тек­сте ва­шей про­грам­мы яв­ля­етcя опе­ра­ци­ей. Пе­ре­чис­лим за­пя­тые, ко­то­рые яв­ля­ют­ся не опе­ра­ци­я­ми, а раз­де­ли­те­ля­ми:

  • За­пя­тые, раз­де­ляю­щие ар­гу­мен­ты мак­ро­под­ста­но­вок. При­мер:#define MIN(a, b) (((a) < (b)) ? (a) : (b))

  • За­пя­тые, раз­де­ляю­щие ар­гу­мен­ты шаб­ло­нов. При­мер:template<class A, class B> class C;

  • За­пя­тые, раз­де­ляю­щие ар­гу­мен­ты функ­ции (при её опре­де­ле­нии, опи­са­нии, и вы­зо­ве);

  • За­пя­тые, раз­де­ляю­щие пе­ре­мен­ные при опи­са­нии не­сколь­ких пе­ре­мен­ных:int a, *b, c;

  • За­пя­тые, раз­де­ляю­щие вы­зо­вы кон­ст­рук­то­ров внут­рен­них объ­ек­тов. При­мер:class C{int x; float y; public: C(void): x(9), y(2.5) { ; } };

  • За­пя­тые, раз­де­ляю­щие эле­мен­ты ини­циа­ли­за­то­ров мас­си­вов и ст­рук­тур:int a[] = {1, 2, 3};

Осталь­ные за­пя­тые яв­ля­ют­ся опе­ра­ци­я­ми. Опе­ра­ция за­пя­тая име­ет са­мый низ­кий при­о­ри­тет сре­ди всех опе­ра­ций язы­ка C++. У этой опе­ра­ции есть 2 опе­ран­да (ле­вый и пра­вый). Вна­ча­ле вы­чис­ля­ет­ся ле­вый опе­ранд, за­тем пра­вый, а в ка­че­стве ре­зуль­та­та воз­вра­ща­ет­ся пра­вый опе­ранд. Три­ви­аль­ный при­мер:

int a = (1 + 2, 3 + 4); //В результате a == 3+4 == 7. Заключёно в                        //  скобки, так как иначе запятая была бы                        //  воспринята, как разделитель переменных

Ес­ли пра­вый опе­ранд опе­ра­ции за­пя­тая яв­ля­ет­ся ле­вос­то­рон­ним вы­ра­же­ни­ем (име­ет ад­рес и не яв­ля­ет­ся кон­стан­той), то ре­зуль­та­том то­же яв­ля­ет­ся ле­вос­то­рон­нее вы­ра­же­ние. В этом слу­чае ре­зуль­та­ту мож­но при­сваи­вать зна­че­ние или вы­чис­лять ад­рес:

int a = 1, b = 2;(a, b) = 3; //В результате a==1, b==3

По­боч­ные эф­фек­ты

Пусть вы­ра­же­ние «по­боч­ный эф­фект» вас не пу­га­ет, — это дей­ствие, со­вер­шен­но осо­знан­но за­про­грам­ми­ро­ван­ное раз­ра­бот­чи­ком про­грам­мы. «По­боч­ный» — не обя­за­тель­но «пло­хой»; сло­во при­об­ре­ло от­ри­ца­тель­ный от­те­нок из-за ле­карств, ко­то­рые обыч­но име­ют один те­ра­пев­ти­че­ский эф­фект и мно­го по­боч­ных.

За­чем же вы­чис­лять зна­че­ния обо­их опе­ран­дов, ес­ли зна­че­ние ле­во­го всё рав­но не ис­поль­зу­ет­ся? Де­ло в том, что в про­цес­се вы­чис­ле­ния опе­ран­да мо­гут быть про­из­ве­де­ны до­пол­ни­тель­ные дей­ствия, на­зы­вае­мые по­боч­ны­ми эф­фек­та­ми. На­при­мер, мо­гут быть мо­дифи­ци­ро­ва­ны ка­кие-ли­бо пе­ре­мен­ные в про­грам­ме, или вы­пол­не­ны не­ко­то­рые внеш­ние дей­ствия (вы­вод на экран, за­пись на диск).

Опе­ра­ция за­пя­тая пред­на­зна­че­на для то­го, что­бы впи­хи­вать дей­ствия с по­боч­ны­ми эф­фек­та­ми в те ме­ста про­грам­мы, где ком­пи­ля­тор ожи­да­ет один опе­ра­тор. Как вы уви­ди­те да­лее, от этой воз­мож­но­сти язы­ка про­грам­ми­ро­ва­ния нет ни­ка­кой поль­зы — по­нят­ность про­грам­мы сни­жа­ет­ся, а до­пол­ни­тель­ные дей­ствия мож­но вы­пол­нить и без за­пя­тых.