Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_С++_последная.doc
Скачиваний:
40
Добавлен:
07.05.2019
Размер:
876.54 Кб
Скачать

Конструкторы и Перегрузка операций.

8.1. Перегрузка операций

В C++ разрешено перегружать встроенные операции – это одно из проявлений полиморфизма. Перегрузка операций не является обязательной в ООП – в языках Java и С# она отсутствует. Однако наличие перегрузки операций в C++ обеспечивает дополнительный уровень удобства при использовании новых типов данных.

При программировании нового типа данных желательно объявлять объекты нового типа аналогично встроенным – формы инициализации не должны отличаться от форм инициализации объектов встроенного типа. Эти возможности обеспечивают конструкторы.

При перегрузке операции нужно учитывать следующие ограничения.

1. Запрещена перегрузка следующих операций:

- sizeof() – определение размера аргумента;

- . (точка) – селектор компонента объекта;

- ?: – условная операция;

- :: – указание области видимости;

-  .* – выбор компонента класса через указатель;

-  # и ## – операции препроцессора.

2. Операции можно перегружать только для нового типа данных – нельзя перегрузить операцию для встроенного типа. В C++ новый тип данных можно образовать с помощью конструкций enum, union, struct и class.

3. Нельзя изменить приоритет перегружаемой операции и количество операндов. Унарная операция обязана иметь один операнд, бинарная – два операнда; не разрешается использовать параметры по умолчанию. Единственная операция, которая не имеет фиксированного количества операндов, – это операция вызова функции (). Операции «+», «-», «*», «&» допускается перегружать и как унарные, и как бинарные.

4. Операции можно перегружать либо как независимые внешние функции (только такой способ перегрузки допустим для enum), либо как методы класса. Четыре операции:

- присваивания =;

- вызова функции ();

- индексирования [];

- доступа по указателю ->;

- допускается перегружать только как методы класса. Эти операции в принципе нельзя перегрузить для конструкции enum.

5. Если операция перегружается как метод класса, то левым (или единственным) аргументом обязательно будет объект класса, для которого перегружается операция.

Прототип функции-операции выглядит следующим образом:

тип operator@(список параметров);

где @ – символ операции. Слово operator является зарезервированным словом и может использоваться только в определении или в функциональной форме вызова операции.

8.1.1. Перегрузка операций внешними функциями

Прототип бинарной операции, перегружаемой как внешняя независимая функция, выглядит так:

тип operator@(параметр_1, параметр_2);

Для обеспечения коммутативности бинарной операции с параметрами разного типа, как правило, требуется реализовать две функции-операции:

тип operator@(параметр_1, параметр_2);

тип operator@(параметр_2. параметр_1);

Хотя бы один из параметров должен быть нового типа. Параметры можно передавать любым допустимым способом. Обращение к операции выполняется двумя способами:

- инфиксная форма параметр_1 @ параметр 2;

- функциональная форма operator@ (параметр_1, параметр2).

Прототип унарной операции, перегружаемой независимой внешней функцией, отличается только количеством параметров:

тип operator@(параметр);

Параметр должен быть нового типа. Обращаться к перегруженной операции следует так:

- инфиксная форма @параметр;

- функциональная форма operator@(параметр).

Операции инкремента ++ и декремента -- имеют две формы: префиксную и постфиксную. В определении постфиксной формы операции должен быть объявлен дополнительный параметр типа int.

тип operator@(параметр, int);

Этот параметр не должен использоваться в теле функции. Инфиксная форма обращения к такой операции – параметр@; при функциональной форме обращения необходимо задавать второй фиктивный аргумент, например: operator@(параметр,0);

В следующем листинге программы приведен пример перегрузки операций для перечислимого типа.

enum Week { mon = 1, tue, wed, thu, fri, sat. sun = 0 };

Week operator+(const Week &m, const int &b)

{ Week t = Week(b + m);

return (t = Week(t%7));

}

// вторая функция для коммутативности сложения

Week operator+(const int &b, const Week &m)

{ return (m+b); }

Week operator++(Week &m) // префиксная форма

{ return (m = Week(m+l)); }

Week operator++(Week &m, int) // постфиксная форма

{ Week t = m; m = Week(m+l); return t; }

void print(const Week &d) //вывод на экран названий дней недели

{ string Days[7] = {"Sunday", "Monday", "Tuesday".

"Wednesday", "Thursday", "Friday", "Saturday"

};

cout << Days[d] << endl;

};

Week m = sat: // m = суббота

print(m+l); // выводит 'Sunday'

print(2+m); // выводит 'Monday'

print(operator+(m.D); // выводит 'Sunday'

print(operator+(2.m)); // выводит 'Monday'

m++; // вызов постфиксной формы, m == sun

print(m); // выводит 'Sunday'

print(++m); // выводит 'Monday'

print(operator++(m)); // префиксная форма, выводит 'Tuesday'

print(operator++(m,0)); // постфиксная форма, выводит 'Tuesday'

print(m); // выводит 'Wednesday'

При перегрузке операции внешней для класса функцией поля должны быть открыты или класс должен предоставлять методы get О и set О для получения и изменения значений полей.

Пример перегрузки операции внешней функцией для класса показан в следующем листинге программы.

struct Fraction

{ int num; int denum; // поля - открыты

void reduce (); // метод - открыт

};

Fraction operator+(const Fraction &l. const Fraction &r)

{ Fraction t;

// (a.b)+(c,d)=(ad+bc.bd)

t.denum = l.denum*r.denum; // знаменатель результата

t.num = 1.num*r.denum+r.num*l.denum; // числитель результата

t.reduce(): // сокращение

return t:

}

Fraction a, b, c;

// ...

a = b + с; // инфиксная форма

a - operator+(b.c); // функциональная форма