C++. Сборник рецептов - [122]
Представьте себе инкремент целого числа. С помощью оператора >++
имеется два способа выполнить его для некоторого целого >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
>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;
Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)
Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.
Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.
Система сборки программ, используемая во FreeBSD, имеет значительно большие возможности, чем те, которые мы задействовали. Какие это возможности и как их использовать в своих портах?
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.
«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.