
Лекции по ППВиС (17 шт, ppt) Романов ВИ 2011 1ый семестр / Л5_Перегрузка операторов
.ppt
1
Перегрузка операторов
В качестве примеров полиморфизма в С++ мы имели дело с перегрузкой функций. А что с перегрузкой операторов?
По сути дела каждый оператор в С++ и представляет собой функцию. Операторы могут иметь один или два аргумента. Если аргумент один, то такой оператор называется унарным. Пример ++ или --. Если аргументов два, то мы имеем дело с бинарным оператором.
Важно! В С++ нельзя перегрузить операторы встроенных типов! Это означает, что невозможно перегрузить оператор ++ таким образом, чтобы он инкрементировал элементы одномерного массива типа int. Все операторы встроенных типов С++ и так являются перегруженными и поэтому не стоит их перегружать.
Любые операции по перегрузке операторов относятся только к пользовательским типам данных, а точнее – к типам, которые описывают объекты.
Перегрузка операторов очень похожа на перегрузку функций. Перегруженный оператор может являться членом класса или быть дружественным к нему.
В С++ нельзя перегрузить оператор отдельно от класса. Если предполагается использование перегруженного оператора за пределами класса, он должен быть объявлен как public.

2
Перегрузка операторов – как и что можно
Прототип перегруженного оператора задается следующей синтаксической формой:
Возвращаемый_тип <имя_класса>:: оператор XX (аргументы);
Вместо XX непосредственно записывается оператор, который перегружается.
В С++ есть ряд операторов, которые не могут перегружаться. В основном это специфические операторы, используемые для работы
с методами и данными классов: ., .*, ::, sizeof и ?:.
По поводу последнего оператора. Это оператор условной трансляции. Он является в С++ единственным оператором, имеющим три аргумента.
Пример
…
int n;
…
cout << (n==1 ? "One" : "Non one");

3
Перегрузка операторов - ограничения
Нельзя перегрузить приоритет какого-либо оператора.
Это значит что вычисление (--k*2)+4 всегда будет происходить в соответствии с приоритетами в последовательности:
декрементация k, умножение результата на 2, добавление к результату 4.
И никак нельзя перегрузить оператор +, чтобы он выполнялся первым.
Могут быть перегружены и такие операторы С++ как new и delete.
Нельзя перегрузить унарный оператор таким образом, чтобы он работал как бинарный и наоборот.
Оператор не может иметь аргументов по умолчанию

4
Перегрузка операторов – базовый пример
Для рассмотрения вариантов перегрузки различных операторов нам понадобится какой-либо пример класса.
Будем работать, занимаясь перегрузками операторов следующего класса:
class Nmb { int n;
public:
Nmb(int n=0) {this->n = n; }; // конструктор void print();
};
void Nmb::print()
{
cout << "n= " << n << endl;
}

5
Перегрузка унарных операторов
Все унарные операторы имеют только один аргумент. При перегрузке этим аргументом является экземпляр класса, относительно которого производится перегрузка оператора.
В случае, когда унарный оператор перегружается как член класса ( а не как дружественная функция), то такой оператор не будет иметь аргументов. Рассмотрим пример перегрузки унарного оператора «-» для класса Nmb:
class Nmb {
…
Nmb& operator - ();
…
};
Nmb& Nmb::operator - ()
{
n = -n; return (*this);
}
Унарный оператор в качестве результирующего значения может возвращать void, однако возвращение ссылки на измененный объект позволяет использовать унарные операции в сложных записях выражений, особенно, где происходит присваивание объектов.
Перегруженный оператор может возвращать и встроенный тип. Это целесообразно, например, при перегрузке операции логического «НЕ».

6
Перегрузка унарных операторов «++» и «--»
Особо следует уделить внимание перегрузке операторов инкремента и декремента, поскольку только эти операторы имеют постфиксную и префиксную формы.
Различие этих форм осуществляется путем использования второго фиктивного аргумента типа int. Если необходимо подчеркнуть , что оператор будет использоваться в постфиксной форме, то необходимо наличие этого аргумента, который по умолчанию устанавливается в 0. Для класса Nmb:
Nmb& Nmb::operator ++ ()
{
++n;
return (*this);
}
Nmb& Nmb::operator ++ (int)
{
n++;
return (*this);
}

7
Перегрузка дружественных унарных операторов «+
+» и «--»
В случае перегрузки указанных операторов как дружественных по отношению к классу, их описание может быть выполнено как:
class Nmb {
…
friend Nmb& operator ++ (Nmb&); friend Nmb& operator ++ (Nmb&, int);
…
};
Nmb& operator ++ (Nmb& obj)
{
++(obj.n); return obj;
}
Nmb& operator ++ (Nmb& obj, int)
{
(obj.n)++; return obj;
}

8
Перегрузка бинарных операторов
Начнем со случая перегрузки операторов как членов класса. Функция реализации бинарного оператора будет иметь только один аргумент. Объясняется это тем, что второй аргумент по умолчанию является экземпляром этого класса.
Для начала перегрузим бинарные операторы «+» и «-» таким образом,
чтобы их можно было использовать так: |
Nmb n1, |
|
единственный аргумент при перегрузкеn2(5); |
||
будет иметь тип int. В обоих случаях этиn2 = n1 + 5; |
||
|
n1 = n2 – 3; |
|
операторы должны возвращать объекты, |
||
|
Nmb Nmb::operator + (const int m) |
|
поскольку результатом операции |
{ |
|
является объект, который |
Nmb tmp; |
|
tmp.n = this->n + m; |
||
присваивается другому. |
||
return tmp; |
||
class Nmb { |
} |
|
… |
Nmb Nmb::operator - (const int m) |
|
Nmb operator + (const |
{ |
|
int); |
Nmb tmp; |
|
tmp.n = this->n - m; |
||
Nmb operator - (const |
||
return tmp; |
||
int); |
||
} |
||
… |
|

9
Перегрузка бинарных операторов - как
Для того, чтобы не возникло никаких побочных эффектов при возврате объекта из перегруженного оператора, необходимо наличие конструктора копирования (если необходимо).
Важно! Данные операторы работают только при записях, приведенных в примерах их использования.
Если бы перегруженные операторы работали без временных объектов и возвращали бы ссылки на текущие объекты, то использование таких операторов было бы некорректным. Почему?
В случае операции n2 = n1 + 5 сначала бы сработал оператор «+», который бы изменил объект n1, а затем измененный объект присвоил бы объекту n2, т.е. произошло бы изменение сразу двух объектов.
Важно! Использовать данный оператор можно только в данной записи, когда первым операндом выступает объект-переменная, а вторым – константа. Это значит, что компилятор не пропустит записи вида n2 = 5+n1. Дело в том, что при такой записи для компилятора появляются два явных аргумента – это целое число и экземпляр класса. В этом случае при описании оператора внутри класса компилятор не пропустит эту запись и выдаст сообщение о том, что у бинарного оператора +(-) должен быть один аргумент, а не 2.

10
Перегрузка бинарных операторов как дружественных
Для решения этой проблемы можно определить перегружаемый оператор как дружественный к данному классу. В этом случае передача ссылки на объект в качестве второго аргумента кажется весьма оправданной!
class Nmb {
…
friend Nmb operator + ( const int, const Nmb&); friend Nmb operator - ( const int, const Nmb&);
…
};
Nmb operator + ( const int m, const Nmb &obj)
{
Nmb tmp;
tmp.n = m + obj.n return tmp;
}
Перегрузка оператора «-» будет идентичной, за исключением одной операции вычитания внутри тела оператора.