1、你可能忘记进行引用计数或者忘记释放某个组件上接口的指针。
2、即使你在该调用Release的时候调用了它,在程序中却不一定会真正调用它,因为发生异常后C++的异常处理程序不会调用Release以释放此COM组件。
3、一对QueryInterface调用极易使函数中有用的代码黯然失色。
4、其次,QueryInterface不是类型安全的,原因在于(void**)。例如:
IZ* pIZ;
pIX->QueryInterface(IID_IY,(void**)&pIZ);
虽然将一个IY接口指针赋给了一个IZ接口指针,但编译仍然会通过。
为解决以上问题,可以通过封装来解决。一种方法是:使用智能指针类来封装接口指针。另一种方法是通过包装类对接口本身进行封装。
一:智能接口指针:
智能接口指针将把引用计数这类细节隐藏起来,并且当程序的执行离开了智能接口指针的作用域后,相应的接口将被释放掉。一个智能指针实际上就是一个重载了操作符->的类。智能接口指针类包含指向另外一个对象的指针。当用户调用智能指针上的->操作符时,智能指针把此调用转发给它所包含的指针所指的对象。包含的指针将是指向一个接口的。
A simple example:
class CFoo{
public:
virtual void Bar();
};
class CFooPointer{
public:
CFooPointer(CFoo* p){m_p = p;}
CFoo* operator ->(){return m_p;}
private:
CFoo *m_p;
};
.......
void Funky(CFoo* pFoo){
CFooPointer spFoo(pFoo);
spFoo->Bar();
}
//实现一个接口指针类IPtr:
template <class T,const IID* piid>
class IPtr{
public:
IPtr(){ m_pI = NULL;}
IPtr(T* lp){
m_pI = lp;
if(m_pI != NULL) m_pI->AddRef();
}
IPtr(IUnknown* pI){
m_pI = NULL;
if(pI != NULL){
pI->QueryInterface(*piid,(void**)&m_pI);
}
}
~IPtr(){Release();}
void Release(){
if(m_pI != NULL){
T* pOld = m_pI;
m_pI = NULL;
pOld->Release();
}
}
operator T*(){ return m_pI; }
T& operator*(){assert(m_pI != NULL); return *m_pI;}
T** operator&(){assert(m_pI != NULL); return &m_pI;}
T* operator->(){assert(m_pIY != NULL); return m_pI};
T* operator=(T* pI){
if(m_pI != pI){
IUnknown* pOld = m_pI;
m_pI = pI;
if(m_pI != NULL){
m_pI -> AddRef();
}
if(pOld != NULL){
pOld->Release();
}
return m_pI;
}
T* operator = (IUnknown* pI){
IUnknown* pOld = m_pI;
m_pI = NULL;
if(pI != NULL){
HRESULT hr = pI->QueryInterface(*piid,(void**)&m_pI);
assert(SUCCEEDED(hr) && (m_pI != NULL));
}
if(pOld != NULL){
pOld->Release();
}
return m_pI;
}
BOOL operator ! (){
return (m_pI == NULL)?TRUE:FALSE;
}
const IID& iid(){
return *piid;
}
private:
T* m_pI;
};
//test
void main(){
IPtr<IX,&IID_IX> spIX;
HRESULT hr = ::CoCreateInstance(CLSID_COMPONENT1, NULL, CLSCTX_ALL,spIX.iid() ,(void**)&spIX);
if(SUCCEEDED(hr)){
spIX->Fx();
}
}
//test
void Fuzzy(IX* pIX1,IX* pIX2){
IPtr<IX,IID_IX> spIX;
spIX = pIX1;
spIX->Fx();
spIX = pIX2;
spIX->Fx();
}
//test.转换操作符,将一个IPtr对象赋给同类型的另一个IPtr对象。
typedef IPtr<IX,IID_IX> SPIX;
SPIX g_spIX;
void Wuzzy(SPIX spIX){
g_spIX = spIX;
}
//test.将另外一个不同类型的接口指针赋给一个智能指针,赋值操作符将自动调用QueryInterface。
void WsaABear(IY* pIY){
IPtr<IX,IID_IX> spIX;
spIX = pIY;
if(spIX) spIX->Fx();
}