我们在使用COM设计的时候,发现使用的接口都是单一的继承一个接口,比如:
MIDL_INTERFACE("000214E8-0000-0000-C000-000000000046")
IShellExtInit : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE Initialize(
/* [annotation][unique][in] */
_In_opt_ PCIDLIST_ABSOLUTE pidlFolder,
/* [annotation][unique][in] */
_In_opt_ IDataObject *pdtobj,
/* [annotation][unique][in] */
_In_opt_ HKEY hkeyProgID) = 0;
};
等等,一系列,从MSDN中看到,对接口的说明都是使用C++来定义的,而C++又是少有的可以多继承的语言,在C++中接口本质就是struct,所以实际上C++中接口可以定义一个接口继承多个接口,比如:
interface IMyInterface: public IShellExtInit, public IShellExecuteHook
{
virtual HRESULT __stdcall test(void) = 0;
};
但是我们看到的windows中定义的接口都是一个接口单一继承一个接口,我认为是从兼容其它语言的设计考虑的,比如我们在C++中定义接口的时候,都会为我们生成一个C接口定义,如下:
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("000214E8-0000-0000-C000-000000000046")
IShellExtInit : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE Initialize(
/* [annotation][unique][in] */
_In_opt_ PCIDLIST_ABSOLUTE pidlFolder,
/* [annotation][unique][in] */
_In_opt_ IDataObject *pdtobj,
/* [annotation][unique][in] */
_In_opt_ HKEY hkeyProgID) = 0;
};
#else /* C style interface */
typedef struct IShellExtInitVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IShellExtInit * This,
/* [in] */ REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
IShellExtInit * This);
ULONG ( STDMETHODCALLTYPE *Release )(
IShellExtInit * This);
HRESULT ( STDMETHODCALLTYPE *Initialize )(
IShellExtInit * This,
/* [annotation][unique][in] */
_In_opt_ PCIDLIST_ABSOLUTE pidlFolder,
/* [annotation][unique][in] */
_In_opt_ IDataObject *pdtobj,
/* [annotation][unique][in] */
_In_opt_ HKEY hkeyProgID);
END_INTERFACE
} IShellExtInitVtbl;
interface IShellExtInit
{
CONST_VTBL struct IShellExtInitVtbl *lpVtbl;
};
#endif /* C style interface */
如果按照C++定义一个接口都要自动生成一个对应的C接口,那么多继承对应生成的C接口定义会非常复杂,而且目前看,很多语言都不支持一个接口继承多个接口,仅仅支持一个类可继承多个接口,像delphi之类的语言就是这样,所以单一继承兼容性比较好,复杂度也会更低。其次,我们在设计类的时候,往往是一个类实现多个接口,而不是把单一的接口继承多个接口,相当于中间多了一个无必要的中间接口,这样设计接口会很复杂,接口的设计原则也是独立简单行,不要把接口搞的复杂。