COM原理与实现之二: 聚合

来源:互联网 发布:域名注册备案 编辑:程序博客网 时间:2024/04/28 21:22

COM原理与实现之二: 聚合


C++没有同聚合等价的特性。聚合实际上是继承性的一种动态形式。而C++的继承总是静态的,是实现继承。COM是接口继承,通过聚合接口,可以做成动态配置。

研究COM,主要是利用接口继承的灵活性构筑强大的系统:可配置、可插拔、可脚本化。本文不讲太多理论,详细原理参考[COM技术内幕]这本书。关于[COM技术内幕],很多内容过时了,比如注册表,类厂之类的。我更关心COM思想所蕴含的哲学。我实现了跨平台COM,支持聚合。


GameStencil这个组件聚合了SystemMngmt这个组件。最初采用IGameStencil::getSystemMngmt()这样的形式返回一个ISystemMngmt接口指针,显然这不是聚合。通过A对象的方法得到B对象,显然A仅仅是B的一种类厂。于是我下决心解决组件聚合问题。就有了本文。


core目录下面就3个文件,是我的跨平台COM的基础。

1) Platform.h

/*** Platform.h*** Init Created: 2016-06-10* Last Updated: 2016-06-10*/#ifndef PLATFORM_H#define PLATFORM_H#if defined _MSC_VER || WIN32    #ifndef OS_PLATFORM_WIN        #define OS_PLATFORM_WIN    #endif  #endif#ifdef OS_PLATFORM_WIN    #include <windows.h>    #include <process.h>#else    #include <pthread.h>    #include <unistd.h>#endif#ifndef interface#define interface struct#endif/*** interface iid*/typedef unsigned int iid_t;/*** long result*/typedef long lresult_t;#define lres_success             0#define lres_error             (-1)#define lres_e_initdata        (-2)#define lres_e_outmemory       (-4)#define lres_e_nointerface     (-11)#define lres_e_noaggregation   (-12)/*** thread_ctx*/#define thread_ctx_single    0#define thread_ctx_multiple  1/*** ref count type*/#ifdef OS_PLATFORM_WIN    typedef volatile unsigned long refcount_t;    #define __interlock_inc(add)  InterlockedIncrement(add)    #define __interlock_dec(sub)  InterlockedDecrement(sub)#else    typedef volatile size_t refcount_t;    #define __interlock_inc(add)  __sync_add_and_fetch(add, 1)    #define __interlock_dec(sub)  __sync_sub_and_fetch(sub, 1)#endif#endif /* PLATFORM_H */

2) Universal.h

