Выбрать главу

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

class CClass {

private:

// Чудовищно сложные структуры, ресурсы,

// мьютексы-шмутексы, все сплошь критическое,

// пачками выбрасывающие исключения.

public:

 CClass (); // Конструктор, которому на Ваши проблемы плевать.

 // Вот тут мы и замучаем свои ресурсы.

 int InitInstance (‹список аргументов›) throw (‹список исключений›);

};

// Где-то в коде:

CClass* cc = new CClass;

if (cc != NULL) {

 try {

  int ret_code = cc-›InitInstance();

  // Тут еще и код возврата можно обработать, если не лень,

  // но только если инициализация прошла успешно.

  // если выскочило исключение, сюда мы не попадем.

 }  catch (…) {

  // да еще и исключения обработать.

 }

};

Все…

Шаг 13 - Перегрузка operator+.

Оператор operator-› мы уже перегружали. Результаты получились просто феерические. Давайте замучаем еще кого-нибудь и посмотрим, что получится? Давайте. Первейшим кандидатом на переопределение является оператор operator+,потому что в жизни (помимо С++) он выражает замечательное действие - добавление объекта к другому объекту. Конечно, Вы можете придать ему и другой смысл, но это будет как раз тот случай, где "если хочешь быть здоров - ешь один, и в темноте"…

Проиллюстрирую сказанное следующим примером: Вы пишете интерфейс на Паскале, и для добавления подменю или пункта меню используете функции AddSubMenu() и AddMenuItem(). Тогда для создания меню Вы прописываете замечательно изящное выражение с толстым-толстым слоем скобок в конце:

Menu.AddSubMenu(Submenu1,

 AddMenuItem(MenuItem1,

  AddMenuItem(MenuItem2,

   AddMenuItem(MenuItem3,

    AddSubMenu (SubMenu2, nil)

))));

А вот что получается на С++:

CMenu Menu = Menu() + SubMenu1() + MenuItem1() + MenuItem2() + MenuItem3() + SubMenu2();

Прошу извинить за отсутствие подробностей - на память не помню; но и так очевидно, что выражение в 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- есть постфиксная и префиксная форма? У постфиксной в скобках фиктивный параметр стоит: