- Любовные романы
- Фантастика и фэнтези
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
C++. Сборник рецептов - Д. Стефенс
Шрифт:
Интервал:
Закладка:
Рецепт 8.11.
8.13. Перегрузка операторов инкремента и декремента
ПроблемаИмеется класс, для которого имеют смысл операции инкремента и декремента, и требуется перегрузить operator++ и operator--, которые позволят легко и интуитивно выполнять инкремент и декремент объектов этого класса.
РешениеЧтобы это сделать, перегрузите префиксную и постфиксную формы ++ и --. Пример 8.14 показывает обычную методику перегрузки операторов инкремента и декремента.
Пример 8.14. Перегрузка инкремента и декремента
#include <iostream>
using namespace std;
class Score {
public:
Score() : score_(0) {}
Score(int i) : score_(i) {}
Score& operator++() {
// префикс
++score_;
return(*this);
}
const Score operator++(int) {
// постфикс
Score tmp(*this);
++(*this); // Использование префиксного оператора
return(tmp);
}
Score& operator--() {
--score_;
return(*this);
}
const Score operator--(int x) {
Score tmp(*this);
--(*this);
return(tmp);
}
int getScore() const {return(score_);}
private:
int score_;
};
int main() {
Score player1(50);
player1++;
++player1; // score = 52
cout << "Счет = " << player1.getScore() << 'n';
(--player1)--; // score_ = 50
cout << "Счет = " << player1.getScore() << 'n';
}
ОбсуждениеОператоры инкремента и декремента часто имеют смысл для классов, которые представляют некоторые разновидности целых значений. Если вы понимаете разницу между префиксной и постфиксной формами и следуете соглашениям о возвращаемых значениях, то их легко использовать.
Представьте себе инкремент целого числа. С помощью оператора ++ имеется два способа выполнить его для некоторого целого i.
i++; // постфиксный
++i; // префиксный
Оба инкрементируют i: первая версия создает временную копию i, инкрементирует i и затем возвращает временное значение, а вторая инкрементирует i и затем возвращает его. C++ позволяет выполнять перегрузку операторов, что означает, что вы можете заставить свой собственный тип (класс или enum) вести себя так же, как и int.
Чтобы добиться нужного эффекта, перегрузите operator++ и operator--. Пример 8.14 иллюстрирует, как перегружать префиксную и постфиксную версии.
Score& operator++() { // префиксный
++score_;
return(*this);
}
const Score operator++(int) { // постфиксный
Score tmp(*this);
++(*this);
return(tmp);
}
Префикс выглядит так, как и следует ожидать, но компилятор различает эти две версии, и в объявление постфиксной версии включается параметр int. Он не имеет семантического применения — он всегда передается как ноль, так что его можно игнорировать.
После этого класс Score можно использовать как int.
Score player1(50);
player1++;
++player1; // score_ = 52
Вы, вероятно, заметили, что сигнатуры префиксной версии operator++ возвращают ссылку на текущий класс. Именно так и следует делать (а не возвращать, к примеру, void), чтобы инкрементируемый или декрементируемый объект мог использоваться в других выражениях. Рассмотрим такую строку из примера.
(--player1)--;
Да, это странно, но она иллюстрирует этот момент. Если бы префиксный operator-- не возвращал чего-то осмысленного, то это выражение не скомпилировалось бы. Еще один пример показывает вызов функции.
foo(--player1);
Функция foo ожидает аргумент типа Score, и для корректной компиляции именно это должно возвращаться из префиксного operator--.
Перегрузка операторов — это мощная возможность, которая позволяет для типов, определяемых пользователем, использовать те же операторы, что и для встроенных типов. Сторонники других языков, которые не поддерживают перегрузку операторов, утверждают, что эта возможность сбивает с толку и очень сложна, и, следует признать, может быть перегружено очень много операторов, соответствующих любому поведению. Но когда дело касается простого инкремента и декремента, хорошо иметь возможность изменить поведение класса так, как этого хочется.
Смотри такжеРецепт 8.14.
8.14. Перегрузка арифметических операторов и операторов присвоения для работы с классами
ПроблемаИмеется класс, для которого имеют смысл некоторые из унарных или бинарных операторов С++, и требуется, чтобы пользователи класса могли использовать их при работе с объектами этого класса. Например, если есть класс с именем Balance, который содержит значение с плавающей точкой (например, баланс счета), будет удобно, если для объектов Balance можно было бы использовать некоторые стандартные операторы С++, как здесь.
Balance checking(50.0);
savings(100.0);
checking += 12.0;
Balance total = checking + savings;
РешениеПерегрузите операторы, которые требуется использовать как методы и отдельные функции, указав аргументы различных типов, для которых данный оператор имеет смысл, как в примере 8.15.
Пример 8.15. Перегрузка унарных и бинарных операторов
#include <iostream>
using namespace std;
class Balance {
// These have to see private data
friend const Balance operator+(const Balance& lhs, const Balance& rhs);
friend const Balance operator+(double lhs, const Balance& rhs);
friend const Balance operator+(const Balance& lhs, double rhs);
public:
Balance() : val_(0.0) {}
Balance(double val) : val_(val) {}
~Balance() {}
// Унарные операторы
Balance& operator+=(const Balance& other) {
val_ += other.val_;
return(*this);
}
Balance& operator+=(double other) {
val_ += other;
return(*this);
}
double getVal() const {return(val_);}
private:
double val_;
};
// Бинарные операторы
const Balance operator+(const Balance& lhs, const Balance& rhs) {
Balance tmp(lhs.val_ + rhs.val_);
return(tmp);
}
const Balance operator+(double lhs, const Balance& rhs) {
Balance tmp(lhs + rhs.val_);
return(tmp);
}
const Balance operator+(const Balance& lhs, double rhs) {
Balance tmp(lhs.val_ + rhs);
return(tmp);
}
int main() {
Balance checking(500.00);
savings(23.91);
checking += 50;
Balance total = checking + savings;
cout << "Платежный баланс: " << checking.getVal() << 'n';
cout << "Общий баланс: " << total.getVal() << 'n';
}
ОбсуждениеНаиболее часто используют перегрузку для арифметических операторов и операторов присвоения. Существует огромное количество различных классов, для которых имеют смысл арифметические операторы (сложение, умножение, остаток от деления, сдвиг битов вправо/влево) и операторы присвоения — вне зависимости от того, используются ли они для вычислений или для чего-то другого. Пример 8.15 показывает основные методики перегрузки этих операторов.
Давайте начнем с того, что, вероятно, является наиболее часто перегружаемым оператором, — оператора присвоения. Оператор присвоения используется при присвоении одного объекта другому, как в следующем выражении.
Balance x(0), у(32);
x = y;
Вторая строка — это краткая запись вызова Balance::operator=(y). Оператор присвоения отличается от большинства других операторов тем, что если вы не создаете собственной его версии, то компилятором создается версия по умолчанию. Версия по умолчанию просто копирует в текущий объект каждый член целевого объекта, что, конечно, не всегда приемлемо, так что его можно перегрузить и обеспечить другое поведение или перегрузить и предоставить возможность присвоения объектов типов, отличных от текущего
Для класса Balance из примера 8.15 оператор присвоения можно определить вот так.
Balance& operator=(const Balance& other) {
val_ = other.val_;
return(*this);
}
Первое, на что вы должны обратить внимание, если не знакомы с перегрузкой операторов, — это синтаксис operator=. Именно так объявляются все операторы. Все операторы можно рассматривать как функции с именами operator[symbol], где symbol — это перегружаемый оператор. Единственным различием между операторами и обычными функциями является синтаксис их вызова. На самом деле, если вы хотите ввести побольше кода и написать отвратительно выглядящий код, то операторы можно вызывать и с помощью такого синтаксиса.