Перегрузка операторов

Поделись знанием:
Перейти к: навигация, поиск

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





Терминология

Термин перегрузка — это калька английского слова overloading. Такой перевод появился в книгах по языкам программирования в первой половине 1990-х годов. В изданиях советского периода аналогичные механизмы назывались переопределением или повторным определением, перекрытием операций.[1]

Причины появления

Иногда возникает потребность описывать и применять к созданным программистом типам данных операции, по смыслу эквивалентные уже имеющимся в языке. Классический пример — библиотека для работы с комплексными числами. Они, как и обычные числовые типы, поддерживают арифметические операции, и естественным было бы создать для данного типа операции «плюс», «минус», «умножить», «разделить», обозначив их теми же самыми знаками операций, что и для других числовых типов. Запрет на использование определённых в языке элементов вынуждает создавать множество функций с именами вида ComplexPlusComplex, IntegerPlusComplex, ComplexMinusFloat и так далее.

Когда одинаковые по смыслу операции применяются к операндам различных типов, их вынужденно приходится называть по-разному. Невозможность применять для разных типов функции с одним именем приводит к необходимости выдумывать различные имена для одного и того же, что создаёт путаницу, а может и приводить к ошибкам. Например, в классическом языке Си существует два варианта стандартной библиотечной функции нахождения модуля числа: abs() и fabs() — первый предназначен для целого аргумента, второй — для вещественного. Такое положение, в сочетании со слабым контролем типов Си, может привести к труднообнаруживаемой ошибке: если программист напишет в вычислении abs(x), где x — вещественная переменная, то некоторые компиляторы без предупреждений сгенерируют код, который будет преобразовывать x к целому путём отбрасывания дробной части и вычислять модуль от полученного целого числа!

Отчасти проблема решается средствами объектного программирования — когда новые типы данных объявляются как классы, операции над ними могут быть оформлены как методы классов, в том числе и одноимённые (поскольку методы разных классов не обязаны иметь различные имена), но, во-первых, оформление подобным образом операций над значениями разных типов неудобно, а во-вторых, это не решает проблему создания новых операторов.

Средства, позволяющие расширять язык, дополнять его новыми операциями и синтаксическими конструкциями (а перегрузка операций является одним из таких средств, наряду с объектами, макрокомандами, функционалами, замыканиями) превращают его уже в метаязык — средство описания языков, ориентированных на конкретные задачи. С его помощью можно для каждой конкретной задачи построить языковое расширение, наиболее ей соответствующее, которое позволит описывать её решение в наиболее естественной, понятной и простой форме. Например, в приложении к перегрузке операций: создание библиотеки сложных математических типов (векторы, матрицы) и описание операций с ними в естественной, «математической» форме, создаёт «язык для векторных операций», в котором сложность вычислений скрыта, и возможно описывать решение задач в терминах векторных и матричных операций, концентрируясь на сути задачи, а не на технике. Именно из этих соображений подобные средства были в своё время включены в язык Алгол-68.

Механизм перегрузки

Реализация

Перегрузка операций предполагает введение в язык двух взаимосвязанных особенностей: возможности объявлять в одной области видимости несколько процедур или функций с одинаковыми именами и возможности описывать собственные реализации бинарных операторов (то есть знаков операций, обычно записываемых в инфиксной нотации, между операндами). Принципиально реализация их достаточно проста:

  • Чтобы разрешить существование нескольких одноимённых операций, достаточно ввести в язык правило, согласно которому операция (процедура, функция или оператор) опознаются компилятором не только по имени (обозначению), но и по типам их параметров. Таким образом, abs(i), где i объявлено как целое, и abs(x), где x объявлено как вещественное — это две разные операции. Принципиально в обеспечении именно такой трактовки нет никаких сложностей.
  • Чтобы дать возможность определять и переопределять операции, необходимо ввести в язык соответствующие синтаксические конструкции. Вариантов их может быть достаточно много, но по сути они ничем друг от друга не отличаются, достаточно помнить, что запись вида «<операнд1> <знакОперации> <операнд2>» принципиально аналогична вызову функции «<знакОперации>(<операнд1>,<операнд2>)». Достаточно разрешить программисту описывать поведение операторов в виде функций — и проблема описания решена.

Перегрузка операторов в C++

В C++ можно выделить четыре типа перегрузок операторов:

  1. Перегрузка обычных операторов + - * / % ˆ & | ~ ! = < > += -= *= /=%= ˆ= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> ( ) [ ]
  2. Перегрузка операторов преобразования типа
  3. Перегрузка операторов аллокации и деаллокации new и delete
  4. Перегрузка литералов operator""

Обычные операторы

Важно помнить, что перегрузка расширяет возможности языка, а не изменяет язык, поэтому перегружать операторы для встроенных типов нельзя. Нельзя менять приоритет и ассоциативность (слева направо или справа налево) операторов. Нельзя создавать собственные операторы и перегружать некоторые встроенные: :: . .* ?: sizeof typeid. Также операторы && || , теряют свои уникальные свойства при перегрузке: ленивость для первых двух и очерёдность для запятой (порядок выражений между запятыми строго определён, как лево-ассоциативный, то есть слева-направо). Оператор -> должен возвращать либо указатель, либо объект (по копии или ссылке).

Операторы могут быть перегружены и как отдельные функции, и как функции-члены класса. Во втором случае левым аргументом оператора всегда выступает объект *this. Операторы = -> [] () могут быть перегружены только как методы (функции-члены), но не как функции.

Можно сильно облегчить написание кода, если производить перегрузку операторов в определённом порядке. Это не только ускорит написание, но и избавит от повторений одного и того же кода. Рассмотрим перегрузку на примере класса, представляющего собой геометрическую точку в двумерном векторном пространстве:

class Point
{
    int x, y;
  public:
    Point(int x, int xx): x(x), y(xx) {}  // Конструктор по-умолчанию исчез. 
    // Имена аргументов конструктора могут совпадать с именами полей класса.
}
  • Операторы присваивания копированием и перемещением operator=
    Стоит учитывать, что по-умолчанию C++ помимо конструктора создаёт пять базовых функций. Поэтому перегрузку операторов присваивания копированием и перемещением лучше отдать на реализацию компилятору или реализовать с помощью идиомы Copy-and-swap.
  • Комбинированные арифметические операторы += *= -= /=%= и т. д.
    Если мы хотим реализовать обычные бинарные арифметические операторы, удобнее будет реализовать вначале данную группу операторов.
    Point& Point::operator+=(const Point& rhs) {
    	x += rhs.x;
    	y += rhs.y;
    	return *this;
    }
Оператор возвращает значение по ссылке, это позволяет писать такие конструкции: (a += b) += c;
  • Арифметические операторы + * - / %
    Чтобы избавиться от повторения кода, воспользуемся нашим оператором комбинированным оператором. Оператор не модифицирует объект, поэтому возвращает новый объект.
    const Point Point::operator+(const Point& rhs) const {
    	return Point(*this) += rhs;
    }
