{

int m_cсh;

// count of characters

// счетчик символов

char *m_psz;

public:

FastString(const char *psz);

~FastString(void);

// IExtensibleObject methods

// методы IExtensibleObject

void *Dynamic_Cast(const char *pszType);

void Delete(void);

// deletes this instance

// удаляет этот экземпляр

// IFastString methods

// методы IFastString

int Length(void) const;

// returns # of characters

// возвращает число символов

int Find(const char *psz) const;

// returns offset

// возвращает смещение

// IPersistentObject methods

// методы IPersistentObject

bool Load(const char *pszFileName);

bool Save(const char *pszFileName);

};

Реализации Dynamic_Cast необходимо имитировать действия RTTI путем управления иерархией типов объекта. Рисунок 1.8 иллюстрирует иерархию типов для только что показанного класса FastString. Поскольку класс реализации порождается из каждого интерфейса, который он выставляет, реализация Dynamic_Cast в FastString может просто использовать явные статические приведения типа (explicit static casts), чтобы ограничить область действия указателя this, основанного на подтипе, который запрашивается клиентом:

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

{

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

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

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

else return 0;

// request for unsupported interface

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

}

Так как объект порождается от типа, используемого в этом преобразовании, оттранслированные версии операторов преобразования просто добавляют определенное смещение к указателю объекта this, чтобы найти начало представления базового класса.

Отметим, что после запроса на общий базовый интерфейс IExtensibleObject реализация статически преобразуется в IFastString. Это происходит потому, что интуитивная версия (intuitive version) оператора

return static_cast<IExtensibleObject*>(this);

неоднозначна, так как и IFastString, и IPersistentObject порождены от IExtensibleObject. Если бы IExtensibleObject был виртуальным базовым классом как для IFastString, так и для IPersistentObject, то данное преобразование не было бы неоднозначным и оператор бы оттранслировался. Тем не менее, применение виртуальных базовых классов добавляет на этапе выполнения ненужную сложность в результирующий объект и к тому же вносит зависимость от транслятора. Дело в том, что виртуальные базовые классы являются всего лишь особенностями языка C++, которые имеют несколько специфических реализации.

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

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

void f(void)

{

IFastString *pfs = 0;

IPersistentObject *ppo = 0;

pfs = CreateFastString(«Feed BOB»);

if (pfs) {

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

if (!ppo) pfs->Delete();

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

ppo->Delete(); }

}

}

Хотя вначале объект был связан через свой интерфейс IFastString , клиентский код вызывает метод Delete через интерфейс IPersistentObject. С использованием свойства C++ о множественном наследовании это вполне допустимо, так как все таблицы vtbl , порожденные классом IExtensibleObject, укажут на единственную реализацию метода Delete . Теперь, однако, пользователь должен хранить информацию о том, какие указатели связаны с какими объектами, и вызывать Delete только один раз на объект. В случае простого кода, приведенного выше, это не слишком тяжелое бремя. Для более сложных клиентских кодов управление этими связями становится делом весьма сложным и чреватым ошибками. Одним из способов упрощения задачи пользователя является возложение ответственности за управление жизненным циклом объекта на реализацию. Кроме того, разрешение клиенту явно удалять объект вскрывает еще одну деталь реализации: тот факт, что объект находится в динамически распределяемой

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату