Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Новости ИТ Программы Книги Games   Обои   Экспорт RSS E-Books
 
Поиск по сайту

TOP-10 программ
Symantec Norton Ghost 9.0
Partition Magic 8.0.2 Pro
Xilisoft 3GP Video Converter v3.1.7.0616b
Norton AntiVirus 2005
Xilisoft 3GP Video Converter v2.1.52.831b
Антивирус Касперского Personal 5.0.303 beta 2
RAR Password Cracker 4.12
ABBYY PDF Transformer v1.00.820
MP3 To Ringtone Gold v3.02
Windows Movie Maker 2.6
 
Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
 
 

   Программирование -> C/C++ -> Сущность технологии COM


Управление ресурсами

Еще одна проблема поддержки нескольких интерфейсов из одного объекта становится яснее, если исследовать схему использования клиентом метода Dynamic_Cast. Рассмотрим следующую клиентскую программу:

void f(void) 
{
    IFastString *pfs = 0; 
    IPersistentObject *ppo = 0; 
   
    pfs = CreateFastString("Feed BOB"); 
   if (pfs) { 
       ppo = (IPersistentObject *) pfs->Dynamic_Cast("IPersistentObject"); 
       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 *Dynamic_Cast (const char* pszType) =0; 
    virtual void Delete(void) = 0; 
}; 

на

class IExtensibleObject {
  public: 
    virtual void *Dynamic_Cast(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 m_cPtrs;
      // count of outstanding ptrs 
      // счетчик невыполненных указателей 
  public: 
      // initialize pointer count to zero 
      // сбросить счетчик указателя в нуль 
    FastString(const char *psz) : m_cPtrs(0) { } 
    void DuplicatePointer(void) { 
      // note duplication of pointer 
      // отметить дублирование указателя 
        ++m_cPtrs; 
    } 
    void DestroyPointer(void) { 
      // destroy object when last pointer destroyed 
      // уничтожить объект, когда уничтожен последний указатель 
        if (--m_cPtrs == 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->Dynamic_Cast("IPersistentObject");
        if (ppo) { 
            ppo->Save("C:\\autoexec.bat"); 
            ppo->DestroyPointer(); 
        } 
        pfs->DestroyPointer(); 
    } 
} 

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

Использование этой схемы вычисления ссылок позволяет объекту весьма единообразно выставлять множественные интерфейсы. Возможность выставления нескольких интерфейсов из одного класса реализации позволяет типу данных участвовать в различных контекстах. Например, новая постоянная подсистема могла бы определить собственный интерфейс для управления автозагрузкой и автозаписью объектов на некоторый специализированный носитель. Класс FastString мог бы добавить поддержку этих возможностей простым наследованием от постоянного интерфейса этой подсистемы. Добавление этой поддержки никак не повлияет на уже установленные базы клиентов, которые, может быть, используют прежний постоянный интерфейс для записи и загрузки строки на диск. Механизм согласования интерфейсов на этапе выполнения может служить краеугольным камнем для построения динамической системы из компонентов, которые могут изменяться со временем.

Где мы находимся?

 
Популярные книги

SQL для "чайников", 5-е издание

Подробнее

Дизайн помещений и интерьеров в 3ds max 7 (+CD)

Подробнее

Практикум по программированию на языке Си (+CD)

Подробнее


 
Новости ИТ
09.01.2009  Exeda -- корпоративный цифровой ассистент с Android Linux
09.01.2009  Правительство Вьетнама массово переходит на Open Source
09.01.2009  Windows 7 build 7000
09.01.2009  Silicon Power представила скоростную SDHC
09.01.2009  CES 2009: RealView 360 3D Desktop Scanner - настольный 3D-сканер, один из первых в мире
09.01.2009  W90 - очень быстрый мультимедийный ноутбук ASUS «Ultimate-уровня»
09.01.2009  CES 2009: SanDisk представила семейство G3 - самых быстрых SSD-накопителей на флэш-памяти MLC
09.01.2009  ZOTAC GeForce GTX 285 и GTX 285 AMP! Edition - 3D-ускорители для геймеров на новом GPU NVIDIA
09.01.2009  Net Applications: в декабре доли Firefox и Chrome росли за счет IE
09.01.2009  Imation говорит о «новом классе» SSD и первом в отрасли полном наборе для модернизации на основе SSD
09.01.2009  Маршрутизатор D-Link Xtreme N DIR-685 может играть роль NAS, сервера печати... и цифровой фоторамки
09.01.2009  Очень тонкая фотокамера Pentax Optio P70 имеет разрешение 12 Мп
09.01.2009  pureSilicon 1TB Nitro - первый в мире 2,5-дюймовый SSD объемом 1 ТБ
09.01.2009  Дебютировали мобильные GPU ATI Mobility Radeon HD 4000
09.01.2009  NVIDIA GeForce GTX 285 и GTX 295 представлены официально
09.01.2009  Scythe выпустила процессорный кулер Mugen 2
09.01.2009  Optio E70 - новая компактная камера Pentax начального уровня
09.01.2009  Новый iPhone получит четырехъядерный процессор?
08.01.2009  FreeBSD 7.1-RELEASE -- обновление операционной системы
08.01.2009  Появилась сборка Om 2008.12 для Neo FreeRunner от bytestore
 
Полезно

 
Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.
 
Rambler's Top100