/*** Universal.h* * Refer:*   <<Inside COM>>** Init Created: 2016-06-10* Last Updated: 2016-06-13*/#ifndef UNIVERSAL_H#define UNIVERSAL_H#include "Platform.h"// IUniversal is a variant from IUnknown//interface IUniversal{    static const iid_t IID = ((iid_t) (0));    virtual lresult_t query(iid_t iid, void **ppvOut) = 0;    virtual unsigned long retain(void) = 0;    virtual unsigned long release(void) = 0;};#define iid_IUniversal  (IUniversal::IID)// Nondelegating IUniversal interface //   - Nondelegating version of IUniversal// interface INondelegatingUniversal{    static const iid_t IID = ((iid_t) (-1));    virtual lresult_t NondelegatingQuery(iid_t iid, void **ppvOut) = 0;    virtual unsigned long NondelegatingRetain(void) = 0;    virtual unsigned long NondelegatingRelease(void) = 0;};#define iid_INondelegatingUniversal  (INondelegatingUniversal::IID)class UniversalImpl{private:    unsigned  thread_ctx;    refcount_t  ref_count;public:    UniversalImpl() :        ref_count(1),        thread_ctx(thread_ctx_multiple) {        printf("UniversalImpl\n");    }    virtual ~UniversalImpl() {        printf("~UniversalImpl\n");    }    void init(unsigned threadctx) {        thread_ctx = threadctx;    }    // Notification to derived classes that we are releasing     void finalRelease() {        // Increment reference count for final release        ref_count = 1;    }    unsigned getThreadCtx() const {        return thread_ctx;    }    // IUniversal    //    virtual lresult_t query(iid_t iid, void **ppv) = 0;    virtual unsigned long retain(void) {        if (thread_ctx == thread_ctx_multiple) {            return __interlock_inc(&ref_count);        } else {            return ++ref_count;        }    }    virtual unsigned long release(void) {        if (thread_ctx == thread_ctx_multiple) {            if (__interlock_dec(&ref_count) == 0) {                delete this;                return 0;            }        } else {            if (--ref_count == 0) {                delete this;                return 0;            }        }        return ref_count;    }};// Declaration of NondelegatingUniversalImpl//   - Base class for implementing INondelegatingUniversal//class NondelegatingUniversalImpl : public INondelegatingUniversal{public:    virtual lresult_t NondelegatingQuery(iid_t iid, void **ppv) = 0;    virtual unsigned long NondelegatingRetain(void) {        if (thread_ctx == thread_ctx_multiple) {            return __interlock_inc(&ref_count);        } else {            return ++ref_count;        }    }    virtual unsigned long NondelegatingRelease(void) {        if (thread_ctx == thread_ctx_multiple) {            if (__interlock_dec(&ref_count) == 0) {                delete this;                return 0;            }        } else {            if (--ref_count == 0) {                delete this;                return 0;            }        }        return ref_count;    }    // Constructor     NondelegatingUniversalImpl(IUniversal* pUniversalOuter) :            ref_count(1) {        // Set outer_universal pointer        if (! pUniversalOuter) {            // Not aggregating; delegate to nondelegating IUniversal            m_pUniversalOuter = reinterpret_cast<IUniversal*>                (static_cast<INondelegatingUniversal*>                (this));        } else {            // Aggregating; delegate to outer IUniversal            m_pUniversalOuter = pUniversalOuter;        }    }    // Destructor     virtual ~NondelegatingUniversalImpl() {    }    // Initialization (especially for aggregates)     void init(unsigned threadctx) {        thread_ctx = threadctx;    }    // Notification to derived classes that we are releasing     virtual void finalRelease() {        // Increment reference count for final release        ref_count = 1;    }protected:    // Support for delegation     IUniversal* getUniversalOuter() const {        return m_pUniversalOuter;    }private:    // thread context    unsigned thread_ctx;    // Reference count for this object    refcount_t  ref_count;    // Pointer to (external) outer IUniversal    IUniversal* m_pUniversalOuter;};/////////////////////////////////////////////////////////// // // Delegating IUniversal //   - Delegates to the nondelegating IUniversal, or to the //      outer IUniversal if the component is aggregated. // #define DECLARE_UNIVERSAL_INTERFACE \    virtual lresult_t query(iid_t iid, void **ppv) { \        return getUniversalOuter()->query(iid, ppv); \    } \    virtual unsigned long retain(void) { \        return getUniversalOuter()->retain(); \    } \    virtual unsigned long release(void) { \        return getUniversalOuter()->release(); \    }#define CREATE_INSTANCE_NO_AGGREGATION(className) \    static lresult_t createInstance(\            unsigned threadctx,\            IUniversal *pUniversalOuter,\            iid_t iid,\            void **ppv) {\        /* cannot be aggregated */ \        if (pUniversalOuter) {\            return lres_e_noaggregation; \        } \        className * p = new className();\        if ( ! p) {\            return lres_e_outmemory;\        }\        lresult_t hr = p->init(threadctx);\        if (hr != lres_success) {\            p->NondelegatingRelease();\            return hr;\        }\        hr = p->NondelegatingQuery(iid, ppv);\        p->NondelegatingRelease();\        return hr;\    }#define CREATE_INSTANCE_WITH_AGGREGATION(className) \    static lresult_t createInstance(\            unsigned threadctx,\            IUniversal* pUniversalOuter,\            iid_t iid,\            void **ppv) {\        className * p = new className(pUniversalOuter);\        if ( ! p) {\            return lres_e_outmemory;\        }\        lresult_t hr = p->init(threadctx);\        if (hr != lres_success) {\            p->release();\            return hr;\        }\        hr = p->NondelegatingQuery(iid, ppv);\        p->NondelegatingRelease();\        return hr;\    }#endif /* UNIVERSAL_H */

