Предполагая, что вам не нужно, чтобы объекты-обработчики были отдельными экземплярами C ++ от общего объекта, тогда может сработать следующее ...
Если я правильно помню свой COM ... - почему бы не простооставьте FooHandler как частично абстрактный базовый класс - оставьте часть IUnknown невыполненной.Пусть MyCOMClass наследует все необходимые обработчики;а затем реализовать IUnknown только в этом наиболее производном классе.Предоставленный вами AddRef / Release / QI будет использоваться для всех базовых классов.(Как правило, можно просто переслать AddRef / Release в класс CUnknown или некоторую базу, которая выполняет ведение подсчета, но, скорее всего, потребуется реализовать QI вручную, поскольку это единственное место, где вы полностью знаете, какой набор интерфейсов вы хотите предоставить.)
Другими словами, продолжайте делать то, что вы делаете;но вам не нужно выполнять часть делегирования вручную: компилятор на самом деле делает то же самое для вас за кулисами, так как множественное наследование интерфейсов (в частности, классов с виртуальными методами) работает в C ++.Волшебная часть заключается в том, что методы, объявленные в самом производном интерфейсе по умолчанию, переопределяют все методы с тем же именем и сигнатурой параметра в базовых классах;поэтому любой базовый класс, который вызывает AddRef или QI в своем собственном IUnknown, в конечном итоге вызовет версию, указанную вами в наиболее производном классе.
Код, вероятно, выглядит примерно так:
class MyCOMClass
, public CUnknown // Assume this handles refcounting (and has a virtual dtor!)
, public CFooHandler // Implements IFoo
, public CBarHandler // Implements IBar
{
... add any interfaces that MyCOMClass itself is implementing...
// Actual impl of IUnknown...
STDMETHOD_(ULONG, AddRef)(); { return CUnknown::AddRef(); }
STDMETHOD_(ULONG, Release)(); { return CUnknown::Release(); }
STDMETHOD(QueryInterface)(IN REFIID riid, OUT void** ppv)
{
*ppv = NULL;
// IUnknown can require extra casting to pick out a specific IUnknown instance
// otherwise compiler will complain about an ambiguous cast. Any IUnknown will do,
// we know they're all the same implementation, so even casting to CFooHandler then IUnknown is fine here.
// Here am assuming that CUnknown implements IUnknown
if(riid == __uuidof(IUnknown))
*ppv = static_cast<IUnknown*>(static_cast<CUnknown*>(this));
else if(riid == __uuidof(IFoo))
*ppv = static_cast<IFoo*>(this);
else if(riid == __uuidof(IBar))
*ppv = static_cast<IBar*>(this);
else
return E_NOINTERFACE;
// Usually you call AddRef on the interface you are returning; but
// we know we're using the same ref count for the whole object, so this
// is appropriate for this specific implementation strategy.
AddRef();
}
Если вы хотите реализовать обработчики для отдельных объектов, то вам нужно выполнить делегирование, которое вы предлагаете, - по сути, это форма агрегации.Но вам не нужно реализовывать интерфейсы на MyCOMClass и писать множество серверов пересылки: все, что MyCOMClass должен сделать, это реализовать QI таким образом, чтобы возвращаемое значение - будь то тот же самый объект или какой-то отдельный объект - было должным образом приведено кзапрашиваемый интерфейс.Но если вам не нужны отдельные объекты, описанная выше техника должна работать нормально.