首 页 网络编程
网页制作 图形图象 操作系统 冲浪宝典
软件教学 认证考试

网络安全 网络办公 行业资讯 评测对比
您当前位置:站长天空 -> 软件教学-> 办公软件
delphi下的接口编程学习笔记(原创)_delphi教程
作者:网友供稿 点击:0
推荐
西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!可在线rar解压,自动数据恢复设置虚拟目录等.免费赠送访问统计,企业邮局.Cn域名注册10元/年,自助建站480元起,免费试用7天,满意再付款!P4主机租用799元/月.月付免压金
站内搜索
文章页数:[1] 
Delphi下的接口编程    
Delphi下的接口编程学习笔记
1.1  为什么使用接口?
    举个例子好了:有这样一个卖票服务,电影院可以卖票,歌剧院可以卖票,客运站也可以卖票,那么我们是否需要把电影院、、歌
剧院和客运站都设计成一个类架构以提供卖票服务?要知道,连经理人都可以卖票,很显然不适合把经理人也包括到卖票服务的继承架构
中,我们需要的只是一个共通的卖票服务。于是,卖票的服务是个接口,电影院、歌剧院什么的只要都遵循这样一个服务定义就能很好地
相互交互和沟通(如果须要的话)。
 
    1.2  如何在Delphi中使用接口
        1.2.1  声明接口
            IMyInterface = interface(IInterface)  //说明(1)
            [{63E072DF-B81E-4734-B3CB-3C23C7FDA8EA}]  //说明(2)
                function GetName(const str: String): String; stdcall;
 
                function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; //说明(3)
                function _AddRef: Integer; stdcall;  //使接口引用数加1。
                function _Release: Integer; stdcall;//使接口引用数减1,当小于等于0时作释放动作。
            end;
            
            说明(1):如果有继续关系则在括号里填父接口,否则省却,如:IMyInterface = interface这样就行。
            说明(2):此GUID可选,如果要实现具有COM特性的接口的话则需要加上,Delphi中对于有GUID的接口在运行时在VMT表的
                         预定位置生成接口的信息,如接口方法的定义、方法参数定义能详细信息。
            说明(3):接口必须实现这三个函数。
 
        1.2.2  接口的实现
            接口服务是由类来实现的。
                TIntfClass = class(TObject, IMyInterface)
                private
                    FCounter: Integer;
                    FRefCount: Integer;
                public
                    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
                    ...
                end;
 
        1.2.3  获取接口
                a. 使用类型转换。
                        如:var aIntf: IMyInterface;
                        begin
                            aObj := TIntfClass.Create;
                            try
                                aIntf := (IMyInterface(aObj);
                                ...
                b. 利用Delphi编译器内建机制。 如:aIntf := aObj。
                c. 利用对象的QueryInterface方法。如OleCheck(aObj.QueryInterface(IID, aIntf)); 只能存取有GUID的COM接口。
                d. 利用as操作符。
                        使用as操作符必须符合下面条件:1.接口必须明确地指定是从IInterface接口继承下来。2.必须拥有GUID值
                    在Delphi7中接口的实现类还必须是从TInterfacedObject继承下来才行,如
                    TIntfClass = class(TInterfacedObject, IMyInterface)
 
        1.2.4  接口和对象生命期             
              因为Delphi会自行检查接口如果在使用后没有释放而在生成的程序里加上释放代码,但也因这样带来了问题,如下面代码:
var
  i: Integer;
  aObj: TIntfClass;
  aIntf: IMyInterface;
begin
  aObj := TIntfclass.Create;
  try
     aIntf := aObj;
     aIntf.GetName...
  finally
     aIntf := nil;
     FreeAndNil(aObj);
  end;
 
  上面的代码执行的话会产生存取违规错误,是因为对接口置nil时已释放接口,而FreeAndNil(aObj)会再释放aIntf一次,而在对aIntf置
nil时已释放了该对象。解决这个问题只要不让接口干扰对象的生命期就可以了,在Release中只需减引用计数而不做释放的动作。
function TIntfClass._Release: Integer;
begin
    Result := InterlockedDecrement(FRefCount);
end;  
 
        1.2.5  接口的委托(Interface Delegation)
            分为两种:1. 对象接口委托    2. 类对象委托。
        . 对象接口委托,假如已有下面接口定义:
IImplInterface = interface(IInterface)
    function ConvertToUSD(const iNTD: Integer): Double;
    function ConvertToRMB(const iNTD: Integer): Double;
end;
 
接着有一个类实现了该接口:
TImplClass = class(TObject, IImplInterface)
private
   FRefCount: Integer;
public
  function ConvertToUSD(const iNTD: Integer): Double;
  ...
end;
 
implementation
 
function TImplClass.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
    if GetInterface(IID, Obj) then
       Result := 0
    else
       Result := E_NOINTERFACE;
end;
 
function TImplClass._Release: Integer;
begin
    Result := InterlockedDecrement(FRefCount);
    if Result = 0 then
      Destroy;
end;
... ...
 
现在有另外一个类TIntfServiceClass要实现IImplInterface接口,不用重新定义,只须使用上面的TImplClass就可以:
TIntfServiceClass = class(TObject, IImplInterface)
private
    FImplService: IImplInterface;
    //FSrvObj: TImplClass;   //如果是用类对象委托的话
public
    Constructor Create; overload;
    Destructor Destroy; override;
    Constructor Create(aClass: TClass); overload;
    property MyService: IImplInterface read FImplService implements IImplInterface;
   // property MyService: TImplClass read FSrvObj implements IImplInterface; //如果是用对象委托的话。
end;
 
实现如下:
constructor TIntfServiceClass.Create;
begin
    FImplService := TImplClass.Create;
end;
 
constructor TIntfServiceclass.Create(aClass: TClass);
var
  instance: TImplClass;
begin
    instance := TImplClass(aClass.NewInstance);
    FImplService := instance.Create;
end;
 
destructor TIntfServiceClass.Destroy;
begin
    FImplService := nil;  //遵照TImplClass使用引用计数来控制对象生命周期,看TImplClass的Destroy实现。
    inherited;
end;
 
    1.2.6  接口和RTTI
        Delphi中在VMT-72位移处定义了接口哥格指针:vmtIntfTable = -72。
相关函数:
        GetInterfaceCount;   //获取接口数量。
        GetInterfaceTable;   //获取接口表格。
        
相关结构:
        TInterfaceEntry = packed record
            IID: TGUID;
            VTable: Pointer;
            IOffset: Integer;
            ImplGetter: Integer;
        end;
 
        PInterfaceTable = ^TInterfaceTable;
        TInterfaceTable = packed record
            EntryCount: Integer;
            Entries: array[0..9999] of TInterfaceEntry;
        end;
 
Self是指向VMT指针的指针,所以:Self.GetInterfaceTable.EntryCount等价于:
    aPtr := PPointer(Integeer((Pointer(Self))^) + vmtIntfTable)^;
 
只要在声明中使用M+/M-指令就能在Delphi中编译出的程序里添加RTTI信息,如:
{$M+}
iInvokable = interface(IInterface)
{$M-}
 
接口的RTTI信息由TIntfMetaData记录结构定义:
TIntfMetaData = record
    name: String;   //接口名称
    UnitName: String;    //接口声明的程序单元名称
    MDA: TIntfMethEntryArray;    //储存接口中方法信息的动态数组
    IID: TGUID;    //接口的GUID值
    Info: PTypeInfo;    //描述接口信息的指针
    AncInfo: PTypeInfo;    //描述父代信息的指针
    NumAnc: Integer;    //此接口继承自父代接口的方法数目
end;
 
TIntfMethEntryArray的定义如下:
type
    TCallConv = (ccReg, ccCdecl, ccPascal, ccStdCall, ccSafeCall);
    TIntfMethEntry = record
        Name: String;    //方法名称
        CC: TCallConv;    //调用惯例
        Pos: Integer;    //方法在接口中的位置
        ParamCount: Integer;    //方法的参数数目
        ResultInfo: PTypeInfo;    //描述方法回传类型的信息指针
        SelfInfo: PTypeInfo;    //描述方法本身的信息指针
        Params: TIntfParamEntryArray;    //描述参数信息的动态数组
        HasRTTI: Boolean;    //这个方法是否拥有RTTI信息的布尔值
    end;
 
    TIntfMethEntryArray = array of TIntfMethEntry;
 
    参数信息TIntfParamEntry定义:
    TIntfParamEntry = record
        Flags: TParamFlags;
        Name: String;
        Info: PTypeInfo;
    end;
 
    TTypeInfo = record
        Kind: TTypeKind;    //数据类型
        Name: ShortString;    //类型信息的字符串格式
    end;
 

文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

文章页数:[1] 


放大字体显示 缩小字体显示 打印文章 推荐给朋友
热门文章
·ASP.NET2.0连接SQL Server数据库详解-.NET教程,Asp.Net开发
·在.net中轻松掌握Windows窗体间的数据交互-.NET教程,.NET Framework
·Java中的类反射机制-JSP教程,Java技巧及代码
·小技巧让pdf文件与word文档之间自由地转换
·j2ee程序员应该掌握的linux知识-JSP教程,J2EE/EJB/服务器
·通过WMI获得硬盘和CPU的物理序列号(VB.net)-.NET教程,VB.Net语言
·firfox浏览器开发人公开firfox2.0开发计划
·VB.net入门(10):补充:类~属性-.NET教程,VB.Net语言
·office2003实战秘笈之excel轻松制胜招
·C#编码规范.doc-.NET教程,C#语言
最新文章
·天涯试水网络口碑营销 邢明:希望与"关键词"媲美_站长访谈
·美梨网站长冰寒的商务之道_站长访谈
·白手起家 新网站流量快速提高之道_站长心得
·照片处理 photoshop简单制作照片柔光效果_photoshop教程
·网络百戒 ---网页外观_站长心得
·utf-8转换gb2312编码,解决统计google搜索来源关键字乱_google推广
·googleadsense作弊不是技术的较量_google推广
·google改进搜索服务 企业可在local更新资料_google推广
·rss订阅对你的网站搜索表现有好处吗?_站长心得
·15种简洁有效的网站推广方法_站长心得
相关主题
  • delphi命令行参数_delphi教程
  • delphi多线程程序示例(与.net一样简单)_delphi教程
  • delphi面向对象支持特点--保护级类成员的应用_delphi教程
  • delphi中的包(三):bpl和dll_delphi教程
  • delphi中的包(一):关于exe的编译、连接和执行_delphi教程
  • 西部数码虚拟主机

    友情链接
    CNNIC 西部数码
    万网 自助建站
    虚拟主机 asp空间
    域名注册 域名
    域名申请 主页空间
    论坛空间 网站空间
    国际域名 虚拟空间
    空间租用 DDOS防火墙
    成都主机托管 四川主机托管
    主机租用 服务器租用
    网站目录 自助建站
    虚拟主机 网址大全
    软件下载
    自助链接
    虚拟主机资讯 特价虚拟主机
    版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!
    关于我们:站长天空:专业提供最新的站长资讯、在线教程、虚拟主机权威评测、虚拟主机性能对比、网站制作教程,开发教程,站长工具。包括网页制作教程、冲浪宝典、编程参考、操作系统、软件教学、行业动态等。
    特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
    发表评论 打印  刷新     关闭