Chinaunix首页 | 论坛 | 博客
  • 博客访问: 672138
  • 博文数量: 90
  • 博客积分: 1631
  • 博客等级: 上尉
  • 技术积分: 1413
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-15 22:43
文章分类
文章存档

2017年(8)

2016年(9)

2015年(11)

2014年(10)

2013年(9)

2012年(9)

2010年(2)

2009年(10)

2008年(22)

我的朋友

分类: C/C++

2012-12-11 09:17:23

 接口有如下特征:
    .接口被声明为Interface类型,不是class类型。惯例是:接口名从字母I开始,正如类类型名从字母T开始。
   
    .所有的接口都从IUnknown直接或间接继承。就像TObject是Delphj中所有类的基类一样,IUnknown是coM中所有接口的基础。

    .接口不能自我创建和实现,必须有其派生的类来创建实例和实现功能。下列是错误的:
    
   

点击(此处)折叠或打开

  1. var
  2.       FormattedNumber:IFormattedNumber;
  3.       
  4.       FormattedNumber := IFormattedNumber.create(); //这将导致编译错误
  5.       FormattedNumber := TFormattedNumber.create(); //TFormattedNumber类是IFormattedNumber接口


的派生实现,这是正确的。
     
1.不能创建接口实例。下面的代码是非法的;

    1)不能在接口中指定范围指示。接口定义的所有方法都是公有型(public),不能在接口声明中包括范围指示(包括公有型)。
   
    2)接口不能声明变量。接口只能决定提供什么样功能。对于如何完成该功能没有限制。如果允许在接口声明中放一个成员
   
    变量,就会在某种程度上命令用何种方法来完成想要的功能。
   
    3)在接口中声明的所有函数和过程,概念上讲都是虚(virtual)抽象函数和过程。声明时不必带virtual关键字;
   
      事实上,这样做是非法的。

2.接口是标准协议,一旦定义经不能随便修改,如果要增强接口功能,可以派生新的接口:
  例如:要为IFormattedNumber接口增加一个SetCaption函数
  
 

点击(此处)折叠或打开

  1. IFormattedNumber2 = inerface(IFormattedNumber);
  2.       procedure SetCatpion(ACapiton:String);
  3.    end;


 

3.声明一个接口:

点击(此处)折叠或打开

  1. IFormattedNumber = interface
  2.    [GUID] //16字节,无重复标识符,在delphi中可Ctrl+Shift+G自动创建一个,在内部调用了coCreateGuid里产生GUID
  3.    function formattedString:String;
  4.   end;
  5.     { //动态获取GUID的方法
  6.   procedure TForm1.btnGenerateClick(Sender: TObject);
  7.    var
  8.        Guid: TGUID;
  9.   begin
  10.        CoCreateGuid(Guid);
  11.        Memo1.Lines.Add(GuidToString(Guid));
  12.   end;
  13.  }



 
  1)TGUID数据结构定义:   

点击(此处)折叠或打开

  1. type
  2.   PGUID = ^TGUID;
  3.   TGUID = packed record
  4.     D1: Longword;
  5.     D2: Word;
  6.     D3: Word;
  7.     D4: array[0..7] of Byte;
  8.   end;



  
  2)下面声明完全一样:

点击(此处)折叠或打开

  1. const IID_IMalloc: TGUID ='{DC1D7C5F-C0DC-4056-B1F2-1D3A1ADA6D51}';
  2.     const IID_IMalloc: TGUID =(D1:$DC1D7C5F;D2:$C0DC;D3:$4056;D4:($B1,$F2,$1D,$3A,$1A,$DA,$6D,$51));



  
  3)接口的实现

点击(此处)折叠或打开

  1. TFormattedNumber = class(TInterfacedObject,IFormattedNumber)
  2.       private
  3.         FormattedString:String;
  4.       public
  5.         function formattedString:String;
  6.     end;



    
  4)IUnkonwn接口

点击(此处)折叠或打开

  1. IiInterface = interface
  2.       ['00000000-0000-0000-C000-00000000000046']
  3.       function QueryInterface(const IID:TGUID;out obj):HResult;stdcall;
  4.       function _AddRef:integer;stdcall;
  5.       function _Release:Integer;stdcall;
  6.     end;
  7.     IUnkonwn = IiInterface;



    由此可见IUnkonwn是所有COM接口的基础接口,QueryInterface,_AddRef,_Release必须由IUnkonwn的派生类来实现,
    在Delphi中由TInterfacedObject来实现了。
    (1)QueryInterface
          QueryInterface是请求指向一个接口指针的函数。如果接口是由问题中的对象实现的,QueryInterface返回在则
          参数中的接口,且返回数值为0。如果接口不是由对象实现的,QueryInterface返回MicroSoft定义的
          常量E_NOINTERFACE。
   
 (2)_AddRef
        接口是引用计数。因此在对象中当获得接口指针时,对象被引用的次数就增加了。当结束使用接口时,对象的
        引用次数就下降了。当引用次数到达零时,就自动销毁对象。_AddRef是负责增大引用计数的函数。
        如何物理上存储引用计数由读者决定,但是典型情况下将建立整型(Integer)变量去保存计数。

 (3)_Release
     _Release既是个负责降低引用计数的函数。当引用计数达到零时,就自动销毁对象。
 
  5)TInterfacedObject实现了Iunkonwn接口的基本类
     TInterfacedObject = class(TObject,IiInterface)
     ....
     end;
    
  6)多接口继承
    一个类可以实现多个接口,但是如果这些接口中有同名函数,必须给他们取别名。

