天天看點

COM學習筆記(十二):程式設計工作的簡化

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();

}

}

COM學習筆記(十二):程式設計工作的簡化

//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();

}

COM學習筆記(十二):程式設計工作的簡化
COM學習筆記(十二):程式設計工作的簡化
COM學習筆記(十二):程式設計工作的簡化
COM學習筆記(十二):程式設計工作的簡化
COM學習筆記(十二):程式設計工作的簡化

繼續閱讀