Оператор возвращает const значение. Это защитит нас от написания конструкций подобного вида (a + b) = c;. С другой стороны, для классов, копирование которых дорого обходится, гораздо выгоднее возвращать значение по неконстантной копии, т. е. : MyClass MyClass::operator+(const MyClass& rhs) const;. Тогда при такой записи x = y + z; будет вызван конструктор перемещения, а не копирования.
  • Унарные арифметические операторы + -
    Унарные плюс и минус не принимают аргументов при перегрузке. Они не изменяют сам объект (в нашем случае), а возвращают новый изменённый объект. Следует перегрузить и их, если перегружены их бинарные аналоги.
Point Point::operator+() {
	return Point(*this);
}
Point Point::operator-() {
	Point tmp(*this);
	tmp.x*=-1;
	tmp.y*=-1;
	return tmp;
}
  • Операторы сравнения == != < <= > >=
    Первыми следует перегрузить операторы равенства и неравенства. Оператор неравенства будет использовать оператор равенства.
bool Point::operator==(const Point& rhs) const {
	return (this->x == rhs.x && this->y == rhs.y);
}
bool Point::operator!=(const Point& rhs) const {
	return !(*this == rhs);
}
Следом перегружаются операторы < и >, а затем их нестрогие аналоги, с помощью ранее перегруженных операторов. Для точек в геометрии такая операция не определена, поэтому в данном примере нет смысла их перегружать.
  • Побитовые операторы <<= >>= &= |= ^= и << >> & | ^ ~
    На них распространяется те же принципы, что и на арифметические. В некоторых классах пригодится использование битовой маски std::bitset. Внимание: оператор & имеет унарный аналог и используется для взятия адреса; обычно не перегружается.
  • Логические операторы && ||
    Эти операторы потеряют свои уникальные свойства ленивости при перегрузке.
  • Инкремент и декремент ++ --
    C++ позволяет перегрузить как постфиксные, так и префиксные инкремент и декремент. Рассмотрим инкремент:
Point& Point::operator++() { //префиксный
	x++;
	y++;
	return *this;
}
Point Point::operator++(int) { //постфиксный
	Point tmp(x,y);
	++(*this);
	return tmp;
}
Заметим, что функция-член operator++(int) принимает значение типа int, но у этого аргумента нет имени. C++ позволяет создавать такие функции. Мы можем присвоить ему (аргументу) имя и увеличивать значения точек на этот коэффициент, однако в операторной форме этот аргумент по-умолчанию будет равен нулю и вызывать его можно будет только в функциональном стиле: A.operator++(5);
  • Оператор () не имеет ограничений на тип возвращаемого значения и типы/количество аргументов и позволяет создавать функторы.
  • Оператор передачи класса в поток вывода. Реализуется в виде отдельной функции, а не функции-члена. В классе эта функция помечается как дружественная.friend std::ostream& operator<<(const ostream& s, const Point& p);

На остальные операторы не распространяются какие-либо общие рекомендации к перегрузке.

Преобразования типов

Преобразования типов позволяют задать правила преобразования нашего класса к другим типам и классам. Также можно указать спецификатор explicit, который позволит преобразовывать типы только, если программист явно это указал (например static_cast<Point3>(Point(2,3));). Пример:

Point::operator bool() const {
	return this->x != 0 || this->y != 0;
}

Операторы аллокации и деаллокации

Операторы new new[] delete delete[] могут быть перегружены и могут принимать любое количеств аргументов. Причём операторы new и new[] первым аргументом обязаны принять аргумент типа std::size_t и возвращать значение типа void *, а операторы delete delete[] принимать первым void * и ничего не возвращать (void). Эти операторы могут быть перегружены как функции, так и для конкретных классов.

Пример:

void* MyClass::operator new(std::size_t s, int a)
{
    void * p = malloc(s*a);
    if(p == nullptr)
        throw "No free memory!";
    return p;
}
// ...
// Вызов:
MyClass * p = new(12) MyClass;


Пользовательские литералы

Пользовательские литералы появились с одиннадцатого стандарта C++. Литералы ведут себя как обычные функции. Они могут быть с квалификатором inline или constexpr. Желательно, чтобы литерал начинался с символа нижнего подчёркивания, так как может возникнуть коллизия с будущими стандартами. Например, литерал i уже принадлежит комплексным числам из std::complex.

Литералы могут принимать только один из следующих типов: const char * , unsigned long long int , long double , char , wchar_t , char16_t , char32_t. Достаточно перегрузить литерал только для типа const char *. Если не найдено более подходящего кандидата, то будет вызван оператор с этим типом. Пример преобразования миль в километры:

constexpr int operator "" _mi (unsigned long long int i)
{ return 1.6 * i;}

constexpr double operator "" _mi (long double i)
{ return 1.6 * i;}

Строковые литералы принимают вторым аргументом std::size_t, а первым один из: const char * , const wchar_t *, const char16_t * , const char32_t *. Строковые литералы применяются к записям, записанным в двойных кавычках.

В C++ встроен префиксный строковый литерал R, который воспринимает все символы в кавычках как обычные и не интерпретирует определённые последовательности в специальный символы. Например, такая команда std::cout << R"(Hello!\n)" выведет на экран Hello!\n.

Пример реализации на С#

Перегрузка операторов тесно связана с перегрузкой методов. Для перегрузки оператора служит ключевое слово Operator, определяющее «операторный метод», который, в свою очередь, определяет действие оператора относительно своего класса. Существует две формы операторных методов (operator): одна — для унарных операторов, другая для бинарных. Ниже приведена общая форма для каждой разновидности этих методов.

// общая форма перегрузки унарного оператора.
public static возвращаемый тип operator op (тип_параметра операнд)
{
// операции
}
// Общая форма перегрузки бинарного оператора.
public static возвращаемый_тип operator op (тип_параметра1 операнд1,
                                            тип_параметра2 операнд2)
{
// операции
}

Здесь вместо «op» подставляется перегружаемый оператор, например + или /; а «возвращаемый_тип» обозначает конкретный тип значения, возвращаемого указанной операцией. Это значение может быть любого типа, но зачастую оно указывается такого же типа, как и у класса, для которого перегружается оператор. Такая корреляция упрощает применение перегружаемых операторов в выражениях. Для унарных операторов операнд обозначает передаваемый операнд, а для бинарных операторов то же самое обозначают «операнд1 и операнд2». Следует обратить внимание, что операторные методы должны иметь оба типа, public и static. Тип операнда унарных операторов должен быть таким же, как и у класса, для которого перегружается оператор. А в бинарных операторах хотя бы один из операндов должен быть такого же типа, как и у его класса. Следовательно, в C# не допускается перегрузка любых операторов для объектов, которые еще не были созданы. Например, назначение оператора + нельзя переопределить для элементов типа int или string. И еще одно замечание: в параметрах оператора нельзя использовать модификатор ref или out.[2]

Варианты и проблемы

