您通常可以在不破坏兼容性的情况下向现有接口的end添加新方法。但是正如您一直在阅读的那样,在某些微妙的情况下这可能会中断。尤其是在已经使用多重继承的情况下。
正确的解决方案是简单地为新方法声明一个新接口。不理会现有的接口。然后让您现有的对象实现这两个接口或使用继承让新接口从旧接口继承。
例如,如果这是我们的原始代码。 (为简洁起见,我假设这是在没有 IDL 文件的情况下完成的)。
原码:
class IPublicInterface : public IUnknown
{
public:
virtual void M1() = 0;
virtual void M2() = 0;
}
class MyPublicClass : IPublicInterface
{
public:
// IPublicInterface
void M1();
void M2();
// IUnknown
HRESULT QueryInterface(...);
ULONG AddRef();
ULONG Release();
};
现在假设我们想在不破坏现有接口和对象的用户的情况下向这个对象添加一个名为 M3 的新方法。正确的解决方案是添加一个新接口。为方便起见,可以直接继承原来的接口。
class IPublicInterface2 : public IPublicInterface
{
public:
virtual void M3() = 0;
};
现在修改类以继承这两个新的派生接口:
class MyPublicClass : public IPublicInterface2
{
public:
// IPublicInterface
void M1();
void M2();
// IPublicInterface2
void M3();
// IUnknown
HRESULT QueryInterface(...);
ULONG AddRef();
ULONG Release();
};
更新 QueryInterface 以支持对 IPublicInterface 的原始 UUID 和 IPublicInterface2 的调用。
HRESULT MyPublicClass::QueryInterface(GUID& iid, void** ppv)
{
// QI request for original interface
if ((iid == uuidof(IPublicInterface) || (iid == uuidof(IUnknown))
{
*ppv = (IPublicInterface*)this;
AddRef();
return S_OK;
}
else if (iid == uuidof(IPublicInterface2)
{
*ppv = (IPublicInterface2*)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
另外,IPublicInterface2 不需要从原始 IPublicInterface 继承。在这种情况下,实现类继承自两个接口。在 QueryInterface 实现中,您需要在处理可能的 IUnknown 模棱两可转换的方式上保持一致。