Предположим, класс реализет несколько интерфейсов.
class I1: public IDispatch {...}
class I2: public IDispatch {...}
class CImpl : public СImplementI1, public СImplementI2 {...}
Задача: нужно для каждого интерфеса класса выдать соответствующий ему IDispatch
вот так:
I1 *pI1;
//
...здесь создаем объект типа CImpl, присваиваем pI1 указатель на I1 из объекта
//
I2 *pI2; pI2->QueryInterface(IID_I2, (void**)pI2);
IDispatch pDisp1; pI1->QueryInterface(IID_IDispatch, (void**)pDisp1);
IDispatch pDisp2; pI2->QueryInterface(IID_IDispatch, (void**)pDisp2);
в итоге, как ни крути pDisp1==pDisp2;
потому что в CImpl есть только один виртуальный метод QueryInterface, и сказать ему, из какого интерфеса (I1 или I2) хотят получить IDispatch нет никакой возможности.
В то же время, если использовать аггрегацию, то подобный прием проходит. Потому что существует 2 объекта, 2 разных vtable, и соответственно 2 QueryInterface.
ИМХО, это несправедливо, потому что из-за IDispatch я должен отказываться от множественного наследования.
Может, кто-нибудь знает как побороть проблему?
Re: несколько реализаций IDispatch в одном CoClass'е
Здравствуйте, Аноним, Вы писали:
А>в итоге, как ни крути pDisp1==pDisp2; А>потому что в CImpl есть только один виртуальный метод QueryInterface, и сказать ему, из какого интерфеса (I1 или I2) хотят получить IDispatch нет никакой возможности.
такая возможность как раз есть, отвлечемся от COM:
struct IDispatch
{
virtual void QueryInterface(int, void**) = 0;
};
class I1 : public IDispatch
{
public:
virtual void QueryInterface(int, void**)
{
}
};
class I2: public IDispatch
{
public:
virtual void QueryInterface(int, void**)
{
}
};
class CImpl : public I1, public I2
{
public:
enum {IID_I1, IID_I2};
virtual void QueryInterface(int iid, void**)
{
if(iid == IID_I1)
{
I1::QueryInterface(iid, 0);
}
else if(iid == IID_I2)
{
I2::QueryInterface(iid, 0);
}
}
};
int main()
{
CImpl *p = new CImpl();
p->QueryInterface(CImpl::IID_I1, 0);
p->QueryInterface(CImpl::IID_I2, 0);
return 0;
}
тоесть пусть CImpl сам решает, по переданному идентификатору, куда диспачить вызов дальше
Re: несколько реализаций IDispatch в одном CoClass'е
Здравствуйте, Аноним, Вы писали:
А>...потому что в CImpl есть только один виртуальный метод QueryInterface, и сказать ему, из какого интерфеса (I1 или I2) хотят получить IDispatch нет никакой возможности. А>В то же время, если использовать агрегацию, то подобный прием проходит. Потому что существует 2 объекта, 2 разных vtable, и соответственно 2 QueryInterface.
Это обманчивое представление. И агрегация не предоставляет вариантов для QueryInterface(IID_IDispatch), потому что внутренний объект должен переадресовать запрос QueryInterface внешнему. Так что схемы похожи и для твоего случая, и для агрегации — хоть и есть две различные реализации IDispatch, работать реально будет только одна. Та, которую вернет IUnknown::QueryInterface(IID_IDispatch) на любом интерфейсном указателе объекта.
А>ИМХО, это несправедливо, потому что из-за IDispatch я должен отказываться от множественного наследования. А>Может, кто-нибудь знает как побороть проблему?
Не использовать IDispatch, т.к. это интерфейс, содержащий в самом себе противоречие: своими методами он описывает нечто, совершенно отличное от него самого, т.е. совершенно другой интерфейс. Или, другими словами, интерфейс IDispatch должен описывать методы (всего) объекта как целого.