Перегрузка процедур и функций на уровне общей идеи, как правило, не представляет сложности ни в реализации, ни в понимании. Однако даже в ней имеются некоторые «подводные камни», которые необходимо учитывать. Разрешение перегрузки операций создаёт гораздо больше проблем как для реализатора языка, так и для работающего на этом языке программиста.

Проблема идентификации

Первый вопрос, с которым сталкивается разработчик транслятора языка, разрешающего перегрузку процедур и функций: каким образом из числа одноимённых процедур выбрать ту, которая должна быть применена в данном конкретном случае? Всё хорошо, если существует вариант процедуры, типы формальных параметров которого в точности совпадают с типами параметров фактических, применённых в данном вызове. Однако практически во всех языках в употреблении типов существует некоторая степень свободы, предполагающая, что компилятор в определённых ситуациях автоматически выполняет безопасные преобразования типов. Например, в арифметических операциях над вещественным и целым аргументами целый обычно приводится к вещественному типу автоматически, и результат получается вещественным. Предположим, что существует два варианта функции add:

 int   add(int a1, int a2);
 float add(float a1, float a2);

Каким образом компилятор должен обработать выражение y = add(x, i), где x имеет тип float, а i — тип int? Очевидно, что точного совпадения нет. Имеется два варианта: либо y=add_int((int)x,i), либо как y=add_flt(x, (float)i) (здесь именами add_int и add_flt обозначены соответственно, первый и второй варианты функции).

Возникает вопрос: должен ли транслятор разрешать подобное использование перегруженных функций, а если должен, то на каком основании он будет выбирать конкретный используемый вариант? В частности, в приведённом выше примере, должен ли транслятор при выборе учитывать тип переменной y? Нужно отметить, что приведённая ситуация — простейшая, возможны гораздо более запутанные случаи, которые усугубляются тем, что не только встроенные типы могут преобразовываться по правилам языка, но и объявленные программистом классы при наличии у них родственных отношений допускают приведение один к другому. Решений у этой проблемы два:

  • Запретить неточную идентификацию вообще. Требовать, чтобы для каждой конкретной пары типов существовал в точности подходящий вариант перегруженной процедуры или операции. Если такого варианта нет, транслятор должен выдавать ошибку. Программист в этом случае должен применить явное преобразование, чтобы привести фактические параметры к нужному набору типов. Этот подход неудобен в языках типа C++, допускающих достаточную свободу в обращении с типами, поскольку он приводит к существенному различию поведения встроенных и перегруженных операций (к обычным числам арифметические операции можно применять, не задумываясь, а к другим типам — только с явным преобразованием) либо к появлению огромного количества вариантов операций.
  • Установить определённые правила выбора «ближайшего подходящего варианта». Обычно в этом варианте компилятор выбирает те из вариантов, вызовы которых можно получить из исходного только безопасными (не приводящими к потере информации) преобразованиями типов, а если их несколько — может выбирать, исходя из того, какой вариант требует меньше таких преобразований. Если в результате остаётся несколько возможностей, компилятор выдаёт ошибку и требует явного указания варианта от программиста.

Специфические вопросы перегрузки операций

В отличие от процедур и функций, инфиксные операции языков программирования имеют два дополнительных свойства, существенным образом влияющих на их функциональность: приоритет и ассоциативность, наличие которых обусловливается возможностью «цепочной» записи операторов (как понимать a+b*c : как (a+b)*c или как a+(b*c)? Выражение a-b+c — это (a-b)+c или a-(b+c)?).

Встроенные в язык операции всегда имеют наперёд заданные традиционные приоритеты и ассоциативность. Возникает вопрос: какие приоритеты и ассоциативность будут иметь переопределённые версии этих операций или, тем более, новые созданные программистом операции? Есть и другие тонкости, которые могут требовать уточнения. Например, в Си существуют две формы операций увеличения и уменьшения значения ++ и -- — префиксная и постфиксная, поведение которых различается. Как должны вести себя перегруженные версии таких операций?

Различные языки по-разному решают приведённые вопросы. Так, в C++ приоритет и ассоциативность перегруженных версий операций сохраняются такими же, как и у определённых в языке, а описания перегрузки префиксной и постфиксной формы операторов инкремента и декремента используют различные сигнатуры:

Префиксная форма Постфиксная форма
Функция T &operator ++(T &) T operator ++(T &, int)
Функция-член T &T::operator ++() T T::operator ++(int)

Фактически целого параметра у операции нет — он фиктивен, и добавляется только для внесения различия в сигнатуры

Ещё один вопрос: допускать ли возможность перегрузки операций для встроенных и для уже объявленных типов данных? Может ли программист изменить реализацию операции сложения для встроенного целочисленного типа? Или для библиотечного типа «матрица»? Как правило, на первый вопрос отвечают отрицательно. Изменение поведения стандартных операций для встроенных типов — чрезвычайно специфическое действие, реальная необходимость в котором может возникать лишь в редких случаях, тогда как отрицательные последствия бесконтрольного применения такой возможности трудно даже предугадать во всей полноте. Поэтому язык обычно либо запрещает переопределять операции для встроенных типов, либо реализует механизм перегрузки операторов таким образом, чтобы с его помощью стандартные операции просто невозможно было бы перекрыть. Что касается второго вопроса (переопределение операторов, уже описанных для существующих типов), то необходимая функциональность полностью обеспечивается механизмом наследования классов и переопределения методов: если требуется изменить поведение уже имеющегося класса, его нужно унаследовать и переопределить описанные в нём операторы. При этом старый класс останется без изменений, новый получит нужную функциональность, а никаких коллизий не возникнет.

Объявление новых операций

Ещё сложнее обстоит дело с объявлением новых операций. Включить в язык саму возможность такого объявления несложно, но вот реализация его сопряжена со значительными трудностями. Объявление новой операции — это, фактически, создание нового ключевого слова языка программирования, осложнённое тем фактом, что операции в тексте, как правило, могут следовать без разделителей с другими лексемами. При их появлении возникают дополнительные трудности в организации лексического анализатора. Например, если в языке уже есть операции «+» и унарный «-» (изменение знака), то выражение a+-b можно безошибочно трактовать как a + (-b), но если в программе объявляется новая операция +-, тут же возникает неоднозначность, ведь то же выражение можно уже разобрать и как a (+-) b. Разработчик и реализатор языка должен каким-то образом решать подобные проблемы. Варианты, опять-таки, могут быть различными: потребовать, чтобы все новые операции были односимвольными, постулировать, что при любых разночтениях выбирается «самый длинный» вариант операции (то есть до тех пор, пока очередной читаемый транслятором набор символов совпадает с какой-либо операцией, он продолжает считываться), пытаться обнаруживать коллизии при трансляции и выдавать ошибки в спорных случаях… Так или иначе, языки, допускающие объявление новых операций, решают эти проблемы.

Не следует забывать, что для новых операций также стоит вопрос определения ассоциативности и приоритета. Здесь уже нет готового решения в виде стандартной языковой операции, и обычно приходится просто задать эти параметры правилами языка. Например, сделать все новые операции левоассоциативными и дать им один и тот же, фиксированный, приоритет, либо ввести в язык средства задания того и другого.

