浅析COM的思想及原理

COM浅析 COM是Component object model的缩写。中文名为组件对象模型。       传统的软件由单个的二进制文件组成。组件将单个二进制文件分割为多个独立的部分,每个部分都被称为一个组件。采用组件技术后,在需要对程序进行修改和改进时,只需替换某个组件模块即可。       组件化程序设计思想是将复杂的应用程序被设计成小的、功能单一的组件模块。为了实现这样的软件,模块与模块之间 阅读详情

浅析COM的思想及原理

  COM--Component Object Model,即组件对象模型,它是微软提出的一套开发软件的方法与规范。它也代表了一种软件开发思想,那就是面向组件编程的思想。


  一、COM编程思想--面向组件编程思想(COP)

  众所周知,由C到C++,实现了由面向过程编程到面向对象编程的过渡。而COM的出现,又引出了面向组件的思想。其实,面向组件思想是面向对象思想的一种延伸和扩展。因此,就让我们先来回忆一下面向对象的思想吧。

  面向对象思想是将所有的操作以及所操作的对象都进行归类(由class实现),而它的目标是要尽量提高代码的可重用性(这也是面向对象相比面向过程最大的优点之一)。比如,有两个程序A和B都需要对class C的对象进行操作,那么class C的代码就可以重用了(即A和B都可以使用class C的代码)。但是,对于这一点,面向对象做得并不够好。还是举刚才的例子,程序A和B都要对class C的对象进行操作,那么,程序A和B的编程人员都必须将class C的代码拷贝过来,然后重新编译一次,这将是多么麻烦的事!况且,如果class C的代码没有公开,那这种重用就根本不可能实现了(除非程序A和B的编程人员和class C的编程人员是同一个人或者团队,但这样局限性就相当大了)。

  由于面向对象的这些局限性,很多程序员就会想,如果我们编程需要重用别人的成果时,不需要重新编译别人的代码那就好了。换句话说,我们要达到的目标是,直接重用别人的成果而不是重用别人的代码。这样说也许很抽象,举个例子大家就会比较明白。比如将class C的代码编译生成一个dll,那么当其他程序员想要重用class C时,就只需要在自己的程序中加载这个dll而不需要重新编译class C的代码了(这也就是组件必须要能动态链接的原因)。正是这种思路引出了面向组件的编程思想。

  下面,我就简单介绍一下面向组件的思想。在以前,应用程序总是被编写成一个单独的模块,就是说一个应用程序就是一个单独的二进制文件。后来在引入了面向组件的编程思想后,原本单个的应用程序文件被分隔成多个模块来分别编写,每个模块具有一定的独立性,也应具有一定的与本应用程序的无关性。一般来说,这种模块的划分是以功能作为标准的。比如,一个网上办公管理系统,从功能上说它需要包含网络通信、数据库操作等部分,我们就可以将网络通信和数据库操作的部分分别提出来做成两个独立的模块。那么,原本单个的应用程序就分隔成了三个模块:主控模块、通信模块和数据库模块。而这里的通信模块和数据库模块还可以做得使其具有一定的通用性,那么其他的应用程序也就可以利用这些模块了。这样做的好处有很多,比如当对软件进行升级的时候,只要对需要改动的模块进行升级,然后用重新生成的一个新模块来替换掉原来的旧模块(但必须保持接口不变),而其他的模块可以完全保持不变。这样,软件升级就变得更加方便,工作量也更小。

  说了这么多,总结一下:面向组件编程思想,归结起来就是四个字:模块分隔。这里的“分隔”有两层含义,第一就是要“分”,也就是要将应用程序(尤其是大型软件)按功能划分成多个模块;第二就是要“隔”,也就是每一个模块要有相当程度的独立性,要尽量与其他模块“隔”开。这四个字是面向组件编程思想的精华所在,也是COM的精华所在!理解了这四个字,也就真正理解了面向组件编程的思想。(这里说一点题外话,COM其实是一套规范或者说一套标准,但是在我看来,COM的核心还在于它的思想,也就是面向组件编程思想。标准谁都能定,但是思想只有一个!)

  二、COM的优点

  COM的优点也就是面向组件编程思想的优点。而面向组件编程思想有很多的优点,上面所说的便于软件升级只是其中之一。对于它的优点,我总结了一下,有下面几条:

  1、便于重用,使软件开发更快捷

  2、便于软件升级

  3、便于软件开发的分工协作

  4、便于用户定制自己的应用

  以上几点,第一和第二点都不用再多说了,前面讲面向组件编程思想的部分里面已经充分展示出了这两点优点。在这里我解释一下第三和第四点。

  如今的很多大型软件,都不可能由某一个人单独开发,甚至不会由某一个公司去单独开发。这是因为现在的很多大型软件,综合性太强,涉及的面也太广。而一个人的精力是有限的,不可能学会这么多方面的知识,也不可能掌握到这么多方面的编程技术,即使有可能,这样做的效率也是很低下的。所以,通常的情况是分工协作。仍以前面提到的网上办公管理系统为例,这个系统分为了三个模块:主控模块、通信模块和数据库模块。由于这三个模块具有相当的独立性,那么就可以将现有的所有开发人员分为三组,每一组负责一个模块。而这三组之间,只需要商量好相互间的接口就可以了。这样,对于每一个开发人员来说,就不需要掌握所有的编程技术,甚至不需要了解其他模块的具体实现,而软件仍然能有效的开发成功。这就是所谓的便于软件开发的分工协作了。

   除此之外,如果一个大型的软件希望允许用户在一定程度上定制自己的应用,那么COM也是最好的选择。比方说一个软件由两个模块组成,模块A和模块B,现在软件的开发商希望给予用户一定的灵活性,希望可以允许用户自己定制模块B来实现自己特定的应用,那么就只需要公开模块B的所有接口;而用户自己编程实现模块B时也只需要实现了所有的这些接口就行了。当然,这里面还有很多问题,比如COM组件的注册,这涉及到COM标准的一些细节,在这里不作讨论。

  三、COM中的几个重要概念

  1、组件:

  其实只要你仔细阅读了前面的部分,组件的概念应该已经很清楚了。这里所说的组件,就是前面反复在讨论的所谓“模块”。现在我只想强调一下组件需要满足的一些条件。首先是封装性,组件必须向外部隐藏其内部的实现细节,使从外部所能看到的只是接口。然后是组件必须能动态链接到一起,而不必像面向对象中的class一样必须重新编译。

  2、接口:

    由于组件向外部隐藏了其内部的细节,因此客户要使用组件时就必须通过一定的机制,也就是说要通过一定的方法来实现客户与组件之间的通信,这就需要接口。所谓接口就是组件对外暴露的、向外部客户提供服务的“连接点”。外部的客户见不到组件内部的细节,它所能看到的只是接口,客户也是通过接口来获取组件提供的服务。这有点像OSI网络协议分层模型,每一层就像一个组件,它内部的实现细节对于其他层是不可见的;而每一层通过“服务接入点”向其上层提供服务,这就像这里所说的接口。一般来说,接口总是固定的,也是公开的。组件的开发人员要实现这些接口,而客户则通过接口获得服务。正是接口的这种固定和公开,才使得组件和客户能够在不了解对方的情况下达成一致。

  3、客户:

  这里所说的客户不是指使用软件的用户,而是指要使用某一个组件的程序或模块。也就是说,这里的客户是相对组件来说的。

  四、COM的实现原理与雏形模拟

  COM编程的一个重要特点就是要模块化,说得具体一些,就是要将客户和组件分隔开来,而客户和组件之间又是通过接口来通信的。下面,我就介绍一下COM是怎样将客户与组件分隔开来,又是怎样利用接口来实现客户与组件间的通信的。

  首先我要讲讲接口。COM中的接口实际上是一个函数地址表,当组件实现了这个接口后,这个函数地址表中就填满了组件所实现的那些接口函数的地址。而客户也就是通过这个函数地址表获得组件中那些接口函数的指针,从而获得组件所提供的服务的。从某种意义上说,我们可以把接口理解为c++中的虚拟基类;或者说,在c++中可以用虚拟基类来实现接口!这是因为COM中规定的接口的存储结构,和c++中的虚拟基类在内存中的结构是一致的。其存储结构如下图:  
 
                                         虚函数表
               vtbl指针------>Fun1()指针-------->
                                       Fun2()指针-------->
                                       Fun3()指针-------->
                                       …………
  
  Vtbl指针指向一个虚函数表,而这个虚函数表的表项就是指向这些虚函数的指针。

  接口有了,那么组件又是怎样实现接口的呢?实际上,如果用虚拟基类来实现接口,那么组件就是对这个虚拟基类的继承。大家知道,当某个类继承于一个虚拟基类的时候,它就要实现这个虚拟基类里声明的虚函数,这就正好与组件实现接口这一点相吻合。举一个例子来说明,有一个接口InterfaceA,组件ComponentB要实现这个接口,那么就可以这样用c++语言来描述:

