编写可复用性更好的C++代码
——Band对象和COMToys(七)
编译/赵湘宁
原着:Paul DilasciaMSJ November 1999 & December 1999
关键字:Bands 对象,Desk Bands,Info/Comm Bands,Explorer Bar,Tool Bands。
本文假设你熟悉C++,COM,IE。
下载本文源代码: MyBands.zip (128KB)
TestEditSrch.zip (75KB)
第七部分 类的实现
类的混合实现
到目前为止,我介绍了一种用多继承代替嵌套类在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; } 上一页 下一页






