Я работаю с простой объектной моделью, в которой объекты могут реализовывать интерфейсы для обеспечения дополнительных функций.По сути, объект должен реализовывать метод getInterface
, которому присваивается (уникальный) идентификатор интерфейса.Затем метод возвращает указатель на интерфейс - или ноль, если объект не реализует запрошенный интерфейс.Вот эскиз кода, чтобы проиллюстрировать это:
struct Interface { };
struct FooInterface : public Interface { enum { Id = 1 }; virtual void doFoo() = 0; };
struct BarInterface : public Interface { enum { Id = 2 }; virtual void doBar() = 0; };
struct YoyoInterface : public Interface { enum { Id = 3 }; virtual void doYoyo() = 0; };
struct Object {
virtual Interface *getInterface( int id ) { return 0; }
};
Чтобы упростить работу для клиентов, работающих в этой среде, я использую небольшой шаблон, который автоматически генерирует реализацию getInterface, так что клиентам просто нужнореализовать фактические функции, требуемые интерфейсами.Идея состоит в том, чтобы извлечь конкретный тип из Object
, а также из всех интерфейсов, а затем позволить getInterface
просто вернуть указатели в this
(приведенный к нужному типу).Вот шаблон и демонстрационное использование:
struct NullType { };
template <class T, class U>
struct TypeList {
typedef T Head;
typedef U Tail;
};
template <class Base, class IfaceList>
class ObjectWithIface :
public ObjectWithIface<Base, typename IfaceList::Tail>,
public IfaceList::Head
{
public:
virtual Interface *getInterface( int id ) {
if ( id == IfaceList::Head::Id ) {
return static_cast<IfaceList::Head *>( this );
}
return ObjectWithIface<Base, IfaceList::Tail>::getInterface( id );
}
};
template <class Base>
class ObjectWithIface<Base, NullType> : public Base
{
public:
virtual Interface *getInterface( int id ) {
return Base::getInterface( id );
}
};
class MyObjectWithFooAndBar : public ObjectWithIface< Object, TypeList<FooInterface, TypeList<BarInterface, NullType> > >
{
public:
// We get the getInterface() implementation for free from ObjectWithIface
virtual void doFoo() { }
virtual void doBar() { }
};
Это работает довольно хорошо, но есть две проблемы, которые уродливы:
Блокировщик для меня заключается в том, что этоне работает с MSVC6 (который плохо поддерживает шаблоны, но, к сожалению, мне нужно его поддерживать).MSVC6 выдает ошибку C1202 при компиляции.
Целый диапазон классов (линейная иерархия) генерируется рекурсивным шаблоном ObjectWithIface
.Это само по себе не проблема, но, к сожалению, я не могу просто сделать один оператор switch
, чтобы сопоставить идентификатор интерфейса с указателем в getInterface
.Вместо этого каждый шаг в иерархии проверяет наличие единственного интерфейса и затем перенаправляет запрос в базовый класс.
У кого-нибудь есть предложения, как улучшить эту ситуацию?Либо исправив две вышеуказанные проблемы с шаблоном ObjectWithIface
, либо предложив альтернативы, которые облегчили бы использование инфраструктуры объектов / интерфейсов.