3)SIPtr.h

/*** SIPtr.h*    Smart Interface Pointer** Use: SIPtr<IX> spIX;*     Do not use with IUniversal; SIPtr<IUniversal>*       will not compile.  Instead, use IUniversalPtr. ** Refer:*   <<Inside COM>>** Init Created: 2016-06-10* Last Updated: 2016-06-10*/#ifndef SIPTR_H#define SIPTR_H#include "Universal.h"#include <assert.h>template <class T> class SIPtr{public:    // Constructors    SIPtr() {        m_pI = 0;    }    SIPtr(T* lp) {        m_pI = lp;        if ( m_pI ) {            m_pI->retain();        }    }    SIPtr(IUniversal* pI) {        m_pI = 0;        if ( pI ) {            pI->query(T::IID, (void **) & m_pI);        }    }    // Destructor    ~SIPtr() {        release();    }    // Reset    void release() {        if ( m_pI ) {            T* pOld = m_pI;            m_pI = 0;            pOld->release();        }    }    // Attach to an existing interface (does not retain)    void attach(T * pI) {        if (m_pI != pI) {            IUniversal* pOld = m_pI;            m_pI = pI;            if (pOld) {                // Release the old interface                pOld->release();            }        }    }    // Detach the interface (does not release)    T* detach() {        T* pOld = m_pI;        m_pI = 0;        return pOld;    }    T* get() {        return m_pI;    }    // Conversion    operator T*() {        return m_pI;    }    // Pointer operations    T& operator*() {        assert(m_pI);        return * m_pI;    }    T** operator&() {        assert(!m_pI);        return &m_pI;    }    T* operator->() {        assert(m_pI);        return m_pI;    }    // Assignment from the same interface    T* operator=(T* pI) {        if (m_pI != pI) {            // Save current value            IUniversal* pOld = (IUniversal *) m_pI;            // Assign new value            m_pI = pI;            if (m_pI) {                m_pI->retain();            }            if (pOld) {                // Release the old interface                pOld->release();            }        }        return m_pI;    }    // Assignment from another interface    T* operator=(IUniversal* pI) {        // Save current value        IUniversal* pOld = m_pI;        m_pI = 0;        // Query for correct interface        if ( pI ) {            lresult_t hr = pI->query(T::iid_interface, (void**) & m_pI);            assert(hr == lres_success && m_pI);        }        if ( pOld ) {            // Release old pointer            pOld->release();        }         return m_pI ;     }     // bool functions     bool operator!() {        return m_pI ? false : true;    }    // Requires a compiler that supports BOOL    operator bool() const {        return m_pI ? true : false;    }    // Interface ID    iid_t iid() {        return T::IID;    } private:     // Pointer variable     T* m_pI;};/*** IUniversalPtr is a smart interface for IUniversal*/class IUniversalPtr{public:    // Constructors    IUniversalPtr() {        m_pI = 0;    }    IUniversalPtr(IUniversal* lp) {        m_pI = lp;        if ( m_pI ) {            m_pI->retain();        }    }    // Destructor    ~IUniversalPtr() {        release();    }    // Reset    void release() {        if (m_pI) {            IUniversal* pOld = m_pI;            m_pI = 0;            pOld->release();        }    }    // Conversion    operator IUniversal*() {        return (IUniversal*) m_pI;    }    // Pointer operations    IUniversal& operator*() {        assert(m_pI);        return *m_pI;    }    IUniversal** operator&() {        assert(!m_pI);        return &m_pI;    }    IUniversal* operator->() {        assert(m_pI);        return m_pI;    }    // Assignment    IUniversal* operator=(IUniversal* pI) {        if (m_pI != pI) {            // Save current value            IUniversal* pOld = m_pI;            // Assign new value            m_pI = pI;            if ( m_pI ) {                m_pI->retain();            }            if ( pOld ) {                // Release the old interface                pOld->release();            }        }        return m_pI;    }    // Boolean functions     bool operator!() {        return m_pI ? false : true;    }    operator bool() const {        return m_pI ? true : false;    }private:    // Pointer variable    IUniversal* m_pI;}; #endif /* SIPTR_H */

