Розробка стійких систем

Функція DBConnection :: create () викликає attach (), тому після завершення роботи з об'єктом необхідно звільнити захоплене підключення явним викликом detach (). Зверніть увагу: клас DBClient також управляє з'єднанням за допомогою RAIL При завершенні програми деструктори двох об'єктів DBClient зменшують лічильник посилань (викликом функції detachQ, успадкованої DBConnection від Countable). Підключення до бази даних закривається (через віртуального деструктора Countable) при падінні лічильника до нуля після знищення об'єкта з1.

Підключення функціональності через успадкування частіше здійснюється із застосуванням шаблонів, щоб користувач міг на стадії компіляції вибрати потрібну різновид. Це дозволяє задіяти різні механізми підрахунку посилань без повторного визначення DBConnection. Ось як це робиться:

Параметризрвані підключення функціональності

#ifndef DBCONNECTION H

# Def1ne DBCONNECTION H

class DBConnection. public Database, public Counter

DBConnection (const DBConnectionS): Заборона копіювання

DBConnectionSt operator = (const DBConnection): protected:

DBConnection (const string dbStr) throw (DatabaseError). Database (dbStr) -DBConnectionO public:

static DBConnection * createCconst string dbStr) throw (DatabaseError)

DBConnection * con = new DBConnection (dbStr):

assert (con-> refCount () == 1): return con:

Інші необхідні функції.

#endif DBC0NNECTI0N2 H III: -

Єдина зміна - поява шаблонного префікса у визначенні класу (і перейменування Countable в Counter для ясності). Клас доступу до бази даних теж можна було б оформити у вигляді параметра шаблона (якби у нас було кілька класів доступу, з яких вибирався б потрібний варіант), але на цей раз клас вийшов цілком самостійним. У наступному прикладі вихідна реалізація Countable приймає в якості аргументу шаблону, але з таким же успіхом можна було б використовувати будь-який тип, який реалізує потрібний інтерфейс (attach (), detach () і т. Д.):

Підключення функціональності через шаблон

При спадкуванні в похідний клас включаються копії всіх змінних базового класу. Наступна програма демонструє можливе розміщення декількох базових подоб'ектов в пам'яті:

Розміщення подоб'ектов в пам'яті

при множині спадкування

using namespace std:

class С. public A. public В :

int mainO

cout c == c endl:

Конкретний вид результатів залежить від компілятора.

DBConnection* Db: public:

DBClient (DBConnection* DbCon) attach ():

int mainO * Db =

DBConnection:: create (MyDatabase): assert (db-> refCount () == 1): DBClient cl (db): assert (db-> refCount () == 2): DBClient c2 (db): assert (db-> refCount () == 3): db-> detach ():

assert (db-> refCount () == 2);> III: -

Загальний патерн для декількох класів, що підключаються виглядає так:

tempiate

class Subject. public Mixinl.

Хоча ко.мпілятор б не виявив помилку. Втім, проблема вирішується за допомогою оператора dynamiccast - за подробицями звертайтеся до попередньої теми.

А * ар = з: У * bp = с;

cout ар == static cast(Ap) endl:

cout bp == static cast(Bp) endl:

C * cp = static cast(Bp):

cout cp == static cast(Cp) endl:

cout bp == cp? boolalpha (bp == cp) endl:

/ * Результат: sizeof (A) == 4 s1zeof (B) == 4 sizeof (C) == 12 c == 1245052 ap == 1245052 bp == 1245056 cp == 1245052 bp == cp? true 0

Як бачите, подоб'екти В об'єкта з знаходиться на відстані 4 байт від початку всього об'єкта. Можна припустити наступну структуру пам'яті:

Схожі статті