Чтение онлайн

на главную - закладки

Жанры

Идиомы и стили С++

Makhmutov Albert

Шрифт:

Вернемся опять к статической функции. Статическую функцию класса можно вызвать двумя способами - указав либо имя класса, либо через экземпляр класса.

CClass* cc1 = CClass::factory(void);

CClass* cc2 = cc1-›factory(void); // Вызов производящей функции

// Не знаю, откуда мы его берем, но это стековый экземпляр

CClass cc3;

CClass* cc4 = cc3.factory(void); // Еще один вызов производящей функции

Тут-то и делается самый прикол. Мы делаем

виртуальный конструктор: виртуальную производящую функцию:

CClass {

public:

 // Теперь виртуальная, а не статическая.

 virtual CClass* factory (void);

 // Конструктор делаем для простоты открытым,

 // поскольку все-таки нам нужен

 // базовый способ получения экземпляров

 CClass {}

};

CClass* CClass::factory(void) { return new CClass; }

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

CClass* cc = new CClass;

// Виртуальное конструирование!!!

CClass* cc1 = cc-›factory(void);

Думаю, что на этом следует закончить этот шаг. К конструированию объектов мы будем возвращаться еще не раз… но не сегодня.

Примером производящих функций являются макросы DECLARE_SERIAL, IMPLEMENT_SERIAL, DECLARE_DYNCREATE, IMPLEMENT_DYNCREATE в MFC. Они конечно сложнее и делают много чего еще, но в конечном итоге это замазанные макросом производящие функции.

Шаг 12 - Двухэтапная инициализация.

Когда мы создаем нестековый экземпляр, то пишем такой код:

CClass* cc = new CClass;

Попробуем поразбираться. new– это глобальный оператор с определением:

void* operator new (size_t bytes);

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

1. Выделение памяти;

2. Конструирование.

Оба действия могут кончиться неудачей. Либо память не выделится, тогда негде будет инициализировать объект, либо память выделится, но инициализация будет неудачной. С 1998 года стандарт C++ предусматривает, что если инициализация прошла неудачно, то выделенная память должна автоматически освободиться - то есть вызваться оператор delete, но без передачи управления деструктору. До того это оставалось на совести разработчика компилятора, и довольно часто выделенная память могла застрять, и больше не вернуться в систему. Кроме того, конструктор ничего не возвращает. Только что проверить на 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+,потому что в жизни (помимо С++) он выражает замечательное действие - добавление объекта к другому объекту. Конечно, Вы можете придать ему и другой смысл, но это будет как раз тот случай, где "если хочешь быть здоров - ешь один, и в темноте"…

Поделиться:
Популярные книги

Лучший из худший 3

Дашко Дмитрий
3. Лучший из худших
Фантастика:
городское фэнтези
попаданцы
аниме
6.00
рейтинг книги
Лучший из худший 3

Идеальный мир для Лекаря 14

Сапфир Олег
14. Лекарь
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 14

Неудержимый. Книга XII

Боярский Андрей
12. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XII

Надуй щеки! Том 6

Вишневский Сергей Викторович
6. Чеболь за партой
Фантастика:
попаданцы
дорама
5.00
рейтинг книги
Надуй щеки! Том 6

Черный дембель. Часть 2

Федин Андрей Анатольевич
2. Черный дембель
Фантастика:
попаданцы
альтернативная история
4.25
рейтинг книги
Черный дембель. Часть 2

Истинная со скидкой для дракона

Жарова Анита
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Истинная со скидкой для дракона

В погоне за женой, или Как укротить попаданку

Орлова Алёна
Фантастика:
фэнтези
6.62
рейтинг книги
В погоне за женой, или Как укротить попаданку

Ванька-ротный

Шумилин Александр Ильич
Фантастика:
альтернативная история
5.67
рейтинг книги
Ванька-ротный

Новик

Ланцов Михаил Алексеевич
2. Помещик
Фантастика:
альтернативная история
6.67
рейтинг книги
Новик

Адептус Астартес: Омнибус. Том I

Коллектив авторов
Warhammer 40000
Фантастика:
боевая фантастика
4.50
рейтинг книги
Адептус Астартес: Омнибус. Том I

Кодекс Крови. Книга ХI

Борзых М.
11. РОС: Кодекс Крови
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Крови. Книга ХI

Идеальный мир для Лекаря 26

Сапфир Олег
26. Лекарь
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 26

…спасай Россию! Десант в прошлое

Махров Алексей
1. Господин из завтра
Фантастика:
альтернативная история
8.96
рейтинг книги
…спасай Россию! Десант в прошлое

Убивать чтобы жить 3

Бор Жорж
3. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 3