Перегрузка и полиморфные переменные

Когда перегружаемые операции, функции и процедуры используются в языках со строгой типизацией, где каждая переменная имеет предварительно описанный тип, задача выбора варианта перегруженной операции, используемого в каждом конкретном случае, независимо от её сложности, решается транслятором. Это означает, что для компилируемых языков использование перегрузки операций не приводит к снижению быстродействия — в любом случае, в объектном коде программы присутствует вполне определённая операция или вызов функции. Иначе обстоит дело при возможности использования в языке полиморфных переменных, то есть переменных, которые могут в разные моменты времени содержать значения разных типов.

Поскольку тип значения, к которому будет применяться перегруженная операция, неизвестен на момент трансляции кода, компилятор лишён возможности выбрать нужный вариант заранее. В этом случае он вынужден встраивать в объектный код фрагмент, который непосредственно перед выполнением данной операции определит типы находящихся в аргументах значений и динамически выберет вариант, соответствующий этому набору типов. Причём такое определение нужно производить при каждом исполнении операции, ведь даже тот же самый код, будучи вызван второй раз, вполне может исполняться по-другому.

Таким образом, использование перегрузки операций в сочетании с полиморфными переменными делает неизбежным динамическое определение вызываемого кода.

Критика

Использование перегрузки не всеми специалистами считается благом. Если перегрузка функций и процедур, в общем, не находит серьёзных возражений (отчасти, потому, что не приводит к некоторым типично «операторным» проблемам, отчасти — из-за меньшего соблазна её использования не по назначению), то перегрузка операций, как в принципе, так и в конкретных языковых реализациях, подвергается достаточно жёсткой критике со стороны многих теоретиков и практиков программирования.

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

  • Идентификация. Если в языке приняты жёсткие правила идентификации, то программист вынужден помнить, для каких именно сочетаний типов существуют перегруженные операции и вручную приводить к ним операнды. Если же язык допускает «приблизительную» идентификацию, никогда нельзя поручиться, что в некоей достаточно сложной ситуации будет выполнен именно тот вариант операции, который имел в виду программист.
  • Приоритет и ассоциативность. Если они определены жёстко — это может быть неудобно и не соответствовать предметной области (например, для операций с множествами приоритеты отличаются от арифметических). Если они могут быть заданы программистом — это становится дополнительным источником ошибок (уже хотя бы потому, что разные варианты одной операции оказываются имеющими разные приоритеты, а то и ассоциативность).

Насколько удобство от использования собственных операций способно перевесить неудобства от ухудшения управляемости программы — вопрос, не имеющий однозначного ответа.

Часть критиков высказываются против перегрузки операций, исходя из общих принципов теории разработки программного обеспечения и реальной промышленной практики.

  • Сторонники «пуританского» подхода к построению языков, такие как Вирт или Хоар, выступают против перегрузки операций уже просто потому, что без неё можно легко обойтись. По их мнению, подобные средства лишь усложняют язык и транслятор, не предоставляя соответствующих этому усложнению дополнительных возможностей. По их мнению, сама идея создания ориентированного на задачу расширения языка лишь выглядит привлекательно. В действительности же использование средств расширения языка делает программу понятной только её автору — тому, кто это расширение разработал. Программу становится гораздо труднее понимать и анализировать другим программистам, что затрудняет сопровождение, модификацию и групповую разработку.
  • Отмечается, что сама возможность использования перегрузки часто играет провоцирующую роль: программисты начинают пользоваться ею где только возможно, в результате средство, призванное упростить и упорядочить программу, становится причиной её усложнения и запутывания.
  • Перегруженные операции могут делать не совсем то, что ожидается от них, исходя из их вида. Например, a + b обычно (но не всегда) означает то же самое, что b + a, но «один» + «два» отличается от «два» + «один» в языках, где оператор + перегружен для конкатенации строк.
  • Перегрузка операций делает фрагменты программы более контекстно-зависимыми. Не зная типов участвующих в выражении операндов, невозможно понять, что это выражение делает, если в нём используются перегруженные операции. Например, в программе на C++ оператор << может означать и побитовый сдвиг, и вывод в поток. Выражение a << 1 возвращает результат побитового сдвига значения a на один бит влево, если a — целая переменная, но если a является выходным потоком, то же выражение выведет в этот поток строку «1». В первом случае состояние левого операнда остается неизменным, во втором — нет.

Классификация

Ниже приведена классификация некоторых языков программирования по тому, позволяют ли они перегрузку операторов, и ограничены ли операторы предопределённым набором:

Множество
операторов
Перегрузки
нет
Перегрузка
есть
Только
предопределённые

Си
Java
JavaScript
Objective-C
Паскаль
PHP
ActionScript
Go

Ада
C++
C#
D
Object Pascal
Perl
Python
Руби
VB.NET
Delphi

Возможно
вводить новые

ML
Pico
Лисп

Алгол 68
Фортран
Haskell
PostgreSQL
Пролог
Perl 6
Seed7
Smalltalk

Напишите отзыв о статье "Перегрузка операторов"

Примечания

См. также


К:Википедия:Статьи без источников (тип: не указан)

Отрывок, характеризующий Перегрузка операторов



