接口思想如图所示(途中有些内容在下面介绍)
// Interface.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "objbase.h" //接口定义 interface IMath { public: virtual int Add( int nAdd1, int nAdd2 ) = 0; virtual int Sub( int nSub1, int nSub2 ) = 0; }; //接口的实现1 class CImpMath1 : public IMath { public: virtual int Add( int nAdd1, int nAdd2 ); virtual int Sub( int nSub1, int nSub2 ); }; int CImpMath1::Add( int nAdd1, int nAdd2 ) { return ( nAdd1 + nAdd2 ); } int CImpMath1::Sub( int nSub1, int nSub2 ) { return ( nSub1 - nSub2 ); } //接口的实现2 class CImpMath2 : public IMath { public: virtual int Add( int nAdd1, int nAdd2 ); virtual int Sub( int nSub1, int nSub2 ); }; int CImpMath2::Add( int nAdd1, int nAdd2 ) { return ( nAdd1 + nAdd2 ); } int CImpMath2::Sub( int nSub1, int nSub2 ) { return ( nSub1 - nSub2 ); } //创建接口 IMath * CreateInstance( ) { return new CImpMath2; } int main(int argc, char* argv[]) { IMath * piMath = CreateInstance( ); int nAdd = piMath->Add( 100, 100 ); return 0; }
新增一个抽象结构体(或者抽象类)接口n,然后让负责功能实现的子类以多继承的方式继承n,并实现n的虚函数功能
但创建接口函数只能创建一种接口,新增的接口如何获取,这就需要接口查询函数(在各个接口中定义,在功能子类中实现),QueryInterface
接口声明
#ifndef _MATH_H_ #define _MATH_H_ #include "objbase.h" // {9080F9E3-19B6-4fe7-B47A-47431C3D35BE} static const GUID IID_IBase = { 0x9080f9e3, 0x19b6, 0x4fe7, { 0xb4, 0x7a, 0x47, 0x43, 0x1c, 0x3d, 0x35, 0xbe } }; interface IBase { public: virtual int AddRef( ) = 0; virtual int Release( ) = 0; virtual int QueryInterface( GUID iid, void ** ppiInterface ) = 0; }; //定义接口 // {B188B6AC-4DE6-4776-97B7-FB1F3C7BA102} static const GUID IID_IMath = { 0xb188b6ac, 0x4de6, 0x4776, { 0x97, 0xb7, 0xfb, 0x1f, 0x3c, 0x7b, 0xa1, 0x2 } }; interface IMath : IBase { public: virtual int Add( int nAdd1, int nAdd2 ) = 0; virtual int Sub( int nSub1, int nSub2 ) = 0; }; // {1A8B9047-F601-4b98-9383-86D78D94134A} static const GUID IID_IMath2 = { 0x1a8b9047, 0xf601, 0x4b98, { 0x93, 0x83, 0x86, 0xd7, 0x8d, 0x94, 0x13, 0x4a } }; interface IMath2 : IBase { public: virtual int Mud( int nMud1, int nMud2 ) = 0; virtual int Div( int nDiv1, int nDiv2 ) = 0; }; #endif //_MATH_H_接口实现
// DllInterface.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" #include "math.h" BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } //接口的实现1 class CMath : public IMath, public IMath2 { public: CMath( ); virtual int AddRef( ); virtual int Release( ); virtual int QueryInterface( GUID iid, void ** ppiInterface ); virtual int Add( int nAdd1, int nAdd2 ); virtual int Sub( int nSub1, int nSub2 ); virtual int Mud( int nMud1, int nMud2 ); virtual int Div( int nDiv1, int nDiv2 ); public: LONG m_nRef; //引用计数 }; CMath::CMath( ) { m_nRef = 0; } int CMath::AddRef( ) { InterlockedIncrement( &m_nRef ); //增加引用计数 return m_nRef; } int CMath::Release( ) { InterlockedDecrement( &m_nRef ); //减少引用计数 //如果为0,删除对象 if( m_nRef == 0 ) { delete this; } return m_nRef; } int CMath::QueryInterface( GUID iid, void ** ppiInterface ) { if( iid == IID_IMath ) { *ppiInterface = static_cast<IMath *>(this); AddRef( ); } else if( iid == IID_IMath2 ) { *ppiInterface = static_cast<IMath2 *>(this); AddRef( ); } else if( iid == IID_IBase ) { *ppiInterface = static_cast<IMath *>(this); AddRef( ); } return 0; } int CMath::Add( int nAdd1, int nAdd2 ) { return ( nAdd1 + nAdd2 ); } int CMath::Sub( int nSub1, int nSub2 ) { return ( nSub1 - nSub2 ); } int CMath::Mud( int nMud1, int nMud2 ) { return ( nMud1 * nMud2 ); } int CMath::Div( int nDiv1, int nDiv2 ) { return ( nDiv1/nDiv2 ); } //创建接口 IMath * CreateInstance( ) { IMath * piMath = new CMath; piMath->AddRef( ); return piMath; }接口使用
// UseDll.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "../DllInterface/math.h" typedef IMath * ( * CREATEINSTANCE)( ); IMath * CreateInterface( ) { //加载动态库 HMODULE hDll = ( HMODULE ) LoadLibrary( "DllInterface.dll" ); //获取创建接口的函数 CREATEINSTANCE CreateInstance = (CREATEINSTANCE)GetProcAddress( hDll, "CreateInstance" ); //创建接口 IMath * piMath = CreateInstance( ); //返回接口 return piMath; } int main(int argc, char* argv[]) { //创建接口 IMath * piMath = CreateInterface( ); //使用接口 int nAdd = piMath->Add( 100, 100 ); printf( "%d\n", nAdd ); /* 无法转换 IMath2 * p = (IMath2 *)piMath; int nMud2 = p->Mud( 100, 100 ); printf( "Mud2: %d\n", nMud2 ); */ //通过查询函数获取IMath2接口 IMath2 * piMath2 = NULL; piMath->QueryInterface( IID_IMath2, (LPVOID *)&piMath2 ); //减少引用计数 piMath->Release( ); int nMud = piMath2->Mud( 100, 100 ); printf( "Mud: %d\n", nMud ); piMath2->Release( ); return 0; }
所以以后定义接口时,都要直接或间接的继承IUnknown 接口(上面例子中的IBase就扮演者IUnknow的角色,微软内部已定义IUnknown 接口的GUID 为 IID_IUnknown)