//接口:
class InterfaceA
{
  virtual void Fun1()=0;
  virtual void Fun2()=0;
};
//实现了接口InterfaceA的组件:
class ComponentB: public InterfaceA
{
  virtual void Fun1()
  {
     printf("Fun1/n");
  }
  virtual void Fun2()
  {
     printf("Fun2/n");
  }
};

  而客户只需要得到一个指向ComponentB实体的InterfaceA指针就可以获得ComponentB组件的服务了:

//使用了组件ComponentB的客户:
……
ComponentB CB;
InterfaceA *pIA=&CB;  //获得指向ComponentB实体的InterfaceA指针,以下客户就可以只通过接口来获取组件的服务
pIA->Fun1();
pIA->Fun2();
……

  但是我们注意到,这样做组件ComponentB和客户还是没有被完全分隔开。因为在客户代码里需要创建ComponentB实体,这对于只能看到接口而对组件一无所知的客户来说,是不可以接受的(比如客户不会知道组件的类名叫ComponentB)。解决这个问题的方法是在实现组件的动态链接文件(比如dll文件)里创建组件的实体,而不是在客户代码里创建组件实体。通常组件都是以dll的形式出现的,而在实现组件的dll里都会实现一个叫CreateInstance的函数,这个函数可以被外部的客户调用。它返回一个接口的指针,当客户调用这个函数后就能够获得指向组件实体的接口指针了。它的实现也很简单:

