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. [AHOI2012]树屋阶梯

    题目描述 输入输出格式 输入格式: 一个正整数N(1<=N<=500),表示阶梯的高度. 输出格式: 一个正整数,表示搭建方法的个数.(注:搭建方法的个数可能很大) 输入输出样例 输入样例 ...

  2. codeforces 842C Ilya And The Tree

    Ilya is very fond of graphs, especially trees. During his last trip to the forest Ilya found a very ...

  3. 【HNOI2017】影魔

    题目描述 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄. 每一个灵魂,都有着自 ...

  4. UOJ #30. 【CF Round #278】Tourists

    Description Cyberland 有 n 座城市,编号从 1 到 n,有 m 条双向道路连接这些城市.第 j 条路连接城市 aj 和 bj.每天,都有成千上万的游客来到 Cyberland ...

  5. 例10-10 uva10491(简单概率)

    题意: 在a+b扇门,a扇后面是牛,b扇后面是车.在你选择一扇门后,主持人为你打开另外c扇门,然后你再选一扇, 求是车的概率 ①先选牛:a/(a+b),然后还剩a+b-c-1扇门,其中b扇为车,所以a ...

  6. hdu 2888 二维RMQ模板题

    Check Corners Time Limit: 2000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  7. [APIO/ctsc2007]

    A.风铃 给一棵二叉树,叶子结点是玩具,为使你的弟弟满意,你需要选一个满足下面两个条件的风铃: (1) 所有的玩具都在同一层(也就是说,每个玩具到天花板之间的杆的个数是一样的)或至多相差一层.(2) ...

  8. Python开发——排队问题随机模拟分析

    案例:主要是基于"蒙特卡罗思想",求解排队等待时间问题 场景:厕所排队问题 1.两场电影结束时间相隔较长,互不影响: 2.每场电影结束之后会有20个人想上厕所: 3.这20个人会在 ...

  9. HTML标签部分(块级/行级)

    一.基本块级标签 1.HTML标签的分类:      a.块级标签:显示为块状,独占一行,自动换行.      b.行级标签:在一行中,从左往右依次排列,不会自动换行. 2.h标签(标题标签) h标签 ...

  10. 关于centos版本安装ethereum钱包

    安装go wget https://studygolang.com/dl/golang/go1.9.linux-amd64.tar.gz --no-check-certificatetar -zxvf ...