点击(此处)折叠或打开

  1. type
  2.       Ifoot = interface
  3.         ...
  4.         function F1:Integer;
  5.       end;
  6.       
  7.       IBall = interface
  8.         ...
  9.         function F1:integer;
  10.       end;
  11.       
  12.       TFootBall = class(TInterfacedObject,IFoot,IBall)
  13.         //为同名方法取别名
  14.         function IFoot.F1 = FootF1;
  15.         function IBall.F1 = BallF1;
  16.         //接口方法
  17.         function FootF1:integer;
  18.         function BallF1:integer;
  19.       end;



    
    7)接口的引用和销毁
      Delphi在引用对象时:

点击(此处)折叠或打开

  1. var
  2.          FormattedNumber:IFormattedNumber;
  3.       begin
  4.        FormattedNumber := TFormattedNumber.create();
  5.       end;



      不必显示调用_Release()去释放资源。这是因为Delphi在后台已经帮你做了释放工作。如果是C或C++就必须显示调用。
      如果要强制销毁一个接口:
      

点击(此处)折叠或打开

  1. FormattedNumber := nil; //强制销毁接口,仅仅把该接口赋值为nil即可



      
    8)获取接口的指针
      Delphi提供了获取接口指针的一些方法。可以获得一个接口的指针,该指针给出了实现接口的一个对象,或给出了另
    一个接口的指针。
     (1)直接分配
          从对象获取接口的最简单的方法是通过直接分配。类是与它们实现的接口类型兼容的,因此可以编写代码如下;
            

点击(此处)折叠或打开

  1. //直接创建实现接口的类,直接赋值
  2.         var
  3.            FormattedNumber:IFormattedNumber;
  4.            ForInteger: TFormattedInteger;
  5.         begin
  6.           ForInteger := TFormattedInteger.Create();
  7.          FormattedNumber := ForInteger;
  8.          //或者直接写为: FormattedNumber=TFormattedInteger.Create();
  9.         end;
  10.         
  11.         //或直接从接口查询QueryInterface函数得到
  12.         //function Tobject.GetInterface(const IID:TGUID;out:obj);Boolean;
  13.         var
  14.           MyObject :Tobject;
  15.           MyNumber :IFormattedNumber;
  16.         begin
  17.           MyObject := TFormattedInteger.Create();
  18.           if MyObject.GetInterface(IFormattedNumber,MyNumber) then //安全方式查询,不会产生异常
  19.           begin
  20.             showmessage(MyNumber.formattedString());
  21.           end;
  22.         end;
  23.         其实IUnkonwn接口中的QueryInterface正是调用了GetInterface方法来实现的接口查询:
  24.         {
  25.          function TinterfaceObject.QueryInterface(const IID:TGUID;out:Obj):HResult;
  26.             const E_NOINTERFACE = $80004002;
  27.          begin
  28.              if GetInterface(IID,Obj) then result := 0 else Result:= E_NOINTERFACE;
  29.          end;
  30.         }



        
      (2)as 操作符
        as操作符即可在Tobject上使用,也可以在接口本身使用。


点击(此处)折叠或打开

  1. var
  2.           MyObject :Tobject;
  3.           MyNumber :IFormattedNumber;
  4.         begin
  5.           MyObject := TFormattedInteger.Create();
  6.           MyNumber := MyObject as IFormattedNumber; //如果MyObject与IFormattedNumber接口不匹配会有异常
  7.           showmessage(MyNumber.formattedString());
  8.         end;



        
       (3)绕过引用计数器
           Delphi为我们提供了一个绕过引用计数,不会自动销毁的类:

点击(此处)折叠或打开

  1. TNonRefCountedObject = Class(TinterfaceObject,IUnkonwn)
  2.               protected
  3.          function _AddRef:integer;stdcall;
  4.          function _Release:Integer;stdcall;
  5.            end;



           
           //例如:下面var A: Array of IUnknown参数如果换为var A: Array of TInterfaceObject;那么下面
           //一行代码就使对象过早地销毁;
           //if (A[J] as ICompare).CompareWith(A[I] as ICompare, ASortBy) < 0 then begin
           //as操作符会使Delphi调用ICompare接口中的_AddRef,_Release,这样就会在排序过程中销毁排序的正确对象,
           //这是一个混合引用模型时会产生的一个麻烦的经典实例。所以使用最基类的IUnknown类型可以避免这个问题。

点击(此处)折叠或打开

  1. type
  2.       ICompare = interface
  3.         ['{DDFE0840-E8FB-11D2-9085-0040F6741DE2}']
  4.         function CompareWith(ACompare: ICompare; ASortBy: Integer): Integer;
  5.       end;
  6.     
  7.         procedure SortArray(var A: Array of IUnknown; ASortBy: Integer);
  8.     var
  9.       I, J: Integer;
  10.       Temp: IUnknown;
  11.     begin
  12.       for I := Low(A) to High(A) - 1 do begin
  13.         for J := I + 1 to High(A) do begin
  14.           if (A[J] as ICompare).CompareWith(A[I] as ICompare, ASortBy) < 0 then begin
  15.             Temp := A[I];
  16.             A[I] := A[J];
  17.             A[J] := Temp;
  18.           end;
  19.         end;
  20.       end;
  21.     end;
  22.     
  23.     end.



转载出处:http://blog.163.com/huangjian_w/blog/static/1943728120088118928775/

阅读(1955) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~