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

COM原理与实现之一的更多相关文章

  1. 奇异值分解(SVD)原理与在降维中的应用

    奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...

  2. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  3. 线性判别分析LDA原理总结

    在主成分分析(PCA)原理总结中,我们对降维算法PCA做了总结.这里我们就对另外一种经典的降维方法线性判别分析(Linear Discriminant Analysis, 以下简称LDA)做一个总结. ...

  4. [原] KVM 虚拟化原理探究(1)— overview

    KVM 虚拟化原理探究- overview 标签(空格分隔): KVM 写在前面的话 本文不介绍kvm和qemu的基本安装操作,希望读者具有一定的KVM实践经验.同时希望借此系列博客,能够对KVM底层 ...

  5. H5单页面手势滑屏切换原理

    H5单页面手势滑屏切换是采用HTML5 触摸事件(Touch) 和 CSS3动画(Transform,Transition)来实现的,效果图如下所示,本文简单说一下其实现原理和主要思路. 1.实现原理 ...

  6. .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理

    .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...

  7. python自动化测试(2)-自动化基本技术原理

    python自动化测试(2) 自动化基本技术原理 1   概述 在之前的文章里面提到过:做自动化的首要本领就是要会 透过现象看本质 ,落实到实际的IT工作中就是 透过界面看数据. 掌握上面的这样的本领 ...

  8. CRC、反码求和校验 原理分析

    3月份开始从客户端转后台,算是幸运的进入全栈工程师的修炼阶段.这段时间一边是老项目的客户端加服务器两边的维护和交接,一边是新项目加加加班赶工,期间最长经历了连续工作三天只睡了四五个小时的煎熬,人生也算 ...

  9. 菜鸟学Struts2——Struts工作原理

    在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...

  10. Objective-C中block的底层原理

    先出2个考题: 1. 上面打印的是几,captureNum2 出去作用域后是否被销毁?为什么? 同样类型的题目: 问:打印的数字为多少? 有人会回答:mutArray是captureObject方法的 ...

随机推荐

  1. [NOI2011]道路修建

    题目描述 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家 之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿 意修建恰好 n – 1 条双向道路. 每条道 ...

  2. bzoj 4894: 天赋

    Description 小明有许多潜在的天赋,他希望学习这些天赋来变得更强.正如许多游戏中一样,小明也有n种潜在的天赋,但有 一些天赋必须是要有前置天赋才能够学习得到的.也就是说,有一些天赋必须是要在 ...

  3. bzoj 4545: DQS的trie

    Description DQS的自家阳台上种着一棵颗粒饱满.颜色纯正的trie. DQS的trie非常的奇特,它初始有n0个节点,n0-1条边,每条边上有一个字符.并且,它拥有极强的生长力:某个i时刻 ...

  4. 【BZOJ3573】【HNOI2014】米特运输

    Description 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储存一直是一个大问题. D星上有N个城市,我们将其顺序编号为1到N,1号城市 ...

  5. [usaco6.1.1Postal Vans]

    来自FallDream的博客,未经允许,请勿转载,谢谢. 给你一个4*n的棋盘,问从(1,1)出发恰好经过所有格子一次的走法数量.(n<=1000) 插头dp,用f[i][j][k]表示转移到第 ...

  6. solr6.6初探之主从同步

    1.关于solr索引数据同步 通常情况下,单节点部署的solr应用很难在并发量很大的情况下"久存",那么多节点部署提高Solr应用的负载量和响应时间势在必行. solr索引同步有以 ...

  7. quartzJob 例子

    KpiOfPoorQualityJob.javapackage com.eastcom_sw.inas.workorder.quartzJob.kpi; import net.sf.json.JSON ...

  8. synchronized修饰static方法与非static方法的区别

    1. 当synchronized修饰一个static方法时,多线程下,获取的是类锁(即Class本身,注意:不是实例),作用范围是整个静态方法,作用的对象是这个类的所有对象. 2. 当synchron ...

  9. JSON.parse()在火狐中的BUG

      //用sessionStorage解决load页面刷新问题 { //sessionStorage.removeItem("loadInfo"); var loadInfo=de ...

  10. bootstrap的模态框

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...