COM组件多接口对象模型
COM组件有两种接口类型,Dual and Custom,如下图所示。本文说的是Custom。所谓多接口COM对象是指此COM对象实现了多于一个的自定义接口,即Custom接口。

接口图如下:

需要注意的是最终实现的COM对象用的不是虚继承而是普通的多继承,因为被多继承的IUnknown接口是不含任何数据成员,只有纯虚函数,继承的子接口也是这样。还有为了实现跨语言或平台的调用,最终没用虚继承。更多的原因请参考本文最后的链接。
这里给出多接口COM对象的模型:


很清楚地看到COM是实现了两个接口,也就是多继承子两个父接口,有两个虚函数表,其中IUnknown的三个函数指针在两个虚函数表里都各有一份。但是从我下面的打印结果来看指向的地址不太一样,不是很清楚真正的COM对象是怎么实现的。留着以后再研究吧。
示例程序。使用时会有assert dialog弹出来,直接点忽略就行了。
#include <iostream>
using namespace std; class IUnknown
{
public:
virtual long QueryInterface( long riid, void * * ppvObject) = ;
virtual long AddRef( void) = ;
virtual long Release( void) = ;
}; class IMyMath : public IUnknown
{
public:
virtual long Add(long n1, long n2, long* pVal) = ;
}; class IStr : public IUnknown
{
public:
virtual long Cat(char* _Dest, const char* _Source) = ;
}; class CMyTest: public IMyMath, public IStr
{
public:
long QueryInterface( long riid, void * * ppvObject) { cout<<"QueryInterface"<<endl; return ;}
long AddRef( void) { cout<<"AddRef"<<endl; return ;}
long Release( void) { cout<<"Release"<<endl; return ;} long Add(long n1, long n2, long* pVal) { cout<<"Add"<<endl; return ;}
long Cat(char* _Dest, const char* _Source){ cout<<"Cat"<<endl; return ;}
}; typedef long (*QueryInterfaceType)( long riid, void * * ppvObject);
typedef long (*AddRefType)( void);
typedef long (*ReleaseType)( void); typedef long (CMyTest::*QueryInterfaceClassType)( long riid, void * * ppvObject); void main()
{
CMyTest * pTest = new CMyTest;
//pTest->AddRef(); int* pFirst = (int*)( *(int*)(pTest)); cout<<"IMyMath virtual table call"<<endl;
for(int i=; i<; i++)
{
((QueryInterfaceType)(*(pFirst+i)))(, NULL);
cout<<int((QueryInterfaceType)(*(pFirst+i)))<<endl;
} cout<<endl<<"--------------------------------------------------"<<endl<<endl; cout<<"IStr virtual table call"<<endl;
for(int i=; i<; i++)
{
int* pFirst2 = (int*)( *((int*)(pTest)+));
((QueryInterfaceType)(*(pFirst2+i)))(, NULL);
cout<<int((QueryInterfaceType)(*(pFirst2+i)))<<endl;
}
}

后记:
之前提出一个问题,IUnknown的三个函数地址在两个虚函数表里都各有一份,但是地址值打印出来不一样,用VS command prompt打印class layout如下图,下面的IStr的虚函数表里多了个this -= 4,这里的4是IStr与实际对象指针也就是this指针的偏移量。

