ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4308
Скачиваний: 28
Часть II. Язык программирования С++
216
Demo* operator ->() const { return p; }
Demo* operator &() const { return p; }
Demo& operator *() const { return *p; }
};
int main()
{
Demo d = {0};
ptr p(d);
(*p).n += 10;
cout << (&p)->n << endl; // печатает 10
cout << p->what() << endl; // печатает 10
return 0;
}
16.8. Операторы инкремента
и декремента
Операторы инкремента и декремента могут быть перегружены
как члены класса без аргументов или как не члены класса с одним
аргументом. Для того чтобы префиксные операторы
++
и
--
от-
личать от соответствующих постфиксных операторов, в объявле-
нии последних вводят дополнительный фиктивный параметр ти-
па
int
.
В листинге 16.6 приведен пример перегрузки префиксного и
постфиксного операторов инкремента.
Листинг 16.6. Перегрузка префиксного и постфиксного операторов
инкремента
#include <iostream>
using namespace std;
class Count
{
int n;
public:
Count(int _n): n(_n) {}
Глава 16. Перегрузка операторов
217
Count& operator ++() // префиксный ++
{
++n;
return *this;
}
Count operator ++(int) // постфиксный ++
{
++n;
return Count(n - 1);
}
int get() { return n; }
};
int main()
{
Count c(0);
cout << ((++c)++).get() << endl; // печатает 1
cout << c.get() << endl; // печатает 2
return 0;
}
16.9. Бинарные операторы
Бинарные операторы могут быть перегружены как нестатические
члены класса с одним параметром:
тип operator @(параметр);
Или как операторы не члены класса с двумя параметрами.
тип operator @(параметр_1, парметр_2);
Символ
@
обозначает один из следующих бинарных операторов:
+ - * . % == <= >= != && || << >>
При перегрузке бинарных операторов следует учитывать симмет-
ричность их параметров. Если аргументами бинарного оператора
являются объекты одного класса, то этот оператор лучше пере-
гружать как дружественный оператор с двумя параметрами.
Часть II. Язык программирования С++
218
Например, для класса
Bool
оператор сравнения на равенство сле-
дует перегрузить следующим образом:
Bool operator ==(const Bool& b1, const Bool& b2)
{
return Bool(b1.n ? (b2.n ? 1 : 0) : (b2.n ? 0 : 1));
}
Если же оператор сравнения на равенство будет определен как
член класса, то первый параметр этого оператора будет иметь тип
const Bool* const
, а второй параметр — тип
const Bool&
, что на-
рушает симметричность параметров и требует дополнительного
преобразования типов.
16.10. Перегрузка операторов
>>
и
<<
для ввода и вывода
Перегруженные операторы ввода/вывода
>>
и
<<
должны опреде-
ляться как дружественные операторы класса, которые имеют сле-
дующий прототип:
friend istream& operator >>(istream&, имя_класса&);
friend ostream& operator <<(ostream&, const имя_класса&);
Это позволяет избежать путаницы с общепринятым написанием
этих операторов. Например, перегрузим операторы
>>
и
<<
соот-
ветственно для ввода и вывода данных типа
Bool
:
std::istream& operator >>(std::istream& in, Bool& b)
{
in >> b.n;
b.n ? b.n = 1 : b.n = 0;
return in;
}
std::ostream& operator <<(std::ostream& out, const Bool& b)
{
return out << b.n;
}
Глава 16. Перегрузка операторов
219
Теперь эти операторы можно использовать следующим образом:
Bool a;
cin >> a;
cout << a << endl;
16.11. Операторы преобразования
типов (конвертеры)
Конвертер
— это функция-член класса, которая преобразует тип
объекта класса в некоторый другой тип. Конвертер имеет сле-
дующий прототип:
operator тип();
Здесь
тип
задает тип данных, к которому приводится объект. Этот
тип может быть как встроенным типом данных, так и типом дан-
ных, определенным пользователем. Конвертер может вызываться
как явно, так и неявно — при преобразованиях типов данных.
Например, определим для класса
Bool
оператор преобразования
в тип
bool
:
Bool::operator bool(void) const { return n ? true : false; }
После определения этого оператора значения типа
Bool
можно
использовать в выражениях со значениями типа
bool
. Например:
bool a;
Bool b = 0;
a = true && b; // а = false
16.12. Операторы
new
и
delete
Перегрузка операторов
new
и
delete
не подчиняется общим пра-
вилам перегрузки операторов. Эти операторы могут быть пере-
гружены только как статические члены класса, даже если специ-
фикатор
static
не используется. Перегруженные операторы
new
и
Часть II. Язык программирования С++
220
delete
не могут быть виртуальными. Эти же замечания справед-
ливы и для перегруженных операторов
new[]
и
delete[]
.
Перегруженный оператор
new
должен иметь следующий прото-
тип:
[static] void* operator new(size_t[, параметры]);
То есть перегруженный оператор
new
должен возвращать значе-
ние типа
void*
и его первый параметр должен иметь тип
size_t
.
Значение первого параметра передается перегруженному опера-
тору
new
средой исполнения неявно и содержит размер памяти,
необходимой для размещения объекта класса. После первого па-
раметра могут следовать другие параметры, значения которых
должны быть переданы перегруженному оператору
new
явно.
В прототипе перегруженного оператора
new
можно также указать
спецификацию выбрасываемых этим оператором исключений.
Перегруженный оператор
delete
должен иметь следующий про-
тотип:
[static] void operator delete(void*[, параметры]);
То есть перегруженный оператор
delete
не должен возвращать
значения и его первый параметр должен иметь тип
void*
. Значе-
ние первого параметра передается перегруженному оператору
delete
явно и должно содержать адрес памяти, предварительно
распределенной для объекта перегруженным оператором
new
. По-
сле первого параметра могут следовать другие параметры.
В прототипе перегруженного оператора
delete
можно также ука-
зать спецификацию выбрасываемых этим оператором исклю-
чений.
В листинге 16.7 приведен пример перегрузки операторов
new
и
delete
как членов класса.
Листинг 16.7. Перегрузка операторов
new
и
delete
#include <iostream>
#include <cstdlib>
using namespace std;