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
- COM原理与实现之二: 聚合
- COM原理之包容与聚合
- <com原理>与<com内幕>的聚合实现部分。
- <com原理>与<com内幕>的聚合实现部分
- COM原理与应用中关于聚合实现的纪要
- COM聚合的实现
- COM聚合的实现
- com 聚合的实现
- COM原理与应用----COM的实现
- COM原理与应用----COM的实现
- COM原理与应用----COM的实现
- COM原理与实现之一
- ATL 实现com的聚合
- COM笔记-包容与聚合
- COM笔记-包容与聚合
- COM笔记-包容与聚合
- 重读《COM原理与应用》之二——概述(第一章)
- 数据分析与处理之二(Leveldb 实现原理)
- 软件工程系列-介绍, 软件工程的那些事
- GNU 内存对齐
- 四、触摸事件
- 【iOS程序启动与运转】- RunLoop个人小结
- 0613_弱鸡问题(2)
- COM原理与实现之二: 聚合
- Tomcat结合nginx使用案例
- (一)为什么你应该(从现在开始就)写博客
- 异常:org.hibernate.LazyInitializationException: could not initialize proxy - no Session
- 大公司都有哪些开源项目~~~阿里,百度,腾讯,360,新浪,网易,小米等
- ubuntu下安装无线网卡Broadcom802.11驱动
- 习题8-10 UVA - 1614 Hell on the Markets 奇怪的股市(贪心)
- Activity的启动流程图
- spring+mybatis学习之路之错误笔记day05