COM原理与实现之一

COM原理与实现之一


COM组件其实是一种特殊的对象体系,遵循一个统一的标准,使到各个软件都可以通过某种方法访问这个对象的方法,也就可以做到组件调用。COM就是统一的标准——通过接口来调用COM组件。接口是COM组件能被外界所感知的唯一的东西。 

所有接口的接口都继承自IUnknown,实现了“接口查询”和“引用计数”。包含3个方法:

  interface   IUnknown
  {
          virtual   HRESULT   _stdcall   QueryInterface([in]REFIID iid, [out] void **ppv)=0;  
          virtual   ULONG   _stdcall   AddRef(void)=0;  
          virtual   ULONG   _stdcall   Release(void)=0;  
  }
QueryInterface负责得到该组件的其他接口的指针。
AddRef/Release负责管理该组件的生存期——引用计数+1/-1。


我实现的跨平台COM,也定义了类似IUnknown的接口,我称之为:IUniversal,定义如下:

/**
* IUniversal.h
*    IUniversal is a variant from IUnknown
*
* Refer:
*   <<Inside COM>>
*
* Init Created: 2016-06-10
* Last Updated: 2016-06-10
*/
#ifndef IUNIVERSAL_H
#define IUNIVERSAL_H

#include "Platform.h"


#define iid_IUniversal  ((iid_t)(-1))

interface IUniversal
{
    static const iid_t IID = ((iid_t) (-1));

    virtual lresult_t query(iid_t iid, void **ppvOut) = 0;
    virtual unsigned long retain(void) = 0;
    virtual unsigned long release(void) = 0;
};


class UniversalImpl
{
private:

    refcount_t  _refc;

public:
    UniversalImpl() : _refc(1) {
    }

    virtual ~UniversalImpl() {
    }

    //
    // IUniversal
    //
    virtual lresult_t query(iid_t iid, void **ppv) = 0;


    virtual unsigned long retain(void) {
        return __interlock_inc(&_refc);
    }


    virtual unsigned long release(void) {
        if (__interlock_dec(&_refc) == 0) {
            delete this;
            return 0;
        }
        return _refc;
    }
};


#endif /* IUNIVERSAL_H */

其中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_outmemory       (-4)
#define lres_e_nointerface     (-11)


/**
 * 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 */

任何一个C++对象想要成为COM,必须从IUniversal继承,并且由于 UniversalImpl 实现了一个默认的 IUniversal,所以可以直接从UniversalImpl继承过来。

例如我们定义下面一个组件Entity,其接口定义如下:

interface EntityInterface : IUniversal
{
    static const iid_t IID = ((iid_t) 0x00F001);

    virtual void addComponent(AbstractComponent * component) = 0;

    virtual void removeComponent(AbstractComponent * component) = 0;

    virtual void removeAllComponents() = 0;
};

组件 Entity 的实现如下:

/**
* Entity.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-05-30
* Last Updated: 2016-06-08
*/
#ifndef ENTITY_H
#define ENTITY_H

#include "../EntityInterface.h"

#include "../ComponentManager.h"

#include <stdio.h>
#include <assert.h>

#include "../../../common/hashmap.h"
#include "../../../common/dhlist.h"

#include <memory>
#include <vector>
using namespace std;


namespace ecs {


class EntityManager;


class Entity :
    public UniversalImpl,
    public EntityInterface
{
    friend class EntityManager;

    static const int COMPS_HASHSIZE = 0x10;

    Entity() {
        printf("Entity\n");

        INIT_LIST_HEAD(&list1_comps);

        for (int hash = 0; hash <= COMPS_HASHSIZE; hash++) {
            INIT_HLIST_HEAD(&hlist_comps[hash]);
        }
    }


public:

    virtual ~Entity() {
        printf("~Entity\n");

        removeAllComponents();
    }


public:

    // Create function
    //
    static lresult_t createInstance(EntityInterface **ppv) {
        EntityInterface * p = (EntityInterface *) new Entity();
        if (p) {
            *ppv = p;
            return lres_success;
        } else {
            *ppv = 0;
            return lres_e_outmemory;
        }
    }

    // IUniversal
    //
    virtual lresult_t query(iid_t iid, void **ppv) {
        if (iid == IUniversal::IID || iid == EntityInterface::IID) {
            *ppv = static_cast<EntityInterface *> (this);
        } else {
            *ppv = 0;
            return lres_e_nointerface;
        }
        reinterpret_cast<IUniversal*>(*ppv)->retain();
        return lres_success;
    }

    virtual unsigned long retain(void) {
        return UniversalImpl::retain();
    }

    virtual unsigned long release(void) {
        return UniversalImpl::release();
    }


    // EntityInterface
    //
    virtual void addComponent(AbstractComponent * component) {
        COMPONENT_TYPE compType = component->getComponentType();

        list_add(&component->i_list, &list1_comps);
    }


    virtual void removeComponent(AbstractComponent * component) {

    }

    virtual void removeAllComponents() {
        struct list_head *list, *node;

        list_for_each_safe(list, node, &list1_comps) {
            class AbstractComponent * p = list_entry(list, class AbstractComponent, i_list);
            list_del(list);
            delete (p);
        }
    }


private:

    struct list_head  i_list;
    struct hlist_node i_hash;

    /*
    * components list and hlist
    */
    struct list_head list1_comps;
    struct hlist_head hlist_comps[COMPS_HASHSIZE + 1];
};

}; /* namespace ecs */

#endif /* ENTITY_H */

这样一个COM系统就初具雏形。使用的时候我们还需要一个智能指针对象,辅助我们使用组件对象。我定义这个智能接口指针如下:

/**
* SIPtr.h
*    Smart Interface Pointer
*
* Use: SIPtr<IX, iidIX> spIX;
*     Do not use with IUniversal; SIPtr<IUniversal, iidIUniversal>
*       will not compile.  Instead, use IUniversalSPtr. 
*
* Refer:
*   <<Inside COM>>
*
* Init Created: 2016-06-10
* Last Updated: 2016-06-10
*/
#ifndef SIPTR_H
#define SIPTR_H

#include "IUniversal.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;
    }


    // 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 */

使用 Entity 很简单:

void testEntityInterface()
{
    SIPtr<EntityInterface>spEntity;

    Entity::createInstance(&spEntity);

    spEntity->addComponent(...);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

车斗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值