在 COM 程式設計中,類別常需實作多個介面(如事件通知、連接點)。MFC 採用 嵌套類別 + 介面映射巨集 的方式,避免多重繼承的複雜性,並自動處理 IUnknown 的參考計數與 QueryInterface 轉發。
class CSampleView : public CView {
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(TestInterface, IMyTest)
STDMETHOD(Test)();
END_INTERFACE_PART(TestInterface)
// ...
};
BEGIN_INTERFACE_MAP(CSampleView, CCmdTarget)
INTERFACE_PART(CSampleView, IID_IMyTest, TestInterface)
END_INTERFACE_MAP()
// IUnknown 轉發至 CCmdTarget
STDMETHODIMP_(ULONG) CSampleView::XTestInterface::AddRef() {
METHOD_PROLOGUE_EX(CSampleView, TestInterface)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CSampleView::XTestInterface::Release() {
METHOD_PROLOGUE_EX(CSampleView, TestInterface)
return pThis->ExternalRelease();
}
STDMETHODIMP CSampleView::XTestInterface::QueryInterface(REFIID iid, LPVOID* ppvObj) {
METHOD_PROLOGUE_EX(CSampleView, TestInterface)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
// 介面實際方法
STDMETHODIMP CSampleView::XTestInterface::Test() {
METHOD_PROLOGUE_EX(CSampleView, TestInterface)
// 具體業務邏輯
return S_OK;
}
宣告靜態介面映射表結構 _interfaceEntries[] 與 interfaceMap,並提供虛擬函數 GetInterfaceMap() 供執行期查詢。
定義嵌套類別 XTestInterface 繼承自 IMyTest,自動包含 AddRef、Release、QueryInterface 宣告,並在外層類別產生實例成員 m_xTestInterface。
建立介面映射表陣列,每筆記錄包含 IID 與嵌套類別在外層類別中的位移(offsetof)。CCmdTarget::ExternalQueryInterface 會遞迴搜尋此表以回傳正確介面指標。
關鍵巨集:從嵌套類別的 this 計算外層類別指標 pThis。原理:pThis = (外層類別*)((BYTE*)this - offsetof(外層類別, m_x嵌套類別))。
CCmdTarget 提供 ExternalAddRef/Release/QueryInterface,嵌套類別僅需轉發。ActiveX 控制項開發、連接點事件來源、自訂 COM 物件實作多介面等。