А что касается виртуальных функций, то и MFC, и OWL, и VCL - все используют их как можно реже - на то веские причины! Если бы все функции в них были виртуальными, то с полметра памяти уходило бы в каждой программе только на поддержание виртуальных таблиц, да по лишнему указателю в каждом объекте.
Есть такое правило "80-20": 20 процентов кода вызывает 80 процентов затруднений, 20 процентов кода занимает 80 процентов процессорного времени. Возможно, оно даже сильнее - "90-10". В данном Шаге это значит - не зашивайтесь в "дешевой" части кода.
В общем, я хочу сказать - перед тем, как применять какую-то технику, оцените - какие усилия Вы затратите на ее освоение, ее поддержание, и какой результат Вы получите (ожидаете получить), и пригодятся ли Вам эти знания в будущем, что тоже важно. Программирование - всегда поиск компромисса между затратами времени, пространства и (!)труда, не забывайте что Ваш день стоит минимум как небольшой DIMM. Надеюсь.
Шаг 22 - Классы объектов, поддерживающие транзакции.
Бывает особенно приятно, когда занимаешься теорией. Занимаешься, думаешь: "ну никакой связи с жизнью, хоть бы минимум пользы"… и вдруг раз! и польза является во всей своей красе, блистая в лучах солнца и хрустя пачками денег. Что чувствовал Менделеев, когда после долгих изысканий, жутких таблиц, являвшихся ему в ночных кошмарах, вдруг получил-таки нормальную, не паленую, 40-градусную водку? Или Эйлер, когда, после терзаний и депрессий, извлек таки сопротивляющийся, визжащий и цепляющийся щупальцами и жвалами квадратный корень из минус единицы? К чему это я? А вот к чему: концепция smart-указателей может предложить простые и прозрачные решения для некоторых сложных задач; и если Вы считаете, что поддержка транзакций (а так же многоуровневой отмены и повтора) есть сложная задача, то смарты помогут Вам с замечательной легкостью.
Вспомним для начала, что делает транзакция:
1. Если транзакция началась, то все изменения в ней либо вносятся вместе, либо не вносятся вообще (это вообще определение транзакции).
2. Если клиент начал и не завершил транзакцию, то другие клиенты не видят его изменений.
3. Две транзакции не могут одновременно изменять одни и те же данные.
Начнем с первого пункта. Если мы хотим закрепить или отменить проведенные изменения, нужно хранить состояние объекта на заданный момент - начало транзакции, и в момент принятия решения или уничтожать предыдущее состояние (закрепление) или возвращаться к нему (отмена). Пусть обслуживанием занимается smart-указатель. Кладем в него два указателя - один на текущий объект, а второй - на объект, представляющий его предыдущее состояние, и три функции - старт, закрепление, отмена.
>#include ‹iostream.h›
>// Некий скромный класс.
>class CSomeClass {
>public:
> int x;
> int y;
>};
>// Его оплетка: smart-pointer с поддержкой отмены.
>class CSimpleTr {
>public:
> CSomeClass* that; // текущее значение
> CSomeClass* previos; // предыдущее значение
>public:
> // конструктор-деструктор-присваивание-копирование
> CSimpleTr(): previos(NULL), that(new CSomeClass) {}
> CSimpleTr(const CSimpleTr& _st): that(new CSomeClass(*(_st.that))), previos(NULL) {}
> ~CSimpleTr() {delete that; delete previos;}
> CSimpleTr& operator=(const CSimpleTr& _st) {
> if (this!=&_st) {
> delete that;
> that = new CSomeClass(*(_st.that));
> }
> return *this;
> }
> // начало транзакции
> void BeginTrans() {
> delete previos;
> previos = that;
> that = new CSomeClass(*previos);
> }
> // закрепление
> void Commit() {
> delete previos;
> previos = NULL;
> }
> // отмена транзакции
> void Rollback() {
> if (previos != NULL) {
> delete that;
> that = previos;
> previos = NULL;
> }
> }
> // реализация указателя
> CSomeClass* operator-›() { return that; }
>};
>int main (void) {
> // проверим быстренько
> CSimpleTr lvPair;
> lvPair-›x = 5;
> lvPair-›y = 8;
> lvPair.BeginTrans();
> lvPair-›x = 7;
> lvPair-›y = 11;
> lvPair.Rollback();
> lvPair.BeginTrans();
> lvPair-›x = 7;
> lvPair-›y = 11;
> lvPair.Commit();
> return 0;
>}
Что может быть проще? Семантика значений, очевидно. Классы должны иметь полный набор обязательных функций, как обычно; в нашем случае класс