zoukankan      html  css  js  c++  java
  • ATL 多步构造

    一.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

  • 相关阅读:
    团队开发冲刺第二阶段_1
    团队开发冲刺第一阶段_7
    mysql 官方集群
    Tomcat提高并发
    Percona XtraDB Cluster 5.7
    Mysql常用配置及优化
    Linux 常用命令
    数据库主从复制
    Linux 环境下Web环境搭建————ActiveMQ
    Linux 下Web环境搭建————redis
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2081019.html
Copyright © 2011-2022 走看看