ATL 多步构造
2011-06-14 22:31 Clingingboy 阅读(2407) 评论(0) 编辑 收藏 举报
一.FinalConstruct && FinalRelease
显然构造函数调用虚方法是有问题的
class Base {
public:
Base() { Init(); }
virtual void Init() {}
};
class Derived : public Base {
public:
virtual void Init() {}
};
分部构造的意思就是在构造函数完全初始化好之后,然后再调用初始化的一个函数,
FinalConstruct 就是这么一个函数(我只能先这么理解了,为什么是叫Init之类的方法呢) 另外一个原因是传递错误信息。
同理FinalRelease的代码本来是放在析构函数里面的,析构函数调用虚方法是同样的道理,在FinalRelease调用虚方法(在调用虚构函数之前) FinalConstruct 和FinalRelease构建了一个对象创建和销毁的一个生命周期(但不在构造函数和析构函数里面)
二.FinalConstruct 防止过早析构
即在调用方法时,可能获取其他接口,以导致减少引用,过早析构
// CPenguin implementation
HRESULT CPenguin::FinalConstruct() {
HRESULT hr;
hr = CoCreateInstance(CLSID_EarthAtmosphere, 0, CLSCTX_ALL,
IID_IAir, (void**)&m_pAir);
if( SUCCEEDED(hr) ) {
// Pass reference to object with reference count of 0
hr = m_pAir->CheckSuitability(GetUnknown());
}
return hr;
}
// CEarthAtmosphere implementation in separate server
STDMETHODIMP CEarthAtmosphere::CheckSuitability(IUnknown* punk) {
IBreatheO2* pbo2 = 0;
HRESULT hr = E_FAIL;
// CPenguin's lifetime increased to 1 via QI
hr = punk->QueryInterface(IID_IBreatheO2, (void**)&pbo2);
if( SUCCEEDED(hr) ) {
pbo2->Release(); // During this call, lifetime decreases
// to 0 and destruction sequence begins...
}
return (SUCCEEDED(hr) ? S_OK : E_FAIL);
}
三.手动添加引用计数防止析构
STDMETHODIMP
CPenguinCO::CreateInstance(IUnknown* pUnkOuter, REFIID riid,
void** ppv) {
*ppv = 0;
if( !pUnkOuter ) {
CComObject<CPenguin>* pobj = new CComObject<CPenguin>;
if( FAILED(hr) ) return E_OUTOFMEMORY;
// Protect object from pre-mature destruction
pobj->InternalAddRef();
hr = pobj->FinalConstruct();
pobj->InternalRelease();
if( SUCCEEDED(hr) ) ...
return hr;
}
...
}
四.恰当好处的引用计数
注意第二点并非绝对,是说有可能性,那么第三部就是非必要的,这两个方法定义在基类,默认为为空方法,必要时可以重载
STDMETHODIMP
CPenguinCO::CreateInstance(IUnknown* pUnkOuter, REFIID riid,
void** ppv) {
*ppv = 0;
if( !pUnkOuter ) {
CComObject<CPenguin>* pobj = new CComObject<CPenguin>;
if( FAILED(hr) ) return E_OUTOFMEMORY;
// Protect object from pre-mature destruction (maybe)
pobj->InternalFinalConstructAddRef();
hr = pobj->FinalConstruct();
pobj->InternalFinalConstructRelease();
if( SUCCEEDED(hr) ) ...
return hr;
}
...
}
五.使用DECLARE_PROTECT_FINAL_CONSTRUCT宏
为重写提供便利
#define DECLARE_PROTECT_FINAL_CONSTRUCT()\
void InternalFinalConstructAddRef() {InternalAddRef();}\
void InternalFinalConstructRelease() {InternalRelease();}
六.关于ATL_NO_VTABLE
参考这里吧:http://www.cnblogs.com/weiqubo/archive/2011/03/16/1985773.html
七.ATL框架的_AtlInitialConstruct和_AtlFinalRelease
目的相同(错误处理),但用于ATL框架的的生命周期,其初始化早于FinalConstruct