3 го марта во всех комнатах Английского клуба стоял стон разговаривающих голосов и, как пчелы на весеннем пролете, сновали взад и вперед, сидели, стояли, сходились и расходились, в мундирах, фраках и еще кое кто в пудре и кафтанах, члены и гости клуба. Пудренные, в чулках и башмаках ливрейные лакеи стояли у каждой двери и напряженно старались уловить каждое движение гостей и членов клуба, чтобы предложить свои услуги. Большинство присутствовавших были старые, почтенные люди с широкими, самоуверенными лицами, толстыми пальцами, твердыми движениями и голосами. Этого рода гости и члены сидели по известным, привычным местам и сходились в известных, привычных кружках. Малая часть присутствовавших состояла из случайных гостей – преимущественно молодежи, в числе которой были Денисов, Ростов и Долохов, который был опять семеновским офицером. На лицах молодежи, особенно военной, было выражение того чувства презрительной почтительности к старикам, которое как будто говорит старому поколению: уважать и почитать вас мы готовы, но помните, что всё таки за нами будущность.
Несвицкий был тут же, как старый член клуба. Пьер, по приказанию жены отпустивший волоса, снявший очки и одетый по модному, но с грустным и унылым видом, ходил по залам. Его, как и везде, окружала атмосфера людей, преклонявшихся перед его богатством, и он с привычкой царствования и рассеянной презрительностью обращался с ними.
По годам он бы должен был быть с молодыми, по богатству и связям он был членом кружков старых, почтенных гостей, и потому он переходил от одного кружка к другому.
Старики из самых значительных составляли центр кружков, к которым почтительно приближались даже незнакомые, чтобы послушать известных людей. Большие кружки составлялись около графа Ростопчина, Валуева и Нарышкина. Ростопчин рассказывал про то, как русские были смяты бежавшими австрийцами и должны были штыком прокладывать себе дорогу сквозь беглецов.
Валуев конфиденциально рассказывал, что Уваров был прислан из Петербурга, для того чтобы узнать мнение москвичей об Аустерлице.
В третьем кружке Нарышкин говорил о заседании австрийского военного совета, в котором Суворов закричал петухом в ответ на глупость австрийских генералов. Шиншин, стоявший тут же, хотел пошутить, сказав, что Кутузов, видно, и этому нетрудному искусству – кричать по петушиному – не мог выучиться у Суворова; но старички строго посмотрели на шутника, давая ему тем чувствовать, что здесь и в нынешний день так неприлично было говорить про Кутузова.
Граф Илья Андреич Ростов, озабоченно, торопливо похаживал в своих мягких сапогах из столовой в гостиную, поспешно и совершенно одинаково здороваясь с важными и неважными лицами, которых он всех знал, и изредка отыскивая глазами своего стройного молодца сына, радостно останавливал на нем свой взгляд и подмигивал ему. Молодой Ростов стоял у окна с Долоховым, с которым он недавно познакомился, и знакомством которого он дорожил. Старый граф подошел к ним и пожал руку Долохову.
– Ко мне милости прошу, вот ты с моим молодцом знаком… вместе там, вместе геройствовали… A! Василий Игнатьич… здорово старый, – обратился он к проходившему старичку, но не успел еще договорить приветствия, как всё зашевелилось, и прибежавший лакей, с испуганным лицом, доложил: пожаловали!
Раздались звонки; старшины бросились вперед; разбросанные в разных комнатах гости, как встряхнутая рожь на лопате, столпились в одну кучу и остановились в большой гостиной у дверей залы.
В дверях передней показался Багратион, без шляпы и шпаги, которые он, по клубному обычаю, оставил у швейцара. Он был не в смушковом картузе с нагайкой через плечо, как видел его Ростов в ночь накануне Аустерлицкого сражения, а в новом узком мундире с русскими и иностранными орденами и с георгиевской звездой на левой стороне груди. Он видимо сейчас, перед обедом, подстриг волосы и бакенбарды, что невыгодно изменяло его физиономию. На лице его было что то наивно праздничное, дававшее, в соединении с его твердыми, мужественными чертами, даже несколько комическое выражение его лицу. Беклешов и Федор Петрович Уваров, приехавшие с ним вместе, остановились в дверях, желая, чтобы он, как главный гость, прошел вперед их. Багратион смешался, не желая воспользоваться их учтивостью; произошла остановка в дверях, и наконец Багратион всё таки прошел вперед. Он шел, не зная куда девать руки, застенчиво и неловко, по паркету приемной: ему привычнее и легче было ходить под пулями по вспаханному полю, как он шел перед Курским полком в Шенграбене. Старшины встретили его у первой двери, сказав ему несколько слов о радости видеть столь дорогого гостя, и недождавшись его ответа, как бы завладев им, окружили его и повели в гостиную. В дверях гостиной не было возможности пройти от столпившихся членов и гостей, давивших друг друга и через плечи друг друга старавшихся, как редкого зверя, рассмотреть Багратиона. Граф Илья Андреич, энергичнее всех, смеясь и приговаривая: – пусти, mon cher, пусти, пусти, – протолкал толпу, провел гостей в гостиную и посадил на средний диван. Тузы, почетнейшие члены клуба, обступили вновь прибывших. Граф Илья Андреич, проталкиваясь опять через толпу, вышел из гостиной и с другим старшиной через минуту явился, неся большое серебряное блюдо, которое он поднес князю Багратиону. На блюде лежали сочиненные и напечатанные в честь героя стихи. Багратион, увидав блюдо, испуганно оглянулся, как бы отыскивая помощи. Но во всех глазах было требование того, чтобы он покорился. Чувствуя себя в их власти, Багратион решительно, обеими руками, взял блюдо и сердито, укоризненно посмотрел на графа, подносившего его. Кто то услужливо вынул из рук Багратиона блюдо (а то бы он, казалось, намерен был держать его так до вечера и так итти к столу) и обратил его внимание на стихи. «Ну и прочту», как будто сказал Багратион и устремив усталые глаза на бумагу, стал читать с сосредоточенным и серьезным видом. Сам сочинитель взял стихи и стал читать. Князь Багратион склонил голову и слушал.
«Славь Александра век
И охраняй нам Тита на престоле,
Будь купно страшный вождь и добрый человек,
Рифей в отечестве а Цесарь в бранном поле.
Да счастливый Наполеон,
Познав чрез опыты, каков Багратион,
Не смеет утруждать Алкидов русских боле…»
Но еще он не кончил стихов, как громогласный дворецкий провозгласил: «Кушанье готово!» Дверь отворилась, загремел из столовой польский: «Гром победы раздавайся, веселися храбрый росс», и граф Илья Андреич, сердито посмотрев на автора, продолжавшего читать стихи, раскланялся перед Багратионом. Все встали, чувствуя, что обед был важнее стихов, и опять Багратион впереди всех пошел к столу. На первом месте, между двух Александров – Беклешова и Нарышкина, что тоже имело значение по отношению к имени государя, посадили Багратиона: 300 человек разместились в столовой по чинам и важности, кто поважнее, поближе к чествуемому гостю: так же естественно, как вода разливается туда глубже, где местность ниже.
Перед самым обедом граф Илья Андреич представил князю своего сына. Багратион, узнав его, сказал несколько нескладных, неловких слов, как и все слова, которые он говорил в этот день. Граф Илья Андреич радостно и гордо оглядывал всех в то время, как Багратион говорил с его сыном.
Николай Ростов с Денисовым и новым знакомцем Долоховым сели вместе почти на середине стола. Напротив них сел Пьер рядом с князем Несвицким. Граф Илья Андреич сидел напротив Багратиона с другими старшинами и угащивал князя, олицетворяя в себе московское радушие.
Труды его не пропали даром. Обеды его, постный и скоромный, были великолепны, но совершенно спокоен он всё таки не мог быть до конца обеда. Он подмигивал буфетчику, шопотом приказывал лакеям, и не без волнения ожидал каждого, знакомого ему блюда. Всё было прекрасно. На втором блюде, вместе с исполинской стерлядью (увидав которую, Илья Андреич покраснел от радости и застенчивости), уже лакеи стали хлопать пробками и наливать шампанское. После рыбы, которая произвела некоторое впечатление, граф Илья Андреич переглянулся с другими старшинами. – «Много тостов будет, пора начинать!» – шепнул он и взяв бокал в руки – встал. Все замолкли и ожидали, что он скажет.
– Здоровье государя императора! – крикнул он, и в ту же минуту добрые глаза его увлажились слезами радости и восторга. В ту же минуту заиграли: «Гром победы раздавайся».Все встали с своих мест и закричали ура! и Багратион закричал ура! тем же голосом, каким он кричал на Шенграбенском поле. Восторженный голос молодого Ростова был слышен из за всех 300 голосов. Он чуть не плакал. – Здоровье государя императора, – кричал он, – ура! – Выпив залпом свой бокал, он бросил его на пол. Многие последовали его примеру. И долго продолжались громкие крики. Когда замолкли голоса, лакеи подобрали разбитую посуду, и все стали усаживаться, и улыбаясь своему крику переговариваться. Граф Илья Андреич поднялся опять, взглянул на записочку, лежавшую подле его тарелки и провозгласил тост за здоровье героя нашей последней кампании, князя Петра Ивановича Багратиона и опять голубые глаза графа увлажились слезами. Ура! опять закричали голоса 300 гостей, и вместо музыки послышались певчие, певшие кантату сочинения Павла Ивановича Кутузова.
«Тщетны россам все препоны,
Храбрость есть побед залог,
Есть у нас Багратионы,
Будут все враги у ног» и т.д.
Только что кончили певчие, как последовали новые и новые тосты, при которых всё больше и больше расчувствовался граф Илья Андреич, и еще больше билось посуды, и еще больше кричалось. Пили за здоровье Беклешова, Нарышкина, Уварова, Долгорукова, Апраксина, Валуева, за здоровье старшин, за здоровье распорядителя, за здоровье всех членов клуба, за здоровье всех гостей клуба и наконец отдельно за здоровье учредителя обеда графа Ильи Андреича. При этом тосте граф вынул платок и, закрыв им лицо, совершенно расплакался.


Пьер сидел против Долохова и Николая Ростова. Он много и жадно ел и много пил, как и всегда. Но те, которые его знали коротко, видели, что в нем произошла в нынешний день какая то большая перемена. Он молчал всё время обеда и, щурясь и морщась, глядел кругом себя или остановив глаза, с видом совершенной рассеянности, потирал пальцем переносицу. Лицо его было уныло и мрачно. Он, казалось, не видел и не слышал ничего, происходящего вокруг него, и думал о чем то одном, тяжелом и неразрешенном.
Этот неразрешенный, мучивший его вопрос, были намеки княжны в Москве на близость Долохова к его жене и в нынешнее утро полученное им анонимное письмо, в котором было сказано с той подлой шутливостью, которая свойственна всем анонимным письмам, что он плохо видит сквозь свои очки, и что связь его жены с Долоховым есть тайна только для одного него. Пьер решительно не поверил ни намекам княжны, ни письму, но ему страшно было теперь смотреть на Долохова, сидевшего перед ним. Всякий раз, как нечаянно взгляд его встречался с прекрасными, наглыми глазами Долохова, Пьер чувствовал, как что то ужасное, безобразное поднималось в его душе, и он скорее отворачивался. Невольно вспоминая всё прошедшее своей жены и ее отношения с Долоховым, Пьер видел ясно, что то, что сказано было в письме, могло быть правда, могло по крайней мере казаться правдой, ежели бы это касалось не его жены. Пьер вспоминал невольно, как Долохов, которому было возвращено всё после кампании, вернулся в Петербург и приехал к нему. Пользуясь своими кутежными отношениями дружбы с Пьером, Долохов прямо приехал к нему в дом, и Пьер поместил его и дал ему взаймы денег. Пьер вспоминал, как Элен улыбаясь выражала свое неудовольствие за то, что Долохов живет в их доме, и как Долохов цинически хвалил ему красоту его жены, и как он с того времени до приезда в Москву ни на минуту не разлучался с ними.
«Да, он очень красив, думал Пьер, я знаю его. Для него была бы особенная прелесть в том, чтобы осрамить мое имя и посмеяться надо мной, именно потому, что я хлопотал за него и призрел его, помог ему. Я знаю, я понимаю, какую соль это в его глазах должно бы придавать его обману, ежели бы это была правда. Да, ежели бы это была правда; но я не верю, не имею права и не могу верить». Он вспоминал то выражение, которое принимало лицо Долохова, когда на него находили минуты жестокости, как те, в которые он связывал квартального с медведем и пускал его на воду, или когда он вызывал без всякой причины на дуэль человека, или убивал из пистолета лошадь ямщика. Это выражение часто было на лице Долохова, когда он смотрел на него. «Да, он бретёр, думал Пьер, ему ничего не значит убить человека, ему должно казаться, что все боятся его, ему должно быть приятно это. Он должен думать, что и я боюсь его. И действительно я боюсь его», думал Пьер, и опять при этих мыслях он чувствовал, как что то страшное и безобразное поднималось в его душе. Долохов, Денисов и Ростов сидели теперь против Пьера и казались очень веселы. Ростов весело переговаривался с своими двумя приятелями, из которых один был лихой гусар, другой известный бретёр и повеса, и изредка насмешливо поглядывал на Пьера, который на этом обеде поражал своей сосредоточенной, рассеянной, массивной фигурой. Ростов недоброжелательно смотрел на Пьера, во первых, потому, что Пьер в его гусарских глазах был штатский богач, муж красавицы, вообще баба; во вторых, потому, что Пьер в сосредоточенности и рассеянности своего настроения не узнал Ростова и не ответил на его поклон. Когда стали пить здоровье государя, Пьер задумавшись не встал и не взял бокала.
– Что ж вы? – закричал ему Ростов, восторженно озлобленными глазами глядя на него. – Разве вы не слышите; здоровье государя императора! – Пьер, вздохнув, покорно встал, выпил свой бокал и, дождавшись, когда все сели, с своей доброй улыбкой обратился к Ростову.
– А я вас и не узнал, – сказал он. – Но Ростову было не до этого, он кричал ура!
– Что ж ты не возобновишь знакомство, – сказал Долохов Ростову.
– Бог с ним, дурак, – сказал Ростов.
– Надо лелеять мужей хорошеньких женщин, – сказал Денисов. Пьер не слышал, что они говорили, но знал, что говорят про него. Он покраснел и отвернулся.
– Ну, теперь за здоровье красивых женщин, – сказал Долохов, и с серьезным выражением, но с улыбающимся в углах ртом, с бокалом обратился к Пьеру.
– За здоровье красивых женщин, Петруша, и их любовников, – сказал он.
Пьер, опустив глаза, пил из своего бокала, не глядя на Долохова и не отвечая ему. Лакей, раздававший кантату Кутузова, положил листок Пьеру, как более почетному гостю. Он хотел взять его, но Долохов перегнулся, выхватил листок из его руки и стал читать. Пьер взглянул на Долохова, зрачки его опустились: что то страшное и безобразное, мутившее его во всё время обеда, поднялось и овладело им. Он нагнулся всем тучным телом через стол: – Не смейте брать! – крикнул он.
Услыхав этот крик и увидав, к кому он относился, Несвицкий и сосед с правой стороны испуганно и поспешно обратились к Безухову.
– Полноте, полно, что вы? – шептали испуганные голоса. Долохов посмотрел на Пьера светлыми, веселыми, жестокими глазами, с той же улыбкой, как будто он говорил: «А вот это я люблю». – Не дам, – проговорил он отчетливо.
Бледный, с трясущейся губой, Пьер рванул лист. – Вы… вы… негодяй!.. я вас вызываю, – проговорил он, и двинув стул, встал из за стола. В ту самую секунду, как Пьер сделал это и произнес эти слова, он почувствовал, что вопрос о виновности его жены, мучивший его эти последние сутки, был окончательно и несомненно решен утвердительно. Он ненавидел ее и навсегда был разорван с нею. Несмотря на просьбы Денисова, чтобы Ростов не вмешивался в это дело, Ростов согласился быть секундантом Долохова, и после стола переговорил с Несвицким, секундантом Безухова, об условиях дуэли. Пьер уехал домой, а Ростов с Долоховым и Денисовым до позднего вечера просидели в клубе, слушая цыган и песенников.
– Так до завтра, в Сокольниках, – сказал Долохов, прощаясь с Ростовым на крыльце клуба.
– И ты спокоен? – спросил Ростов…
Долохов остановился. – Вот видишь ли, я тебе в двух словах открою всю тайну дуэли. Ежели ты идешь на дуэль и пишешь завещания да нежные письма родителям, ежели ты думаешь о том, что тебя могут убить, ты – дурак и наверно пропал; а ты иди с твердым намерением его убить, как можно поскорее и повернее, тогда всё исправно. Как мне говаривал наш костромской медвежатник: медведя то, говорит, как не бояться? да как увидишь его, и страх прошел, как бы только не ушел! Ну так то и я. A demain, mon cher! [До завтра, мой милый!]
На другой день, в 8 часов утра, Пьер с Несвицким приехали в Сокольницкий лес и нашли там уже Долохова, Денисова и Ростова. Пьер имел вид человека, занятого какими то соображениями, вовсе не касающимися до предстоящего дела. Осунувшееся лицо его было желто. Он видимо не спал ту ночь. Он рассеянно оглядывался вокруг себя и морщился, как будто от яркого солнца. Два соображения исключительно занимали его: виновность его жены, в которой после бессонной ночи уже не оставалось ни малейшего сомнения, и невинность Долохова, не имевшего никакой причины беречь честь чужого для него человека. «Может быть, я бы то же самое сделал бы на его месте, думал Пьер. Даже наверное я бы сделал то же самое; к чему же эта дуэль, это убийство? Или я убью его, или он попадет мне в голову, в локоть, в коленку. Уйти отсюда, бежать, зарыться куда нибудь», приходило ему в голову. Но именно в те минуты, когда ему приходили такие мысли. он с особенно спокойным и рассеянным видом, внушавшим уважение смотревшим на него, спрашивал: «Скоро ли, и готово ли?»
Когда всё было готово, сабли воткнуты в снег, означая барьер, до которого следовало сходиться, и пистолеты заряжены, Несвицкий подошел к Пьеру.
– Я бы не исполнил своей обязанности, граф, – сказал он робким голосом, – и не оправдал бы того доверия и чести, которые вы мне сделали, выбрав меня своим секундантом, ежели бы я в эту важную минуту, очень важную минуту, не сказал вам всю правду. Я полагаю, что дело это не имеет достаточно причин, и что не стоит того, чтобы за него проливать кровь… Вы были неправы, не совсем правы, вы погорячились…
– Ах да, ужасно глупо… – сказал Пьер.
– Так позвольте мне передать ваше сожаление, и я уверен, что наши противники согласятся принять ваше извинение, – сказал Несвицкий (так же как и другие участники дела и как и все в подобных делах, не веря еще, чтобы дело дошло до действительной дуэли). – Вы знаете, граф, гораздо благороднее сознать свою ошибку, чем довести дело до непоправимого. Обиды ни с одной стороны не было. Позвольте мне переговорить…
– Нет, об чем же говорить! – сказал Пьер, – всё равно… Так готово? – прибавил он. – Вы мне скажите только, как куда ходить, и стрелять куда? – сказал он, неестественно кротко улыбаясь. – Он взял в руки пистолет, стал расспрашивать о способе спуска, так как он до сих пор не держал в руках пистолета, в чем он не хотел сознаваться. – Ах да, вот так, я знаю, я забыл только, – говорил он.
– Никаких извинений, ничего решительно, – говорил Долохов Денисову, который с своей стороны тоже сделал попытку примирения, и тоже подошел к назначенному месту.
Место для поединка было выбрано шагах в 80 ти от дороги, на которой остались сани, на небольшой полянке соснового леса, покрытой истаявшим от стоявших последние дни оттепелей снегом. Противники стояли шагах в 40 ка друг от друга, у краев поляны. Секунданты, размеряя шаги, проложили, отпечатавшиеся по мокрому, глубокому снегу, следы от того места, где они стояли, до сабель Несвицкого и Денисова, означавших барьер и воткнутых в 10 ти шагах друг от друга. Оттепель и туман продолжались; за 40 шагов ничего не было видно. Минуты три всё было уже готово, и всё таки медлили начинать, все молчали.


