ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4302
Скачиваний: 28
Глава 16. Перегрузка операторов
211
Оператор присваивания и конструктор копирования обычно со-
держат много общего кода. Поэтому в этом случае часто пишут
отдельную, закрытую функцию, которая реализует этот код и вы-
зывается как в операторе присваивания, так и конструкторе копи-
рования.
В листинге 16.2 приведен пример класса, для которого нужно
обязательно перегрузить оператор присваивания. Этот класс яв-
ляется расширением класса
Demo
, приведенного в
разд. 15.4
.
Листинг 16.2. Определение класса с перегруженным оператором
присваивания
#if !defined DEMO
#define DEMO
class Demo
{
unsigned size;
void copy(const Demo& d); // функция копирования
public:
int* p;
// конструкторы
Demo(unsigned n): size(n), p(new int[size]) {}
Demo(const Demo& d);
// оператор присваивания
Demo& operator =(const Demo& d);
// деструктор
~Demo() { delete[] p; }
};
#endif
В листинге 16.3 приведена реализация конструктора копирования
и оператора присваивания для класса
Demo
.
Листинг 16.3. Реализация оператора присваивания
#include "Demo.h"
// реализация функции копирования объектов
void Demo::copy(const Demo& d)
Часть II. Язык программирования С++
212
{
for (unsigned i = 0; i < size; ++i)
p[i] = d.p[i];
}
// реализация конструктора копирования
Demo::Demo(const Demo& d): size(d.size), p(new int[size])
{
copy(d);
}
// реализация оператора присваивания
Demo& Demo::operator =(const Demo& d)
{
if (&d != this)
{
delete[] p; // удаляем старый массив
size = d.size;
p = new int[size];
copy(d); // копируем
}
return *this;
}
Если посредством оператора присваивания инициализируется
новый объект, то вместо вызова конструктора по умолчанию и
оператора присваивания сразу вызывается конструктор копиро-
вания.
16.4. Составные операторы
присваивания
Составные операторы присваивания также могут быть пере-
гружены только как нестатические члены класса. Перегружен-
ные составные операторы присваивания имеют следующий про-
тотип:
имя_класса& operator @(const имя_класса&);
Символ
@
обозначает составной оператор присваивания. Как ви-
дим, этот прототип аналогичен прототипу простого оператора
Глава 16. Перегрузка операторов
213
присваивания. Очевидно, что при реализации составных операто-
ров присваивания не нужно проверять на присваивание объекта
самому себе.
Например, приведем реализацию одного из составных операто-
ров присваивания, перегруженных в классе
Bool
:
Bool& Bool::operator +=(const Bool& b)
{
n ? n : n = b.n;
return *this;
}
16.5. Оператор индексирования
[ ]
Оператор индексирования
[]
перегружается только как нестати-
ческий член класса с одним параметром. Перегружается этот
оператор в основном для контейнерных классов, чтобы обеспе-
чить доступ к отдельным элементам класса по их индексу. При
перегрузке оператора присваивания следует учитывать, что он
может использоваться как для константного, так и для не кон-
стантного объекта. Например:
struct BadIndex {};
class Coord
{
int x, y;
public:
Coord() {}
Coord(int _x, int _y): x(_x), y(_y) {}
int& operator [](const int& i)
{
switch (i)
{
case 0: return x;
case 1: return y;
default: throw BadIndex();
}
}
Часть II. Язык программирования С++
214
const int& operator [](const int& i) const
{
switch (i)
{
case 0: return x;
case 1: return y;
default: throw BadIndex();
}
}
};
16.6. Оператор вызова функции
Оператор вызова функции может быть перегружен только как
нестатический член класса. Перегруженный оператор вызова
функции
()
должен иметь следующий прототип:
тип operator ()(список_параметров);
где количество параметров может быть неопределенным, а также
допускается определять значения параметров по умолчанию. Вы-
зывается оператор вызова функции путем применения списка ар-
гументов к объекту класса, в котором он определен. Так как в
этом случае объект может использоваться как функция, то он на-
зывается
объектом-функцией
или
функциональным объектом
.
В листинге 16.4 приведен пример перегрузки оператора вызова
функции.
Листинг 16.4. Перегрузка оператора вызова функции
#include <iostream>
using namespace std;
struct Inc
{
int& operator()(int& n) { return ++n; }
};
int main()
{
Inc inc;
int n = 1;
Глава 16. Перегрузка операторов
215
inc(n);
cout << inc(n) << endl; // печатает 3
return 0;
}
16.7. Оператор доступа
к членам класса
Оператор доступа к членам класса
->
должен быть перегружен
как нестатический член класса без параметров, а также обеспечи-
вать семантику указателя потому, что для объекта
x
выражение
x->m
интерпретируется компилятором как:
(x.operator->()) -> m
Перегрузка оператора
->
используется для создания указателей
на объекты с дополнительными возможностями.
Например, в листинге 16.5 реализован класс
ptr
, который не по-
зволяет создавать неинициализированные указатели на объекты
типа
int
. Кроме того, в этой программе приведены примеры пе-
регрузки операторов определения адреса и разыменования.
Листинг 16.5. Перегрузка операторов доступа к членам класса,
определения адреса и разыменования
#include <iostream>
using namespace std;
struct Demo
{
int n;
int what() { return n; }
};
class ptr
{
Demo* p;
public:
ptr(Demo& d): p(&d) {}