Идиомы и стили С++ - [9]

Шрифт
Интервал

, но без передачи управления деструктору. До того это оставалось на совести разработчика компилятора, и довольно часто выделенная память могла застрять, и больше не вернуться в систему. Кроме того, конструктор ничего не возвращает. Только что проверить на NULL. Ну еще конечно исключения, да… но все так сложно, елы… Короче, не след бы нам смешивать разные вещи, даже если это совсем не суп и не мухи, а совсем выделение памяти и инициализация.

В какой-то степени по этой причине, но так же и по некоторым другим соображениям, в C++ применяется прием двухэтапной инициализации. На мой взгляд это не есть идиома, а довольно простой прием, но есть весьма важная причина, почему я должен о нем рассказать: его не используют.

Особенно часто этим грешат начинающие Delphi-щики, и VB-шники: слишком велик соблазн щелкнуть по методу формы OnCreate, OnShow (Form_Create, Form_Show), и прописывать инициализации там, или, что еще ужаснее, залезть из одной формы в другую и там изменять значения переменных. Не делайте этого! Граждане дельфинщики! Форма - такой же класс, как и все остальные. Не лишайте ее законного конструктора, дайте ей заслуженную инициализацию! Не чмарите свой инструмент, и он воздаст Вам сторицей!

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

>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- есть постфиксная и префиксная форма? У постфиксной в скобках фиктивный параметр стоит:


Еще от автора Альберт Махмутов
Человек! Чего же ты хочешь, скажи!

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


И всё-таки люди созданы для счастья

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


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.