– Ну, начинать! – сказал Долохов.
– Что же, – сказал Пьер, всё так же улыбаясь. – Становилось страшно. Очевидно было, что дело, начавшееся так легко, уже ничем не могло быть предотвращено, что оно шло само собою, уже независимо от воли людей, и должно было совершиться. Денисов первый вышел вперед до барьера и провозгласил:
– Так как п'отивники отказались от п'ими'ения, то не угодно ли начинать: взять пистолеты и по слову т'и начинать сходиться.
– Г…'аз! Два! Т'и!… – сердито прокричал Денисов и отошел в сторону. Оба пошли по протоптанным дорожкам всё ближе и ближе, в тумане узнавая друг друга. Противники имели право, сходясь до барьера, стрелять, когда кто захочет. Долохов шел медленно, не поднимая пистолета, вглядываясь своими светлыми, блестящими, голубыми глазами в лицо своего противника. Рот его, как и всегда, имел на себе подобие улыбки.
– Так когда хочу – могу стрелять! – сказал Пьер, при слове три быстрыми шагами пошел вперед, сбиваясь с протоптанной дорожки и шагая по цельному снегу. Пьер держал пистолет, вытянув вперед правую руку, видимо боясь как бы из этого пистолета не убить самого себя. Левую руку он старательно отставлял назад, потому что ему хотелось поддержать ею правую руку, а он знал, что этого нельзя было. Пройдя шагов шесть и сбившись с дорожки в снег, Пьер оглянулся под ноги, опять быстро взглянул на Долохова, и потянув пальцем, как его учили, выстрелил. Никак не ожидая такого сильного звука, Пьер вздрогнул от своего выстрела, потом улыбнулся сам своему впечатлению и остановился. Дым, особенно густой от тумана, помешал ему видеть в первое мгновение; но другого выстрела, которого он ждал, не последовало. Только слышны были торопливые шаги Долохова, и из за дыма показалась его фигура. Одной рукой он держался за левый бок, другой сжимал опущенный пистолет. Лицо его было бледно. Ростов подбежал и что то сказал ему.
– Не…е…т, – проговорил сквозь зубы Долохов, – нет, не кончено, – и сделав еще несколько падающих, ковыляющих шагов до самой сабли, упал на снег подле нее. Левая рука его была в крови, он обтер ее о сюртук и оперся ею. Лицо его было бледно, нахмуренно и дрожало.
– Пожалу… – начал Долохов, но не мог сразу выговорить… – пожалуйте, договорил он с усилием. Пьер, едва удерживая рыдания, побежал к Долохову, и хотел уже перейти пространство, отделяющее барьеры, как Долохов крикнул: – к барьеру! – и Пьер, поняв в чем дело, остановился у своей сабли. Только 10 шагов разделяло их. Долохов опустился головой к снегу, жадно укусил снег, опять поднял голову, поправился, подобрал ноги и сел, отыскивая прочный центр тяжести. Он глотал холодный снег и сосал его; губы его дрожали, но всё улыбаясь; глаза блестели усилием и злобой последних собранных сил. Он поднял пистолет и стал целиться.
– Боком, закройтесь пистолетом, – проговорил Несвицкий.
– 3ак'ойтесь! – не выдержав, крикнул даже Денисов своему противнику.
Пьер с кроткой улыбкой сожаления и раскаяния, беспомощно расставив ноги и руки, прямо своей широкой грудью стоял перед Долоховым и грустно смотрел на него. Денисов, Ростов и Несвицкий зажмурились. В одно и то же время они услыхали выстрел и злой крик Долохова.
– Мимо! – крикнул Долохов и бессильно лег на снег лицом книзу. Пьер схватился за голову и, повернувшись назад, пошел в лес, шагая целиком по снегу и вслух приговаривая непонятные слова:
– Глупо… глупо! Смерть… ложь… – твердил он морщась. Несвицкий остановил его и повез домой.
Ростов с Денисовым повезли раненого Долохова.
Долохов, молча, с закрытыми глазами, лежал в санях и ни слова не отвечал на вопросы, которые ему делали; но, въехав в Москву, он вдруг очнулся и, с трудом приподняв голову, взял за руку сидевшего подле себя Ростова. Ростова поразило совершенно изменившееся и неожиданно восторженно нежное выражение лица Долохова.
– Ну, что? как ты чувствуешь себя? – спросил Ростов.
– Скверно! но не в том дело. Друг мой, – сказал Долохов прерывающимся голосом, – где мы? Мы в Москве, я знаю. Я ничего, но я убил ее, убил… Она не перенесет этого. Она не перенесет…
– Кто? – спросил Ростов.
– Мать моя. Моя мать, мой ангел, мой обожаемый ангел, мать, – и Долохов заплакал, сжимая руку Ростова. Когда он несколько успокоился, он объяснил Ростову, что живет с матерью, что ежели мать увидит его умирающим, она не перенесет этого. Он умолял Ростова ехать к ней и приготовить ее.
Ростов поехал вперед исполнять поручение, и к великому удивлению своему узнал, что Долохов, этот буян, бретёр Долохов жил в Москве с старушкой матерью и горбатой сестрой, и был самый нежный сын и брат.


