
- •Конструкторы и перегрузка операций
- •Введение
- •Лабораторная работа № 1. Конструкторы
- •Выполнение лабораторной работы
- •Методические указания к выполнению лабораторной работы
- •Int hours, minutes, seconds; // закрытые поля
- •Int getDigitByPosition(int pos); // возврат цифры числа по позиции
- •Int transferTo10(); // перевод в десятичную систему счисления
- •Void transferFrom10(int numb); // перевод из десятичной системы счисления
- •Int p_number_class::getDigitByPosition(int pos) {
- •Int p_number_class::transferTo10() {
- •Void p_number_class::transferFrom10(int numb) {
- •Int main(int argc, char* argv[])
- •Лабораторная работа № 2. Перегрузка операций
- •Выполнение лабораторной работы
- •Методические указания к выполнению лабораторной работы
- •Void print(const Week &d) // вывод на экран названий дней недели
- •Int denum; // поля - открыты
- •Void reduce(); // метод - открыт
- •Int getDigitByPosition(int pos); // возврат цифры числа по позиции
- •Int transferTo10(); // перевод в десятичную систему счисления
- •Void transferFrom10(int numb); // перевод из десятичной системы счисления
- •Int p_number_class::getDigitByPosition(int pos) {
- •Int p_number_class::transferTo10() {
- •Void p_number_class::transferFrom10(int numb) {
- •Int main(int argc, char* argv[])
- •Библиографический список
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,l)): // выводит 'Sunday'
print(operator+(2,m)): // выводит 'Monday'
m++; // вызов постфиксной формы, m == sun
print(m); // выводит 'Sunday'
print(++m); // выводит 'Monday'
print(operator++(m)); // префиксная форма, выводит 'Tuesday'
print(operator++(m,u)): // постфиксная форма, выводит '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 = l.num*r.denum+r.num*l.denum; // числитель результата
t.reduce(); // сокращение
return t;
}
Fraction a, b, c;
// ...
a = b + с; // инфиксная форма
a = operator+(b,c); // функциональная форма
Перегрузка операций методами класса
У методов один параметр – текущий объект – определен по умолчанию. Унарные операции выполняются для текущего объекта, который и является единственным аргументом. Поэтому унарные операции, перегружаемые как методы класса, не имеют параметров. Прототип унарной операции, реализованной как метод класса, выглядит так:
тип operator@();
где @ – символ операции. Возвращаемое значение может быть любого типа, в том числе и определяемого класса. Операция может возвращать значение, ссылку или указатель на объект. Разрешается указывать void на месте типа возвращаемого значения.
Постфиксные операции инкремента и декремента являются исключением из этого правила. Чтобы отличить постфиксную операцию от префиксной, в постфиксной форме задается фиктивный параметр типа int, который реально не используется.
Префиксная форма инкремента (и декремента) должна иметь прототип
тип& operator@();
Постфиксная операция инкремента (и декремента) должна иметь прототип
тип operator@(int);
Тип – это «имя_класса», в котором определяется операция.
Прототип бинарной операции имеет один аргумент и выглядит таким образом:
тип operator@(параметр);
Параметры разрешается передавать любым удобным нам способом: по значению, по ссылке или по указателю. Возвращать метод-операция тоже может значение, указатель или ссылку на объект, в том числе и своего класса. Разрешается указывать void на месте типа возвращаемого значения.
При реализации метода-операции вне класса требуется в заголовке обычным образом указывать префикс-имя класса:
тип класс::operator@() // унарная операция
тип класс::operator@(параметр) // бинарная операция
Вызов унарной операции для объекта имеет форму
@объект
объект@
в зависимости от того, какой вид операции используется – префиксный или постфиксный. Функциональный вызов для префиксной операции имеет форму
объект.operator@()
Для постфиксной операции в функциональной форме вызова нужно задавать фиктивный аргумент:
объект.operator@(0)
Функциональная форма вызова для бинарной операции, определенной как метод класса, выглядит так:
объект.operator@(аргумент)
Инфиксная форма
объект @ аргумент
является сокращением функциональной.
Операции присваивания являются бинарными операциями, поэтому должны иметь один аргумент. Если операция присваивания operator= не реализуется явным образом, она создается автоматически по умолчанию. Для любого класса автоматически создаваемая операция присваивания имеет прототип
класс& operator=(const класс &r)
Допускается реализовать операцию присваивания с параметром и возвращаемым результатом не своего класса; разрешается передавать параметр любым способом; возвращать можно не ссылку, а значение или указатель — все зависит от потребностей задачи.
Другие операции с присваиванием автоматически не создаются. Функции-операции с присваиванием обычно должны возвращать ссылку на текущий объект. Любой метод, возвращающий неконстантную ссылку, можно использовать многократно.
Money& Money::operator+=(const Money &b)
Повторное использование можно явным образом запретить, если возвращать константную ссылку, например
const Moneys Money::operator+=(const Money &b)
Модификатор const запрещает дальнейшую модификацию результата.
Функции-друзья класса
Любая внешняя функция, определенная как «друг» класса, имеет неограниченный доступ к любым элементам класса, в том числе и к закрытым. Для того чтобы внешняя функция стала другом класса, необходимо в интерфейсе класса задать ее прототип, добавив впереди слово friend, например
friend Money operator*(const long double &a, const Money &b);
При реализации функции слово friend писать запрещается. Не указывается также и префикс класса.
Рекомендуемые формы перегрузки операций для класса приведены в таблице 1. В частности, операции ввода/вывода operator>> и operator<< практически всегда реализуются как внешние дружественные функции. Например, для класса Two с двумя полями х и у целого типа эти функции могут выглядеть так:
ostream& operator<<(ostream& t, const Two &r)
{ return (t << '(' << r.x << '.' << r.y << ')'); }
istream& operator>>(istream& t, Two &r)
{ t >> r.x >> r.y; return t; )
Пример перегрузки операций методами класса и дружественными функциями
class F
{
int f;
int m;
public:
F(int t, int r = 0):f(t),m(r)// конструктор
{ }
F& operator++() // префиксный инкремент
{ f++; return *this; }
F operator++(int) // постфиксный инкремент
{F t= *this; f++; return t; }
F& operator+=(const F& r) // сложение с присваивание
{ f+=r.f; m+=r.m; return *this; }
// дружественные функции
friend F operator+(const F &l, const F &r);
friend ostream& operator<<(ostream& t, const F &r);
friend istream& operator>>(istream& t, F &r);
};
// реализация дружественных функций
F operator+(const F &l, const F &r)
{ F t = l; t+=r; return t; }
// дружественные функции ввода/вывода
ostream& operator«(ostream& t, const F &r)
{ return (t << r.f << '/' << r.m); }
istream& operator>>(istream& t, F &r)
{ t >> r.f >> r.m; return t; }
Таблица 1
Форма перегрузки операций
Операция |
Рекомендуемая форма перегрузки |
Все унарные операции |
Метод класса |
- [] 0 -> * |
Обязательно метод класса |
+= -= *= /= %= &=. |= ^= <<= >>= |
Метод класса |
Остальные бинарные операции |
Внешняя функция-друг |
В описание класса добавляем конструкторы:
class P_number_class {
char number[200]; // число
unsigned int scale_of_notation; // система счисления