Прошу извинить за отсутствие подробностей - на память не помню; но и так очевидно, что выражение в C++
выглядит просто красивее. Это одно из главных достоинств С++ - язык позволяет выражать наши намерения предельно ясно.Есть еще один смысл, который можно придать оператору operator+
, если "от перестановки мест слагаемых сумма не изменяется". Примером, кроме сложения и умножения чисел, может быть соударение объектов: столкнулся ли Титаник с айсбергом, айсберг ли столкнулся с Титаником, результат один - вызов деструктора для Титаника. (Я не утверждаю, что это НУЖНО делать так, это только можно!)Немного ниже мы используем это для уменьшения количества диспетчерских функций при двойной диспетчеризации из Шага 4, а сейчас быстренько напишем код с переопределением operator+
для любимого стека всех времен и народов. Понятно, на месте стека может оказаться каждый, те же меню, опять же.class CArray {
private:
int a[100];
int iTop;
public:
CArray ():iTop(0) {}
CArray (const CArray& _ca) {
iTop = _ca.iTop;
for (int i=0; i++; i ‹100) a[i]= _ca.a[i];
}
CArray& operator=(const CArray& _ca) {
if (this==&_ca) return *this;
for (int i=0; i++; i ‹100) a[i]= _ca.a[i];
iTop = _ca.iTop;
return *this;
};
// С этим еще можно согласиться
CArray& operator+ (int _i) { a[iTop]=_i; iTop++; return *this; }
// Это пример дурного стиля
int operator-- () { iTop--; return a[iTop+1]; }
};
Для такого тестового стека определим оператор operator+
(и operator+=) для вставки объектов, а оператор operator- для выталкивания и удаления. Вы кстати знаете, что для operator++ и operator- есть постфиксная и префиксная форма? У постфиксной в скобках фиктивный параметр стоит:const type& operator++(); // Префиксная
type operator++(int); // Постфиксная.
Я позволяю себе пропустить кучу деталей (например то, что вставка сто первого элемента слегка повесит программу), но обращаю внимание: определение конструктора копии и оператора присваивания - суровая необходимость. Не сделаете - пожалеете; почему - говорил в Шаге 5.
Еще нюанс: определение operator--
для выбора из стека есть, мягко говоря, спорный стиль; некоторые считают даже перегрузку operator‹‹ и operator›› для работы с потоками крайне неудачной идеей. Так что это я только для примера…Пример имеет семантику значений, а не семантику указателей. Это в общем значит, что в коллекции хранятся примитивные значения, а не указатели или ссылки.
Кстати, запомните эти умные слова, их круто вставить в разговор с приятелями или (еще лучше) с начальством, чтобы запутать его в камом-нибудь вопросе или снять с себя ответственность за неверно принятые решения. Если особенно ответственность лежит так же и на начальстве (оно же и аналитик), то объяснение "так и так, тут семантика значений" будет воспринято лучше, чем "вы все - тупицы и недоучки, неспособные к проектированию и анализу". Вообще, теоретические познания бывают как нельзя более кстати при поиске виновных, чем при повседневной работе. Вы можете колбасить программы на фокспре или хотя и на C++
c MTS и DCOM, но если Ваша программа повесит сервер бухгалтерии за день до зарплаты или годового отчета… то никакие познания не будут лишними, чтобы свалить вину на сисадминов!Перед тем, как закончить Шаг, вернусь к стилю: если я для примера безграмотно переопределил операторы арифметики, это не значит, что то же самое должны делать Вы. Компилятор позволяет определить любое возвращаемое значение и запрограммировать любые действия, но понемногу изменяя семантику, в конце концов Вы выроете себе яму и попадете в нее. Есть еще одна опасность - поведение, приоритет и правила взаимодействия операторов ЗАДАНЫ раз и навсегда, а компилятор не может оценить Ваш интеллектуальный уровень, и действует так, как ДОЛЖЕН, а не так, как Вы ДУМАЕТЕ, что он должен. Из-за этого НИКОГДА не переопределяйте операторы operator&&()
и operator||(), и всегда правильно задавайте возвращаемое значение операторов.Шаг 14 - Двойная диспетчеризация. Продолжение.