编写可复用性更好的C++代码:Band对象和COMToys(7)
2006-07-21 11:46:03 来源:WEB开发网核心提示:第一部分:Band 对象介绍第二部分:BandObj的类层次和MyBands服务程序的注册第三部分:深入Band内部,揭开Band的面纱第四部分:Band对象使用中遇到的一些问题第五部分:建立自己的COM编程平台ComToys第六部分:设计和构造COMToys第七部分 类的实现类的混合实现到目前为止,编写可复用性更好的
第一部分:Band 对象介绍
第二部分:BandObj的类层次和MyBands服务程序的注册
第三部分:深入Band内部,揭开Band的面纱
第四部分:Band对象使用中遇到的一些问题
第五部分:建立自己的COM编程平台ComToys
第六部分:设计和构造COMToys
第七部分 类的实现
类的混合实现
到目前为止,我介绍了一种用多继承代替嵌套类在MFC中实现COM对象的方法。基本思路是忽略MFC宏和接口映射,并调用GetInterfaceHook来返回接口指针。很明显,这已经使编程容易了许多,但可复用性体现在哪呢?开发COMToys的主要目的是让它具备可复用性特点来实现普通的COM接口。为此,COMToys使用了混合类。
混合类被设计成利用多继承特性与其它类混合。通常混合类与主类的关系是直交的,也就是说它提供与类层次的无关性来避免菱形派生树(请原谅我的矛盾修饰法),不用怀疑,CBandObj比我在前面四个部分中讨论的要复杂一些,其新版本的代码如下:
//更新的 CBandObj
/////////////////////////////////////////
// CBandObj —— 典型的实现多接口的 COM 类
// 头文件.h :
class CBandObj : public CWnd,
// interfaces
// public IOleWindow, // 从IDeskBand继承
// public IDockingWindow, // 从IDeskBand继承
public IDeskBand,
public IObjectWithSite,
public IInputObject,
// public IPersist, // 从IPersistStream继承
public IPersistStream,
public IContextMenu,
// 使用ComToys实现
public CTOleWindow,
public CTDockingWindow,
public CTPersist,
public CTPersistStream,
public CTInputObject,
public CTInputObjectSite,
public CTContextMenu
{
public:
CBandObj(REFCLSID clsid);
virtual ~CBandObj();
// 改写以便实现 QueryInterface
virtual LPUNKNOWN GetInterfaceHook(const void* iid);
// 用ComToys实现的接口
DECLARE_IUnknown();
DECLARE_IOleWindow();
DECLARE_IDockingWindow();
DECLARE_IInputObject();
DECLARE_IPersist();
DECLARE_IPersistStream();
DECLARE_IContextMenu();
DECLARE_IObjectWithSite();
// IDeskBand
STDMETHOD (GetBandInfo) (DWORD, DWORD, DESKBANDINFO*);
};
// 实现文件 .cpp :
CBandObj::CBandObj(REFCLSID clsid) :
// 初始化所有实现类
CTMfcComObj(this),
CTOleWindow(this),
CTDockingWindow(this),
CTPersist(clsid),
CTPersistStream(),
CTInputObject(this),
CTContextMenu(this, CTMfcComObjFactory::GetFactory(clsid)->GetResourceID())
{
......
}
//////////////////////////////////
// 这些宏用ComToys实现了所有接口
//
IMPLEMENT_IUnknown (CBandObj, CTMfcComObj);
IMPLEMENT_IOleWindow (CBandObj, CTOleWindow);
IMPLEMENT_IDockingWindow (CBandObj, CTDockingWindow);
IMPLEMENT_IPersist (CBandObj, CTPersist);
IMPLEMENT_IContextMenu (CBandObj, CTContextMenu);
IMPLEMENT_IPersistStream (CBandObj, CTPersistStream);
IMPLEMENT_IInputObject (CBandObj, CTInputObject);
/////////////////////////////////////////////////////////////////////
// 改写后旁路掉MFC在CCmdTarget::InternalQueryInterface中的接口映射
//
LPUNKNOWN CBandObj::GetInterfaceHook(const void* piid)
{
REFIID iid = *((IID*)piid);
if (iid==IID_IUnknown)
return (IDeskBand*)this;
#define IF_INTERFACE(iid, iface) \
if (iid==IID_##iface) \
return (iface*)this; \
IF_INTERFACE(iid, IOleWindow);
IF_INTERFACE(iid, IDockingWindow);
IF_INTERFACE(iid, IObjectWithSite);
IF_INTERFACE(iid, IInputObject);
IF_INTERFACE(iid, IPersist);
IF_INTERFACE(iid, IPersistStream);
IF_INTERFACE(iid, IContextMenu);
IF_INTERFACE(iid, IDeskBand);
return NULL;
}
乍一看这些类与ATL如此类似!且看下文的分析。
更多精彩
赞助商链接