组件 GameStencil的代码:

/*** IGameStencil.h** Author: master@pepstack.com** Refer:*   http://www.richardlord.net/blog/what-is-an-entity-framework*   http://blog.csdn.net/i_dovelemon/article/details/30250049*   http://blog.csdn.net/zhao_92221/article/details/46629553*   http://blog.csdn.net/ubuntu64fan/article/details/8839778** Init Created: 2016-06-13* Last Updated: 2016-06-13*/#ifndef IGAME_STENCIL_H#define IGAME_STENCIL_H#include "core/SIPtr.h"namespace ecs {interface IGameStencil : IUniversal {    static const iid_t IID = ((iid_t) 0x00F000);    virtual void update(float dt) = 0;};}; /* namespace ecs */#endif /* IGAME_STENCIL_H */

/*** GameStencil.h*   The GameStencil class is the central point for creating*     and managing your game state.** Refer:*   http://www.richardlord.net/blog/what-is-an-entity-framework*   http://blog.csdn.net/i_dovelemon/article/details/30250049*   http://blog.csdn.net/zhao_92221/article/details/46629553*   http://blog.csdn.net/ubuntu64fan/article/details/8839778** Init Created: 2016-06-12* Last Updated: 2016-06-12*/#ifndef GAME_STENCIL_H#define GAME_STENCIL_H#include "IGameStencil.h"#include "SystemMngmt.h"#include <memory>#include <vector>using namespace std;namespace ecs {class GameStencil :    public IGameStencil,    public NondelegatingUniversalImpl   {public:    // Creation    //    CREATE_INSTANCE_NO_AGGREGATION(GameStencil)private:    // Constructor    GameStencil() :        NondelegatingUniversalImpl(0),        updating(false),        m_pUniversalInner(0) {        printf("GameStencil\n");        m_pISystemMngmt = 0;    }    // Destructor    virtual ~GameStencil() {        finalRelease();        printf("~GameStencil\n");    }// Initialization    //virtual lresult_t init(unsigned threadctx) {        NondelegatingUniversalImpl::init(threadctx);        IUniversal * pUniversalOuter = this;        lresult_t hr = SystemMngmt::createInstance(threadctx, pUniversalOuter,            IUniversal::IID, (void**) &m_pUniversalInner);        if (hr != lres_success) {            return lres_error;        }        hr = m_pUniversalInner->query(ISystemMngmt::IID, (void**) &m_pISystemMngmt);        if (hr != lres_success) {            m_pUniversalInner->release();            return lres_error;        }        pUniversalOuter->release();        return lres_success;    }    virtual void finalRelease() {        NondelegatingUniversalImpl::finalRelease();        getUniversalOuter()->retain();        m_pISystemMngmt->release();        if (m_pUniversalInner) {            m_pUniversalInner->release();        }    }    // IUniversal    //    DECLARE_UNIVERSAL_INTERFACE    // INondelegatingUniversal    //virtual lresult_t NondelegatingQuery(iid_t iid, void** ppv) {        if (iid == IUniversal::IID) {            *ppv = static_cast<IGameStencil*> (this);        } else if (iid == IGameStencil::IID) {            *ppv = static_cast<IGameStencil*> (this);        } else if (iid == ISystemMngmt::IID) {            // contained component            *ppv = m_pISystemMngmt;        } else {            *ppv = 0;            return lres_e_nointerface;        }        reinterpret_cast<IUniversal*> (*ppv)->retain();        return lres_success;    }     // IGameStencil    //    virtual void update(float dt) {        updating = true;        // TODO:        updating = false;    }private:    bool updating;    IUniversal * m_pUniversalInner;    ISystemMngmt * m_pISystemMngmt;};}; /* namespace ecs */#endif /* GAME_STENCIL_H */


被聚合的组件 SystemMngmt的代码:

