zoukankan      html  css  js  c++  java
  • Inside COM接口

    1.接口的作用


    组件可以充应用程序中删除并可用另外一个组件代替,只要新的组件支持同样的接口。单个组件并不能起决定性作用,相反,用以连接组件的接口对应用程序亲戚到决定性作用。使用组件来构成应用程序最大优点在于可以复用应用程序的结构。
    接口可以保护系统免受外界变化的影响、接口可以使得客户用相同的方式处理不同的组件。

    2.COM接口的实现


    class  IX                    //First Interface
    {
    public :
            virtual  void  Fx1() = 0;
            virtual  void  Fx2() = 0;
    };

    class  IY                  //Second Interface
    {
    public :
            virtual  void  Fy1() = 0;
            virtual  void  Fy2() = 0;
    };

    class  CA :  public  IX,  public  IY
    {
    public :
            //implement Interface IX
            virtual  void  Fx1(){cout<< "Fx1()" <<endl;}
            virtual  void  Fx2(){cout<< "Fx2()" <<endl;}
            //implement Interface IY
            virtual  void  Fy1(){cout<< "Fy1()" <<endl;}
            virtual  void  Fy2(){cout<< "Fy2()" <<endl;}
    };

    IX和IY是用于实现接口的纯抽象基类。组件CA继承了IX和IY接口。抽象基类指定了起派生类应提供哪些函数。而派生类则具体实现这些函数,对纯虚类的继承称作接口继承。com接口必须继承至IUnknown接口。
    在objbase.h中定义:#define interface struct    所以使用struc 就不必留有public更简洁。

    总结:
    • com接口在c++中是用纯抽象基类实现的
    • 一个com组件可以提供多个接口
    • 一个c++类可以使用多继承来实现一个了可以提供多个接口的组件
          (1) __stdcall调用
              __stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。WIN32 Api都采用__stdcall调用方式,这样的宏定义说明了问题: #define WINAPI _stdcall  按C编译方式,__stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,形如_functionName@nnn。

          (2) __cdecl调用
              __cdecl是C/C++的缺省调用方式,参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护。__cedcl约定的函数只能被C/C++调用,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用__stdcall函数的大。 由于_cdecl调用方式的参数内存栈由调用者维护,所以变长参数的函数能(也只能)使用这种调用约定。由于Visual C++默认采用__cdecl 调用方式,所以VC中中调用DLL时,用户应使用__stdcall调用约定。按C编译方式,__cdecl调用约定仅在输出函数名前面加下划线,形如_functionName。

    3.实现细节

    • 类并非组件
    • 接口并非总是继承的
         可以用一个类实现几个不同的接口,还可以用单个的类来实现每一个接口
    • 多重接口及多重继承
         一个接口是一个函数集合、一个组件是一个接口集合,而一个系统是一系列组件的集合。
    • 命名冲突

    4.接口的背后


    虚拟函数表
         当定义一个抽象基类时,定义的实际上是一个内存块的结构。纯抽象基类所有实现都是一些具有相同的基本结构的内存块
    interface  IX
    {
            virtual  void  __stdcall  Fx1() = 0;
            virtual  void  __stdcall  Fx2() = 0;
            virtual  void  __stdcall  Fx3() = 0;
            virtual  void  __stdcall  Fx4() = 0;
    };
    定义一个纯抽象基类也就是定义了相应的内存结构。次内存在派生类中实现此抽象基类的时候才会分配。当派生类继承一个抽象基类时,将继承此内存结构:
    一个抽象基类定义的内存结构分为两部分。上图右边是虚拟函数表(vtbl)其中包含一组指向虚拟函数实现的指针,vtbl中第一项为派生类中所实现Fx1函数的地址。左侧为一个指向vtbl的指针,指向抽象基类的指针则指向vtbl指针。

    vtbl指针及实例数据
    class  CA:  public  IX
    {
    public :
            //implement interface IX
            virtual  void  __stdcall  Fx1(){cout<<  "CA::Fx1()" <<endl;}
            virtual  void  __stdcall  Fx2(){cout<<m_Fx2<<endl;}
            virtual  void  __stdcall  Fx3(){cout<<m_Fx3<<endl;}
            virtual  void  __stdcall  Fx4(){cout<<m_Fx4<<endl;}
            //
          CA(  double  d):m_Fx2(d*d),m_Fx3(d*d*d),m_Fx4(d*d*d*d){}
            //interface data
            double  m_Fx2;
            double  m_Fx3;
            double  m_Fx4;
    };




  • 相关阅读:
    Leetcode-2 两数相加
    离散数学-基本割集的找法
    Linux操作系统分析课程学习总结报告
    Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程
    Linux实验二:深入理解系统调用
    初始python
    水仙花数讲解
    Python-运算
    Python-列表
    Python-字符串
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3069607.html
Copyright © 2011-2022 走看看