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所实现
本文探讨了在实现多个接口时遇到的命名冲突问题,并提供了几种解决方案,包括微软特定的方法和通用的forwardingshims技巧。

被折叠的 条评论
为什么被折叠?



