Во-первых, некоторые технические знания : компиляторы C ++ обычно генерируют нечто, называемое vtable, для любого класса с виртуальными функциями. Это в основном таблица функциональных указателей. В таблице содержится указатель на функцию для каждого виртуального метода, реализуемого классом.
В COM интерфейсы - это в основном абстрактные базовые классы, которые реализует компонент, например ::10000
class CSomeComponent : IUnknown, ISomeOtherInterface { ... };
В таблицу для CSomeComponent
будут включены указатели функций для всех методов, определенных в этих двух интерфейсах.
struct __imaginary_vtable_for_CSomeComponent
{
// methods required by IUnknown
HRESULT (*QueryInterface)( const IID& iid, void** ppv );
ULONG (*AddRef)();
ULONG (*Release)();
// methods required by ISomeOtherInterface
void (*foo)();
...
};
Любой экземпляр объекта имеет ссылку на виртуальную таблицу своего динамического типа. Вот как программа знает, как вызывать правильный метод в тех случаях, когда базовый метод переопределяется в производном классе:
class Base
{
public:
virtual void foo() { ... }
}
class Derived : public Base
{
public:
virtual void foo() { ... } // overrides Base::foo()
virtual void bar() { ... }
}
...
Base* X = new Derived;
X->foo();
Последняя строка должна вызывать Derived::foo
. Это работает, потому что объект X
имеет ссылку на vtable для класса Derived
. Как уже говорилось, vtable похож на список указателей на функции. Теперь vtables имеют фиксированную компоновку: если класс Derived
наследуется от класса Base
, указатель функции для метода foo
будет в том же относительном местоположении в vtable Derived
, что и в vtable Base
. :
struct __imaginary_vtable_for_Base
{
void (*foo)();
};
// __imaginary_vtable_for_Base::foo = Base::foo
struct __imaginary_vtable_for_Derived
{
void (*foo)();
void (*bar)();
};
// __imaginary_vtable_for_Derived::foo = Derived::foo
Теперь, если компилятор видит что-то вроде X->foo()
, он знает, что для всех классов, производных от Base
, метод foo
соответствует первой записи в vtable. Таким образом, он вызывает вызов первого указателя функции, который в случае X
является вызовом Derived::foo
.
Ответ на ваш вопрос : Компиляторы могут генерировать COM-компоненты, только если они генерируют ту же компоновку для vtables, которую требует спецификация COM. Таблицы vtables могут быть реализованы различными способами, особенно когда речь идет о множественном наследовании (что требуется для компонентов COM). Необходимо придерживаться определенного формата vtable, чтобы при вызове метода компонента f
вы на самом деле вызывали метод f
, а не какой-либо другой метод g
, который находится в f
позиция в vtable класса компонента. Я полагаю, что COM-совместимые компиляторы по сути должны создавать те же макеты vtable, что и Microsoft Visual C ++, поскольку технология COM была определена Microsoft.
P.S. : Извините за такую техническую информацию, я надеюсь, что приведенная выше информация вам пригодится.