/*** ISystemMngmt.h** Author: master@pepstack.com** Refer:*   http://www.richardlord.net/blog/what-is-an-entity-framework*   http://blog.csdn.net/i_dovelemon/article/details/30250049*   http://blog.csdn.net/zhao_92221/article/details/46629553*   http://blog.csdn.net/ubuntu64fan/article/details/8839778** Init Created: 2016-06-10* Last Updated: 2016-06-12*/#ifndef ISYSTEM_MNGMT_H#define ISYSTEM_MNGMT_H#include "core/SIPtr.h"namespace ecs {interface ISystemMngmt : IUniversal{    static const iid_t IID = ((iid_t) 0x10F001);    virtual void update(float dt) = 0;    virtual void pause() = 0;    virtual void resume() = 0;};}; /* namespace ecs */#endif /* ISYSTEM_MNGMT_H */

/*** SystemMngmt.h** Refer:*   http://www.richardlord.net/blog/what-is-an-entity-framework*   http://blog.csdn.net/i_dovelemon/article/details/30250049*   http://blog.csdn.net/zhao_92221/article/details/46629553*   http://blog.csdn.net/ubuntu64fan/article/details/8839778** Init Created: 2016-06-13* Last Updated: 2016-06-13*/#ifndef SYSTEM_MNGMT_H#define SYSTEM_MNGMT_H#include "ISystemMngmt.h"#include <memory>#include <vector>using namespace std;namespace ecs {class SystemMngmt :    public ISystemMngmt,    public NondelegatingUniversalImpl{public:    // Creation    //CREATE_INSTANCE_WITH_AGGREGATION(SystemMngmt)private:// Constructor     SystemMngmt(IUniversal * pUniversalOuter) :        NondelegatingUniversalImpl(pUniversalOuter) {        paused = false;        printf("SystemMngmt\n");    }    // Destructor    virtual ~SystemMngmt() {        finalRelease();        printf("~SystemMngmt\n");    }    virtual lresult_t init(unsigned threadctx) {        NondelegatingUniversalImpl::init(threadctx);        return lres_success;    }public:    // IUniversal    //    DECLARE_UNIVERSAL_INTERFACE    // INondelegatingUniversal    //virtual lresult_t NondelegatingQuery(iid_t iid, void** ppv) {        if (iid == IUniversal::IID) {            *ppv = static_cast<INondelegatingUniversal*> (this);        } else if (iid == ISystemMngmt::IID) {            *ppv = static_cast<ISystemMngmt*> (this);        } else {            *ppv = 0;            return lres_e_nointerface;        }        reinterpret_cast<IUniversal*> (*ppv)->retain();        return lres_success;    }     // ISystemMngmt    //    // Update all the system    void update(float dt) {    }    // Pause all the systems    void pause() {        paused = true;    }    // Resume all the systems    void resume() {        paused = false;    }private:    bool paused;};}; /* namespace ecs */#endif /* SYSTEM_MNGMT_H */

最后是测试代码:

//// main.cpp//#ifdef WIN32    // Refer:    //   http ://www.cnblogs.com/skynet/archive/2011/02/20/1959162.html    #define _CRTDBG_MAP_ALLOC    #include <stdlib.h>    #include <crtdbg.h>#else    #include <stdlib.h>#endif#include <assert.h>#include <stdio.h>#include <string.h>#include "model/GameStencil.h"using namespace ecs;void usage(){    SIPtr<IGameStencil> spGame;    GameStencil::createInstance(thread_ctx_single, 0, spGame.iid(), (void**) &spGame);    SIPtr<ISystemMngmt> spSysMngmt;    spGame->query(spSysMngmt.iid(), (void**) &spSysMngmt);    SIPtr<IGameStencil> spGame2;    spSysMngmt->query(spGame2.iid(), (void**) &spGame2);    assert(spGame2.get() == spGame.get());    spSysMngmt->update(0.1f);}int main(){#ifdef _CRTDBG_MAP_ALLOC    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);#endif    printf("main.cpp start\n");    usage();    printf("main.cpp exit.\n");    return 0;}

没有内存泄露。OK!


0 0
原创粉丝点击