Handling Name Conflicts
接口定义有时会遇到命名冲突,例如:
interface ICowboy : IUnknown { HRESULT Draw(); }; interface IArtist : IUnknown { HRESULT Draw(); };
// Ace Powell was a cowboy/artist who lived in the western US // from 1912 to his death in 1978. I'd like to thank Tim Ewald // for this fabulous example, which I have used to death // for years. class CAcePowell : public CComObjectRootEx<CComSingleThreadModel>, public ICowboy, public IArtist { public: BEGIN_COM_MAP(CAcePowell) COM_INTERFACE_ENTRY(ICowboy) COM_INTERFACE_ENTRY(IArtist) END_COM_MAP() ... STDMETHODIMP Draw() { /* Act as a cowboy or an artist? */ } };
上述代码中,Draw()不同的接口表现完全不同
微软解决方案
class CAcePowell : public CComObjectRootEx<CComSingleThreadModel>, public ICowboy, public IArtist { public: BEGIN_COM_MAP(CAcePowell) COM_INTERFACE_ENTRY(ICowboy) COM_INTERFACE_ENTRY(IArtist) END_COM_MAP() ... STDMETHODIMP IArtist::Draw() { /* Draw like an artist */ return S_OK; } STDMETHODIMP ICowboy::Draw() { /* Draw like a cowboy */ return S_OK; } };
上述代码只能用在头文件中,而且并非标准cpp,只能用在微软编译器
forwarding shims解决方案
struct _IArtist : public IArtist { STDMETHODIMP Draw() { return ArtistDraw(); } STDMETHOD(ArtistDraw)() =0; }; struct _ICowboy : public ICowboy { STDMETHODIMP Draw() { return CowboyDraw(); } STDMETHOD(CowboyDraw)() =0; };
_IArtist和_ICowboy被称为shim class
class CAcePowell : public CComObjectRootEx<CComSingleThreadModel>, public _ICowboy, public _IArtist { public: BEGIN_COM_MAP(CAcePowell) COM_INTERFACE_ENTRY(ICowboy) COM_INTERFACE_ENTRY(IArtist) END_COM_MAP() ... STDMETHODIMP ArtistDraw(); STDMETHODIMP CowboyDraw(); };
上述代码使用额外的vtable来解决问题,如果不想要这个负担,例子:
template <typename Deriving> struct ATL_NO_VTABLE _IArtist : public IArtist { STDMETHODIMP Draw() { return static_cast<Deriving*>(this)->ArtistDraw(); } }; template <typename Deriving> struct ATL_NO_VTABLE _ICowboy : public ICowboy { STDMETHODIMP Draw() { return static_cast<Deriving*>(this)->CowboyDraw(); } }; class ATL_NO_VTABLE CAcePowell : public CComObjectRootEx<CComSingleThreadModel>, public _ICowboy<CAcePowell>, public _IArtist<CAcePowell> { public: BEGIN_COM_MAP(CAcePowell) COM_INTERFACE_ENTRY(ICowboy) COM_INTERFACE_ENTRY(IArtist) END_COM_MAP() ... HRESULT ArtistDraw(); HRESULT CowboyDraw(); };
下面的代码是错误的:
template <typename Deriving> struct ATL_NO_VTABLE _ICowboy : public ICowboy { STDMETHODIMP Draw() { return static_cast<Deriving*>(this)->CowboyDraw(); } }; class ATL_NO_VTABLE CAcePowell : public CComObjectRootEx<CComSingleThreadModel>, public _ICowboy<CAcePowell>, public IArtist { public: BEGIN_COM_MAP(CAcePowell) COM_INTERFACE_ENTRY(ICowboy) COM_INTERFACE_ENTRY(IArtist) END_COM_MAP() ... HRESULT Draw(); // Use for both IArtist::Draw and // ICowboy::Draw HRESULT CowboyDraw(); // Never called! };
Interface Coloring
利用CPP的漏洞,统计各个接口的调用,在ATL7中已经为_ALT_DEBUG_INTERFACES所实现