ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 11) онлайн
Перегрузка оператора присваивания
Следующий коротенький пример демонстрирует технологию перегрузки опера-
тора присваивания.
Листинг 11.16. Программа ASSIGN
// assign.cpp
// перегрузка операции присваивания (=)
#include <iostream>
using namespace std;
///////////////////////////////////////////////////////////
class alpha
{
private:
int data;
public:
alpha() //конструктор без аргументов
{ }
alpha(int d) //конструктор с одним аргументом
{ data = d; }
void display() //вывести данные
{ cout << data; }
alpha operator = (alpha& a) //перегружаемый =
{
data = a.data; //не выполняется автоматически
cout << "\nЗапущен оператор присваивания";
return alpha(data); //возвращает копию alpha
}
};
///////////////////////////////////////////////////////////
Листинг 11.16 (продолжение)
int main()
{
alpha a1(37);
alpha a2;
a2 = a1; //запуск перегружаемого =
cout << "\na2="; a2.display(); //вывести a2
alpha a3 = a2; //НЕ запускается =
cout << "\na3="; a3.display(); //вывести a3
cout << endl;
return 0;
}
Класс alpha очень прост, в нем содержится только один элемент данных.
Конструкторы инициализируют данные, а методы выводят их значения на экран.
Вот и все, что тут делается. А новизна примера ASSIGN заключается в функции
operator=(), перегрузившей оператор = operator.
В main() мы определяем переменную a1 и присваиваем ей значение 37, опре-
деляем переменную а2, но значения ей не присваиваем. Затем, как видите, при-
сваиваем а2 значение a1:
а2 = a1; //Выражение присваивания
Тем самым мы запускаем нашу перегружаемую функцию operator=(). Про-
грамма ASSIGN заканчивается с таким результатом:
Запущен оператор присваивания
а2=37
а3=37
Инициализация — это не присваивание
В последних двух строчках кода ASSIGN мы инициализируем объект аЗ объектом
а2 и выводим его значение на экран. И пусть вас не смущает синтаксис в приве-
денном ниже выражении. Выражению
alpha аЗ = а2; //инициализация копирования. а не
//присваивание!
соответствует не присваивание, а инициализация. А эффект будет при этом тот
же, что при использовании выражения
alpha аЗ(а2); //альтернативный вариант инициализации
//копирования
Именно поэтому оператор присваивания выполняется только один раз, что
и отражено в результатах работы программы в единственной строчке вызова:
Запущен оператор присваивания
Ответственность
Когда перегружается оператор присваивания, подразумевается, что за все, что по
умолчанию делал этот оператор, отвечает программист. Часто это связано с ко-
пированием элементов данных из одного объекта в другой. Класс alpha из про-
граммы ASSIGN включает в себя только один элемент — data, поэтому функция
operator=() копирует его значение с помощью следующего выражения:
data = a.data;
В обязанности этой функции также входит вывод на экран строки «Запуще-
на операция присваивания», по которой мы можем определить, что функция
выполняется.
Передача по ссылке
Аргумент для функции operator=() передается по ссылке. Нельзя сказать, что это
совершенно необходимо, но обычно именно так и делается. Зачем? Как вы знаете,
аргумент, передающийся по значению, создает в памяти собственную копию для
функции, которой он передается. Аргумент, передающийся функции operator=(),
не является исключением. А если объекты большие? Их копии могут занять в па-
мяти очень много места, причем от них нет никакой пользы. Когда же значения
аргументов передаются по ссылке, копии не создаются, что помогает экономить
память.
Есть и еще одна причина. В определенных ситуациях необходимо отслежи-
вать количество созданных объектов (как в примере STATFUNC, где мы нумерова-
ли созданные объекты). Если же компилятор генерирует еще какие-то объекты
всякий раз, когда используется оператор присваивания, то есть шанс сильно за-
высить оценку их количества. С помощью передачи по ссылке удается ликвиди-
ровать прецеденты ложного создания объектов.
Возврат значений
Как вы уже успели заметить, функция может возвращать результат в вызыва-
ющую программу по значению или по ссылке. При возвращении по значению
происходит фактически передача результата, а значит, создается копия объекта,
которая и возвращается в программу. В вызывающей программе этот вновь соз-
данный объект может присваиваться какому-либо другому объекту или исполь-
зоваться как-то еще, это уже не так важно. Если же возвращение происходит по
ссылке, никакой новый объект не создается. Ссылка на исходный объект — вот
и все, что возвращается в качестве результата.
Функция operator=() возвращает результат путем создания временного объекта
alpha и его инициализации с помощью одноаргументного конструктора в выра-
жении
return alpha(data);
Возвращаемое значение — это копия исходного, а не тот же самый объект,
чьим методом является перегружаемая операция =. Такой стиль возвращения
значений позволяет выстраивать эти функции в цепочку:
аЗ = а2 = a1;
Да, впечатляет, но все равно возвращение результата по значению имеет все
те же недостатки, что и передача по значению. Прежде всего, это создание в па-
мяти копии возвращаемого объекта, что может привести к некоторой путанице.
А можем мы вернуть результат по ссылке, используя описатель, показанный ни-
же, для перегружаемого присваивания?
alpha& operator = (аlpha& а) //Неудачная мысль
К сожалению, нет, мы не можем осуществить возврат результата по ссылке
при работе с локальными переменными данной функции.
Напомним, что локальные переменные, то есть созданные внутри функции и
не объявленные статическими, уничтожаются при выходе из функции. Но, как
мы знаем, возвращение по ссылке передает в вызывающую программу только
адрес данных, который для локальных переменных указывает на данные, находя-
щиеся внутри функции. При возврате из функции указатель хранит уже какое-
то не имеющее смысла значение. Компилятор может сигнализировать о такой
ситуации предупреждением. В разделе «Указатель this» этой главы мы пока-
жем, как можно решить эту проблему.
Ограничение на наследование
Оператор присваивания уникален среди остальных операторов тем, что он не
может наследоваться. Перегрузив присваивание в базовом классе, вы не сможете
использовать ту же функцию в порожденных классах.
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
Схожі підручники
- Загальні питання з курсу Безпека життєдіяльності №2 (частина 2)
- Прежде чем начать СВОЙ БИЗНЕС (онлайн)
- Методичні вказівки до виконання практичного заняття на тему «Графічний метод розв’язку задач НЛП» Розв’язати графічним методом задачу НЛП
- РЕГІОНАЛЬНА ЕКОНОМІКА. Тексти лекцій онлайн (частина 3)
- Соціальне страхування. Навчальний посібник (частина 2)
- Хрестоматія з Філософії (частина 2) (онлайн)