//在实现组件ComponentB的dll里:
InterfaceA *CreateInstance()
{
   ComponentB CB;
   InterfaceA *pIA=&CB;
   return pIA;
}

  当然,真正的CreateInstance函数没有这么简单,我上面的代码只是一个简单的模拟。有个CreateInstance函数之后,客户代码就变成了:

//使用了组件ComponentB的客户:
……
InterfaceA *pIA=CreateInstance();  //获得指向ComponentB实体的InterfaceA指针,以下客户就可以只通过接口来获取组件的服务
pIA->Fun1();
pIA->Fun2();
……

  这样,组件和客户就完全被分隔开了,而连接它们的只有接口以及一个CreateInstance的函数。

  以上就是COM的基本原理了。当然,我前面也说了,COM其实是一套规范,它定义了很多标准,比如COM规定每个接口都必须继承于一个叫IUnknown的接口。我这里基本上没有提及它的这些标准,只是希望能通过对它进行一个简单的模拟来说清楚它的实现原理。下面就给出我模拟COM机制实现的一套COM的雏形,希望能对大家理解COM有帮助。

  1、实现了组件ComponentB的ComponentDll.dll:

//Interface.h
//接口
class InterfaceA
{
public:
  virtual void Fun1()=0;
  virtual void Fun2()=0;
};
//Component.h
//组件(实现了接口InterfaceA)
class ComponentB: public InterfaceA
{
public:
 virtual void Fun1()
 {
  printf("Fun1/n");
 }
 virtual void Fun2()
 {
  printf("Fun2/n");
 }
};
//ComponentDll.cpp
//CreateInstance函数
ComponentB instance;
extern "C" _declspec(dllexport) InterfaceA *CreateInstance()
{
 InterfaceA *pIA=&instance;
 return pIA;
}

  2、客户Client.exe:

//Client.cpp
#include "Interface.h"
#pragma comment(lib,"ComponentDll")
int main(int argc, char* argv[])
{
 InterfaceA *pIA=0;
 pIA=CreateInstance();
 if(pIA!=0)
  pIA->Fun1();
 return 0;
}

深入探索COM组件对象模型 本文还有配套的精品资源,点击获取 简介:COM(Component Object Model)是由微软推出的一种支持跨语言、跨平台接口技术,用于构建和集成软件系统。本书《COM本质》详尽阐述了COM的核心概念和实现机制,为软件开发者提供了深入理解COM工作原理及其应用的宝贵资料。内容覆盖了接口设计、组件注册、延迟绑定、线程模型、实例化、错误处理、自动化和ActiveX技术,... 阅读详情

相关推荐

深入Android构建系统:一次修改ro.vendor.build.fingerprint失败的排查与解决记录

本文深入探讨了Android构建系统中修改ro.vendor.build.fingerprint的完整解决方案。通过分析vendor分区的特殊地位和构建指纹的生成路径,提供了三种实战修改方法,并揭示了指纹修改可能遇到的陷阱与对策,帮助开发者彻底解决这一常见问题。

weixin_30621711的博客 144

COM初学 (一) 理论入门

163博客迁移! 面向对象: 整个世界是由不同的对象组成的,花、草、人、动物等等,所有的这些对象是有其特定的固有的属性,例如:人有很多的行为属性(走、跑、跳..)、心里属性(哭、笑...),我们将该对象的这种固有的、稳定的特征找出来,归纳为一系列的方法,例如就是前面提到的人的行为方法:描述怎么走的方法、描述怎么跑的方法、描述怎么跳的方法等等,这种思想,我们就称之为面向对象。

