通常会将不同的功能划分到不同的COM接口,到继承并实现具体功能的类。通过一个实现QueryInterface/AddRef/Release等公共函数的类,对外部暴露单一的接口,而实现COM组件的DLL封装。例如:
class IMyCom1 : public IUnknown
{
public:
virtual int add(int x, int y) = 0;
virtual int sub(int x, int y) = 0;
};
class IMyCom2 : public IUnknown
{
public:
virtual int mul(int x, int y) = 0;
virtual int div(int x, int y) = 0;
};
class CMyCom1 : public IMyCom1
{
public:
int add(int x, int y) override;
int sub(int x, int y) override;
};
class CMyCom2 : public IMyCom2
{
public:
int mul(int x, int y)override;
int div(int x, int y)override;
};
// 暴露给工厂的类
clss CMyCom : public CMyCom2 ,public class CMyCom1
{
ULONG AddRef() override;
ULONG Release() override;
//
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv) override;
}
工厂在管理COM类时,上述的CMyCom由于有多个IUnknown基类,会由于二义性而包编译时错误。
如果将IMyCom1和IMyCom2的基类改为
public virtual IUnknown
那么编译错误消失。
但运行时,在客户端创建我们的COM类时。在内部调用QueryInterface后。即使能够返回正确的指针(通过内部测试可以证明),COM内部的内存布局与msvc编译器的虚继承的内存布局不兼容。可能是标准C++对于虚继承的实现(内存布局)未定义。这种内存错误,会很难排查。