码迷,mamicode.com
首页 > 其他好文 > 详细

COM组件初探——《Inside COM》笔记

时间:2015-08-05 19:48:28      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:

  一个应用程序通常是由单个的二进制文件组成的,这样的话,每次更新其中的一部分都需要将整个应用程序重新编译。而 COM 的基本思想就是:将单个的应用程序分隔成多个独立的部分,也即组件。这并不是说将应用程序分割成文件、模板或类,因为这在本质上并没有什么变化,仍然是将它们编译并链接成一个铁板一块状的应用程序。在组件架构中,一个组件类似于一个微型应用程序(即:已经编译、链接好并可以使用),而应用程序是由这样的多个组件打包而成的(各定制的组件在运行时同其他组件连接起来以构成某个应用程序)。这样的架构思想实现了修改应用程序只需替换其中一个组件,而无须陷入整体重新编译的窘态。

COM 有几个特性——

  • 它并不是类似 Win32 API 那样的函数集,它只是一个规范,提供了编写组件的一个标准方法,而遵循 COM 标准的组件可以被组合起来以形成应用程序;
  • 它不是一种计算机语言,恰恰相反,因为组件是以二进制形式发布的,它具有与语言的无关性,可用任何语言来编写组件,且任一客户能够使用任一组件;
  • COM 组件是以 Win32 动态链接库(DLLs)或可执行文件(EXEs)的形式发布的可执行代码组成的,但它本身与 DLL 并没有很大关系,只不过 COM 利用了 DLL 极佳的动态链接能力。

  COM 是与语言无关的,所以为了将客户与 COM 组件连接起来,COM 组件通过接口与外界打交道。而对于 COM 组件这样的二进制文件来说,什么是接口呢?它同样有着一个二进制的标准——表示一个接口的内存块必须具有一定的结构。

  以下将用 C++ 语言来描述这些细节。

  首先介绍 COM 组件中接口的概念,以下贴一段描述接口实现以及使用的代码,但注意:这并不是真正的 COM 接口,COM 接口还需支持一些额外的属性。

#include <iostream>
#include <objbase.h>    //此头文件中定义有 #define interface struct 

using namespace std;

//定义 IX,IY 接口
interface IX //纯抽象基类
{
    virtual void _stdcall Fx1() = 0; //纯虚函数
    virtual void _stdcall Fx2() = 0;
};
interface IY
{
    virtual void _stdcall Fy1() = 0;
    virtual void _stdcall Fy2() = 0;
};

//实现组件
class CA :public IX, public IY
{
public:
    //实现 IX 接口
    virtual void __stdcall Fx1() { cout << "CA::Fx1" << endl; }
    virtual void __stdcall Fx2() { cout << "CA::Fx2" << endl; }
    //实现 IY 接口
    virtual void __stdcall Fy1() { cout << "CA::Fy1" << endl; }
    virtual void __stdcall Fy2() { cout << "CA::Fy2" << endl; }
};

void trace(const char* pMsg)
{
    cout << pMsg << endl;
}

//客户
int main()
{
    trace("客户:创建该组件的实例");
    CA* pA = new CA;

    //得到指向 IX 的指针
    IX* pIX = pA;

    trace("客户:调用 IX 接口");
    pIX->Fx1();
    pIX->Fx2();

    //得到指向 IY 的指针
    IY* pIY = pA;

    trace("客户:调用 IY 接口");
    pIY->Fy1();
    pIY->Fy2();

    trace("客户:删除组件");
    delete pA;

    cin.get();
    return 0;
}

  如代码所见,在 C++ 中用纯抽象基类来定义 COM 接口,这是因为纯抽象基类所定义的内存结构可以满足 COM 对接口的要求。

  那么纯抽象基类所定义的内存结构是什么样的呢?这就不得不提到虚函数表了。

  我们知道,在 C++ 中,因为虚函数的存在,导致了隐式向上强制转换的问题(即:基类指针或引用可以指向基类对象或派生类对象),为了能够在程序运行时选择正确的虚方法(究竟是基类的还是派生类的,该过程又被称为动态联编),编译器采用了虚函数表的方法——在每个类中添加一个隐藏的指针成员,其指向一个函数地址数组,而这个数组中存储了所有定义的虚函数的地址(对于派生类来说,如果其没有重新定义虚函数,数组中将继承基类中对应虚函数原始版本的地址),这个数组就被称为虚函数表(virtual function table, vtbl)。

  那么,纯抽象基类的内存结构也就可想而知了——一块连续的内存中存储了所有的虚函数的地址,而当派生类继承一个抽象基类时,它也将继承此内存结构。而“巧合”的是,COM 接口的内存结构同 C++ 编译器为抽象基类所生成的内存结构是相同的。

  今天将《Inside COM》读到了第二章,做一个阶段性的笔记总结,我这么懒,可能会过几天再往后看吧QAQ

  PS:我对于 C++ 的编译器实现并不清楚,在虚函数表的解释那儿可能有点儿问题,欢迎友好交流=。=

COM组件初探——《Inside COM》笔记

标签:

原文地址:http://www.cnblogs.com/Sleepingbear/p/4705353.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!