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

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

Жанры

Сущность технологии СОМ. Библиотека программиста
Шрифт:

if (!ppo) pfs->Delete;

else { ppo->Save(«C:\\autoexec.bat»);

ppo->Delete; }

}

}

Хотя вначале объект был связан через свой интерфейс IFastString , клиентский код вызывает метод Delete через интерфейс IPersistentObject. С использованием свойства C++ о множественном наследовании это вполне допустимо, так как все таблицы vtbl , порожденные классом IExtensibleObject,

укажут на единственную реализацию метода Delete . Теперь, однако, пользователь должен хранить информацию о том, какие указатели связаны с какими объектами, и вызывать Delete только один раз на объект. В случае простого кода, приведенного выше, это не слишком тяжелое бремя. Для более сложных клиентских кодов управление этими связями становится делом весьма сложным и чреватым ошибками. Одним из способов упрощения задачи пользователя является возложение ответственности за управление жизненным циклом объекта на реализацию. Кроме того, разрешение клиенту явно удалять объект вскрывает еще одну деталь реализации: тот факт, что объект находится в динамически распределяемой памяти (в «куче», on the heap).

Простейшее решение этой проблемы – ввести в каждый объект счетчик ссылок, который увеличивается, когда указатель интерфейса дублируется, и уменьшается, когда указатель интерфейса уничтожается. Это предполагает изменение определения IExtensibleObject с

class IExtensibleObject

{

public:

virtual void *DynamicCast (const char* pszType) =0;

virtual void Delete(void) = 0;

};

на

class IExtensibleObject

{

public:

virtual void *DynamicCast(const char* pszType) = 0;

virtual void DuplicatePointer(void) = 0;

virtual void DestroyPointer(void) = 0;

};

Разместив эти методы, все пользователи IExtensibleObject должны теперь придерживаться следующих двух соображений:

1) Когда указатель интерфейса дублируется, требуется вызов DuplicatePointer.

2) Когда указатель интерфейса более не используется, следует вызвать DestroyPointer.

Эти методы могут быть реализованы в каждом объекте: нужно просто фиксировать количество действующих указателей и уничтожать объект, когда невыполненных указателей не осталось:

class FastString : public IFastString,

public IPersistentObject

{

int mcPtrs;

// count of outstanding ptrs

// счетчик невыполненных указателей

public:

// initialize pointer count to zero

// сбросить счетчик указателя в нуль

FastString(const char *psz) : mcPtrs(0) { }

void DuplicatePointer(void)

{

// note duplication of pointer

// отметить дублирование указателя

++mcPtrs;

}

void DestroyPointer(void)

{

// destroy object when last pointer destroyed

// уничтожить объект,

когда уничтожен последний указатель

if (-mcPtrs == 0) delete this;

}

: : :

};

Этот совершенно стандартный код мог бы просто быть включен в базовый класс или в макрос С-препроцессора, чтобы его могли использовать все реализации.

Чтобы поддерживать эти методы, все программы, которые манипулируют или управляют указателями интерфейса, должны придерживаться двух простых правил DuplicatePointer/DestroyPointer. Для реализации FastString это означает модификацию двух функций. Функция CreateFastString берет начальный указатель, возвращаемый новым оператором C++, и копирует его в стек для возврата клиенту. Следовательно, необходим вызов DuplicatePointer:

IFastString* CreateFastString(const char *psz)

{

IFastString *pfsResult = new FastString(psz);

if (pfsResult) pfsResult->DuplicatePointer;

return pfsResult;

}

Реализация копирует указатель и в другом месте – в методе Dynamic_Cast:

void *FastString::Dynamic_Cast(const char *pszType)

{

void *pvResult = 0;

if (strcmp(pszType, «IFastString») == 0) pvResult = static_cast<IFastString*>(this);

else if (strcmp(pszType, «IPersistentObject») == 0) pvResult = static_cast<IPersistentObject*>(this); 

else if (strcmp(pszType, «IExtensibleObject») == 0) pvResult = static_cast<IFastString*>(this);

else return 0;

// request for unsupported interface

// запрос на неподдерживаемый интерфейс

// pvResult now contains a duplicated pointer, so

// we must call DuplicatePointer prior to returning

// теперь pvResult содержит скопированный указатель,

// поэтому нужно перед возвратом вызвать DuplicatePointer

((IExtensibleObject*)pvResult)->DuplicatePo1nter;

return pvResult;

}

С этими двумя усовершенствованиями соответствующий код пользователя становится значительно более однородным и прозрачным:

void f(void)

{

IFastString *pfs = 0;

IPersistentObject *ppo = 0;

pfs = CreateFastString(«Feed BOB»);

if (pts) {

рро = (IPersistentObject *) pfs->DynamicCast(«IPersistentObject»);

if (ppo) { ppo->Save(«C:\\autoexec.bat»);

ppo->DestroyPointer; }

pfs->DestroyPointer; }

}

Поскольку каждый указатель теперь трактуется как автономный объект с точки зрения времени жизни, клиенту можно не интересоваться тем, какой указатель соответствует какому объекту. Вместо этого клиент просто придерживается двух простых правил и предоставляет объектам самим управлять своим временем жизни. При желании способ вызова DuplicatePointer и DestroyPointer можно легко скрыть за интеллектуальным указателем (smart pointer) C++.

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

Новый Рал

Северный Лис
1. Рал!
Фантастика:
фэнтези
попаданцы
5.70
рейтинг книги
Новый Рал

Адвокат Империи 2

Карелин Сергей Витальевич
2. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Адвокат Империи 2

Архонт

Прокофьев Роман Юрьевич
5. Стеллар
Фантастика:
боевая фантастика
рпг
7.80
рейтинг книги
Архонт

Чехов. Книга 3

Гоблин (MeXXanik)
3. Адвокат Чехов
Фантастика:
альтернативная история
5.00
рейтинг книги
Чехов. Книга 3

Сирота

Шмаков Алексей Семенович
1. Светлая Тьма
Фантастика:
юмористическое фэнтези
городское фэнтези
аниме
5.00
рейтинг книги
Сирота

Бомбардировщики. Полная трилогия

Максимушкин Андрей Владимирович
Фантастика:
альтернативная история
6.89
рейтинг книги
Бомбардировщики. Полная трилогия

Сделай это со мной снова

Рам Янка
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Сделай это со мной снова

Наследник

Кулаков Алексей Иванович
1. Рюрикова кровь
Фантастика:
научная фантастика
попаданцы
альтернативная история
8.69
рейтинг книги
Наследник

Эра Мангуста. Том 2

Третьяков Андрей
2. Рос: Мангуст
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Эра Мангуста. Том 2

Выйду замуж за спасателя

Рам Янка
1. Спасатели
Любовные романы:
современные любовные романы
7.00
рейтинг книги
Выйду замуж за спасателя

Скандальный развод, или Хозяйка владений "Драконье сердце"

Милославская Анастасия
Фантастика:
попаданцы
фэнтези
5.00
рейтинг книги
Скандальный развод, или Хозяйка владений Драконье сердце

Морана

Кулаков Алексей Иванович
Фантастика:
фэнтези
альтернативная история
5.00
рейтинг книги
Морана

Громовая поступь. Трилогия

Мазуров Дмитрий
Громовая поступь
Фантастика:
фэнтези
рпг
4.50
рейтинг книги
Громовая поступь. Трилогия

Наследник пепла. Книга II

Дубов Дмитрий
2. Пламя и месть
Фантастика:
фэнтези
5.00
рейтинг книги
Наследник пепла. Книга II