参考文章:
http://bbs.csdn.net/topics/390223914
http://blog.csdn.net/wxc1987821/article/details/5958325
COM组件多接口对象模型的更多相关文章
- COM组件双接口对象模型
模型如下: 这里COM对象一共实现了三个接口,IUnknown,IDispatch, Ixxx. 每个COM都必须实现IUnknown,不考虑在内的话共实现了IDispatch和自定义接口Ixxx两个 ...
- Android开发之自定义组件和接口回调
说到自定义控件不得不提的就是接口回调,在Android开发中接口回调用的还是蛮多的.在这篇博客开始的时候呢,我想聊一下iOS的自定义控件.在iOS中自定义控件的思路是继承自UIView, 在UIVie ...
- 【Android 应用开发】 自定义组件 宽高适配方法, 手势监听器操作组件, 回调接口维护策略, 绘制方法分析 -- 基于 WheelView 组件分析自定义组件
博客地址 : http://blog.csdn.net/shulianghan/article/details/41520569 代码下载 : -- GitHub : https://github.c ...
- COM组件三大接口IUnknown、IClassFactory、IDispatch。
转自:http://blog.csdn.net/chenyujing1234/article/details/7753863 (1)COM组件有三个最基本的接口类,分别是IUnknown.IClass ...
- DRF(2) - 解析器,序列化组件使用(GET/POST接口设计)
一.DRF - 解析器 1.解析器的引出 我们知道,浏览器可以向django服务器发送json格式的数据,此时,django不会帮我们进行解析,只是将发送的原数据保存在request.body中,只有 ...
- Restful 2 --DRF解析器,序列化组件使用(GET/POST接口设计)
一.DRF - 解析器 1.解析器的引出 我们知道,浏览器可以向django服务器发送json格式的数据,此时,django不会帮我们进行解析,只是将发送的原数据保存在request.body中,只有 ...
- django rest framework 解析器组件 接口设计,视图组件 (2)
1. 使用视图组件进行接口优化 1.1 使用视图组件的mixin进行接口逻辑优化 - 导入mixin from rest_framework.mixinx import ( ListModelMix, ...
- django rest framework 解析器组件 接口设计,视图组件 (1)
一.解析器组件 -解析器组件是用来解析用户请求数据的(application/json), content-type 将客户端发来的json数据进行解析 -必须适应APIView -request.d ...
- C++ 类的动态组件化技术
序言: N年前,我们曾在软件开发上出现了这样的困惑,用VC开发COM组件过于复杂,用VB开发COM组件发现效率低,而且不能实现面向对象的很多特性,例如,继承,多态等.更况且如何快速封装利用历史遗留的大 ...
随机推荐
- Android 高版本API方法在低版本系统上的兼容性处理
Android 版本更替,新的版本带来新的特性,新的方法. 新的方法带来许多便利,但无法在低版本系统上运行,如果兼容性处理不恰当,APP在低版本系统上,运行时将会crash. 本文以一个具体的例子说明 ...
- ulimit 不生效
ulimit is a shell builtin like cd, not a separate program. sudo looks for a binary to run, but there ...
- uVa 12563 Jin Ge Jin Qu
分析可知,虽然t<109,但是总曲目时间大于t,实际上t不会超过180*n+678.此问题涉及到两个目标信息,首先要求曲目数量最多,在此基础上要求所唱的时间尽量长.可以定义 状态dp[i][j] ...
- ubuntu常用 命令
卸载软件 ,比如chrome sudo apt-get remove google-chrome-stable
- unity shadow
这东西好难找LIGHT_ATTENUATION(a) shadow 的结果就在这个衰减里,这谁能猜的着,我一点点测出来的,reference也很难找 感谢这位http://blog.csdn.net/ ...
- boost/config.hpp文件详解
简要概述 今天突发奇想想看一下boost/config.hpp的内部实现,以及他有哪些功能. 这个头文件都有一个类似的结构,先包含一个头文件,假设为头文件1,然后包含这个头文 件中定义的宏.对于头文件 ...
- solr 常用命令
1.启动和关闭 a.启动和重启 启动和重启命令有很多选项让你运行在SolrCloud模式,使用示例配置,以hostname为开头或者非默认端口,指向本地ZooKeeper. bin/solr star ...
- SparkSQL的3种Join实现
引言 Join是SQL语句中的常用操作,良好的表结构能够将数据分散在不同的表中,使其符合某种范式,减少表冗余.更新容错等.而建立表和表之间关系的最佳方式就是Join操作. 对于Spark来说有3中Jo ...
- eCos系统无法正确链接到在C++源文件里自己定义的cyg_user_start函数的问题和解决的方法
在C++源文件里定义cyg_user_start函数前,将其声明成C函数.就可以解决这个问题. eCos官网:http://ecos.sourceware.org eCos中文技术网:http://w ...
- Windows服务器SYSTEM权限Webshell无法添加3389账户情况突破总结
转自:http://bbs.blackbap.org/thread-2331-1-1.html 近好多Silic的朋友在Windows下SYSTEM权限的php webshell下添加账户,但是却无法 ...