Пьер в последнее время редко виделся с женою с глазу на глаз. И в Петербурге, и в Москве дом их постоянно бывал полон гостями. В следующую ночь после дуэли, он, как и часто делал, не пошел в спальню, а остался в своем огромном, отцовском кабинете, в том самом, в котором умер граф Безухий.
Он прилег на диван и хотел заснуть, для того чтобы забыть всё, что было с ним, но он не мог этого сделать. Такая буря чувств, мыслей, воспоминаний вдруг поднялась в его душе, что он не только не мог спать, но не мог сидеть на месте и должен был вскочить с дивана и быстрыми шагами ходить по комнате. То ему представлялась она в первое время после женитьбы, с открытыми плечами и усталым, страстным взглядом, и тотчас же рядом с нею представлялось красивое, наглое и твердо насмешливое лицо Долохова, каким оно было на обеде, и то же лицо Долохова, бледное, дрожащее и страдающее, каким оно было, когда он повернулся и упал на снег.
«Что ж было? – спрашивал он сам себя. – Я убил любовника , да, убил любовника своей жены. Да, это было. Отчего? Как я дошел до этого? – Оттого, что ты женился на ней, – отвечал внутренний голос.
«Но в чем же я виноват? – спрашивал он. – В том, что ты женился не любя ее, в том, что ты обманул и себя и ее, – и ему живо представилась та минута после ужина у князя Василья, когда он сказал эти невыходившие из него слова: „Je vous aime“. [Я вас люблю.] Всё от этого! Я и тогда чувствовал, думал он, я чувствовал тогда, что это было не то, что я не имел на это права. Так и вышло». Он вспомнил медовый месяц, и покраснел при этом воспоминании. Особенно живо, оскорбительно и постыдно было для него воспоминание о том, как однажды, вскоре после своей женитьбы, он в 12 м часу дня, в шелковом халате пришел из спальни в кабинет, и в кабинете застал главного управляющего, который почтительно поклонился, поглядел на лицо Пьера, на его халат и слегка улыбнулся, как бы выражая этой улыбкой почтительное сочувствие счастию своего принципала.
«А сколько раз я гордился ею, гордился ее величавой красотой, ее светским тактом, думал он; гордился тем своим домом, в котором она принимала весь Петербург, гордился ее неприступностью и красотой. Так вот чем я гордился?! Я тогда думал, что не понимаю ее. Как часто, вдумываясь в ее характер, я говорил себе, что я виноват, что не понимаю ее, не понимаю этого всегдашнего спокойствия, удовлетворенности и отсутствия всяких пристрастий и желаний, а вся разгадка была в том страшном слове, что она развратная женщина: сказал себе это страшное слово, и всё стало ясно!
«Анатоль ездил к ней занимать у нее денег и целовал ее в голые плечи. Она не давала ему денег, но позволяла целовать себя. Отец, шутя, возбуждал ее ревность; она с спокойной улыбкой говорила, что она не так глупа, чтобы быть ревнивой: пусть делает, что хочет, говорила она про меня. Я спросил у нее однажды, не чувствует ли она признаков беременности. Она засмеялась презрительно и сказала, что она не дура, чтобы желать иметь детей, и что от меня детей у нее не будет».
Потом он вспомнил грубость, ясность ее мыслей и вульгарность выражений, свойственных ей, несмотря на ее воспитание в высшем аристократическом кругу. «Я не какая нибудь дура… поди сам попробуй… allez vous promener», [убирайся,] говорила она. Часто, глядя на ее успех в глазах старых и молодых мужчин и женщин, Пьер не мог понять, отчего он не любил ее. Да я никогда не любил ее, говорил себе Пьер; я знал, что она развратная женщина, повторял он сам себе, но не смел признаться в этом.