jimk1983的专栏 1544

ShardingSphere-jdbc 5.5.0 + spring boot 基础配置 - 实战篇

shardingsphere 5.5.0移除了sm4算法,自己加上即可。增加spi扩展org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm增加以下代码:SM4算法代码/***/static {@Getter@Overrideif (!

qq_21903999的博客 4747

COM编程小结

COM编程小结   一、Com概念 所谓COM(Componet Object Model,组件对象模型),是一种说明如何建立可动态互变组件的规范,此规范提供了为保证能够互操作,客户和组件应遵循的一些二进制和网络标准。通过这种标准将可以在任意两个组件之间进行通信而不用考虑其

深之JohnChen的专栏 3万+

KEIL MDK实战:如何用fromelf工具解析STM32的ELF文件结构(附完整命令行)

本文详细介绍了如何使用KEIL MDK中的fromelf工具解析STM32的ELF文件结构,包括内存段分析、符号表追踪和反汇编关键函数等实战技巧。通过完整的命令行示例,帮助嵌入式开发者优化内存占用、排查运行时问题,并提升STM32项目的开发效率。

weixin_42631411的博客 188

学习笔记——神经科学的数学基础

m%3D2X_%7Bi%7DiNy%3DAxW%3DABx_%7Bj%7Dy_%7Bi%7Dy%3DWxt=N7T8卷积神经网络(CNN)详细介绍及其原理详解_IronmanJay的博客-优快云博客https://blog.youkuaiyun.com/IronmanJay/article/details/128689946?

zxyopenstar的博客 1374

COM组件对象模型

COM(Component Object Model)是一种标准。它的目的是实现软件的动态连接和无缝集成。 它一种软件组件技术标准:即建立动态的可重组的可无缝连接的跨语言的组件技术标准。 COM规范就是一套为组件架构设置标准的描述文档。符合COM的组件 以DLL形式或EXE形式发布。 它需实现动态连接和信息封装。 它可以以二进制形式发布。 它完全与语言无关。 它可以自由的升级替换而且不...

顺其自然~专栏 3402

聚宽策略实盘新路径:不开通QMT , 小资金自动化交易解决方案

聚宽策略实盘新路径:不开通QMT , 小资金自动化交易解决方案

u011111246的博客 1469

[COM/ATL]浅析COM的思想及原理

COM--Component Object Model,即组件对象模型,它是微软提出的一套开发软件的方法与规范。它也代表了一种软件开发思想,那就是面向组件编程的思想。 COM编程思想--面向组件编程思想(COP)   众所周知,由C到C++,实现了由面向过程编程到面向对象编程的过渡。而COM的出现,又引出了面向组件的思想。其实,面向组件思想是面向对象思想的一种延伸和扩展。因此,就让我们

超越 2616

PCL 基于法线微分(DoN)的点云分割【2026最新版】

基于法线微分的分割。博客长期更新,本文最新更新时间为:2026年5月10日。

点云侠的博客 39万+

AI 时代嵌入式工程师的能力模型与学习路线:全系列收官

AI 时代嵌入式工程师的能力模型与学习路线:全系列收官

weixin_42162924的博客 40

COM面向组件的编程思想

浅析COM的思想及原理   本文关键词: COM 思想 原理 COM--Component Object Model,即组件对象模型,它是微软提出的一套开发软件的方法与规范。它也代表了一种软件开发思想,那就是面向组件编程的思想。   一、COM编程思想--面向组件编程思想(COP)   众所周知,由C到C++,实现了由面向过程编程到面向对象编程的过渡。而COM的出

li160620的博客 2777

【Nginx学习】5步揭秘Nginx邮件代理模块:邮件代理服务器的功能与实现

Nginx的邮件代理模块(Mail Proxy Module)允许Nginx作为邮件代理服务器,支持SMTP、POP3和IMAP协议。这使得Nginx可以作为一个高性能的邮件网关,用于过滤垃圾邮件、病毒扫描、负载均衡等任务。简单来说,Nginx在这里就像是一个邮递员,负责将邮件从发件人手中安全、快速地送到收件人手中。通过上述的解析,我们可以看到Nginx在邮件代理模块中的设计和实现。从配置解析、连接处理,到协议处理、SSL/TLS加密和日志记录,每一步都至关重要。

java专栏 1314
上一篇: C++初学者必看
下一篇: vb初学者必看
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值