Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бьерн Страуструп C++.doc
Скачиваний:
12
Добавлен:
07.11.2018
Размер:
2.45 Mб
Скачать

Глава 7.

Если я выбираю слово, оно значит только то,

что я решу, ни больше и ни меньше.

- Шалтай Болтай

Глава содержит описание механизма перегрузки операций в С++. Программист может задать интерпретацию операций, когда они применяются к объектам определенного класса. Помимо арифметических, логических и операций отношения можно переопределить вызов функций (), индексацию [], косвенное обращение ->, а также присваивание и инициализацию. Можно определить явные и скрытые преобразования между пользовательскими и основными типами. Показано, как определить класс, объект которого можно копировать и уничтожать только с помощью специальных, определенных пользователем функций.

7.1 Введение

Обычно в программах используются объекты, являющиеся конкретным представлением абстрактных понятий. Например, в С++ тип данных int вместе с операциями +, -, *, / и т.д. реализует (хотя и ограниченно) математическое понятие целого. Обычно с понятием связывается набор действий, которые реализуются в языке в виде основных операций над объектами, задаваемых в сжатом, удобном и привычном виде. К сожалению, в языках программирования непосредственно представляется только малое число понятий. Так, понятия комплексных чисел, алгебры матриц, логических сигналов и строк в С++ не имеют непосредственного выражения. Возможность задать представление сложных объектов вместе с набором операций, выполняемых над такими объектами, реализуют в С++ классы. Позволяя программисту определять операции над объектами классов, мы получаем более удобную и традиционную систему обозначений для работы с этими объектами по сравнению с той, в которой все операции задаются как обычные функции. Приведем пример:

class complex {

double re, im;

public:

complex(double r, double i) { re=r; im=i; }

friend complex operator+(complex, complex);

friend complex operator*(complex, complex);

};

Здесь приведена простая реализация понятия комплексного числа, когда оно представлено парой чисел с плавающей точкой двойной точности, с которыми можно оперировать только с помощью операций + и *. Интерпретацию этих операций задает программист в определениях функций с именами operator+ и operator*. Так, если b и c имеют тип complex, то b+c означает (по определению) operator+(b,c). Теперь можно приблизиться к привычной записи комплексных выражений:

void f()

{

complex a = complex(1,3.1);

complex b = complex(1.2,2);

complex c = b;

a = b+c;

b = b+c*a;

c = a*b+complex(1,2);

}

Сохраняются обычные приоритеты операций, поэтому второе выражение выполняется как b=b+(c*a), а не как b=(b+c)*a.

7.2 Операторные функции

Можно описать функции, определяющие интерпретацию следующих операций:

+ - * / % ^ & | ~ !

= < > += -= *= /= %= ^= &=

|= << >> >>= <<= == != <= >= &&

|| ++ -- ->* , -> [] () new delete

Последние пять операций означают: косвенное обращение ($$7.9), индексацию ($$7.7), вызов функции ($$7.8), размещение в свободной памяти и освобождение ($$3.2.6). Нельзя изменить приоритеты этих операций, равно как и синтаксические правила для выражений. Так, нельзя определить унарную операцию % , также как и бинарную операцию !. Нельзя ввести новые лексемы для обозначения операций, но если набор операций вас не устраивает, можно воспользоваться привычным обозначением вызова функции. Поэтому используйте pow(), а не ** . Эти ограничения можно счесть драконовскими, но более свободные правила легко приводят к неоднозначности. Допустим, мы определим операцию ** как возведение в степень, что на первый взгляд кажется очевидной и простой задачей. Но если как следует подумать, то возникают вопросы: должны ли операции ** выполняться слева направо (как в Фортране) или справа налево (как в Алголе)? Как интерпретировать выражение a**p как a*(*p) или как (a)**(p)?

Именем операторной функции является служебное слово operator, за которым идет сама операция, например, operator<<. Операторная функция описывается и вызывается как обычная функция. Использование символа операции является просто краткой формой записи вызова операторной функции:

void f(complex a, complex b)

{

complex c = a + b; // краткая форма

complex d = operator+(a,b); // явный вызов

}

С учетом приведенного описания типа complex инициализаторы в этом примере являются эквивалентными.