Идиомы и стили С++ | страница 39
>// класс незавершенного вызова. Это самое важное.
>class pmfc {
>private:
> // два указателя - на объект и на функцию
> CSmth* m_smth;
> PF m_pfunct;
>public:
> // конструктор
> pmfc (CSmth*& _smth, PF& _pfunct) : m_smth(_smth), m_pfunct(_pfunct) {}
> // вызов конечной функции из оператора ()
> int operator()() const { return (m_smth-›*m_pfunct)(); }
>};
>// класс умного указателя.
>class CPtr {
>private:
> CSmth* a;
>public:
> CPtr() { a = new CSmth(); }
> ~CPtr() { delete a; }
> CSmth* operator-›() const { return a; }
> CSmth& operator* () const { return *a; }
> operator CSmth* () const { return a; }
> // возвращает PMFC. Это тоже важно.
> pmfc operator-›*(PF _pf) { return pmfc (a, _pf); }
>};
>// проверим все
>int main() {
> CPtr t;
> t-›a = 10;
> // заодно проверим operator*
> (*t).a = 16;
> int b = 0;
> // получили указатель на функцию.
> PF lpF =&CSmth::pf;
> // вызвали функцию по указателю при помощи нашей конструкции
> b = (t-›*lpF)();
> return 0;
>}
С тоской взглянув на полученный результат, сразу осознаешь, что без шаблонов не обойтись - ведь нужно обслуживать разные типы указателей на функции. Но зато мы минимум знаем, как решать эту проблему. Еще раз испытали proxy-объекты. Потрогали указатели на функции и функции члены. Перегрузили операторы * и (). И если встанет проблема - то знаем, где искать решение (у Скотта Мейерса).
Шаг 28 - Классы объектов, поддерживающие транзакции. Продолжение 2.
Классы объектов, хранящие состояния, получились очень неплохие - при минимальных интеллектуальных затратах, хотя о транзакциях говорить рано: для транзакций они недостаточно кислотные. (ACID - Atomic, Consistent, Isolated, Durable). Не хватает вот чего:
1. Объекты, задействованные в транзакции, блокируются на запись.
2. Объекты, задействованные в транзакции, представляют другим клиентам свое состояние до транзакции.
Мы уже понимаем общий принцип: если нужна дополнительная логика - вынесите ее на отдельный уровень. Что означает это в нашем случае? То, что 1: транзакция должна быть представлена отдельным уровнем - отдельным классом; 2: объекты, задействованные в транзакции, должны поддерживать специальный стандартный интерфейс, за который транзакция должна ими рулить. То есть, они либо должны быть порождены от специального абстрактного базового класса, либо они должны быть упакованы в специальный смарт-указатель - делающий то же самое.