


下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Delphi接口和编程两大陷阱Delphi接口和编程两大陷阱2012-06-0100:20150人阅读评论(1)收藏举报Delphi接口编程的两大陷阱前一阵写了一个通过接口扩展功能的例子,当时由于指针和接口的转换,导致了很多错误,最近乂接触到了一个类和接口混用的例子,导致程序的指针在传递中变了地址或者内容,导致读到了错误的地址,现在将接口和类之间的情况进行一下汇总。陷阱一、接口的类型转换陷阱1)不能把一个对象引用强制转换成这个引用的类型没有声明实现的接口,即使这个对象实际实现了这个接口呵呵,优点拗口。2)当把一个对象变虽赋给一个接口变虽,在把这个接口变H赋还给对象变H时,这个对象变H的地址已经
2、变了,也就是不再是原来的对象了,而是指向一个错误的地址例如:I1=interfacefunctionDo:Boolean;end;TC1=classATT1:Integer;end;TC2=Class(TC1,I1)ATT2:Integer;functionDo:Boolean;end;Intf1:I1;OBJ1:TC!;OBJ2:TC2;OBJ2:=TC2.Create;OBJ1:=OBJ2.I1(OBJ2).DO;正确。I1(OBJ1).DO;编译失败因为OBJ1的类型TC1没有声明实现I1所以不能转换成I1,即使OBJ1确实实现了I1。如果把对象转为接口再转回来也会有问题。OBJ2:=T
3、C2.Create;OBJ2.ATT1:=0;Intf1:=OBJ2;/正确。OBJ2:=Intf1;TC2(Intf1).ATT1:=0;/运行期非法地址访问错误。OBJ2.ATT1:=0;/运行期非法地址访问错误。也就是,从对象引用转换成指针引用后,地址改变了,但是由指针引用再转回对象引用时地址没有变回来Delphi的bug?。陷阱二、接口的生存期管理我认为接口是不需要生存期管理的,因为接口根本不可能生成真正的对象。但是Delphi却乂一次打击了我的常识咦,为什么要说“乂”呢?,它的接口是有生存期的,而且必须实现以下三个方法:functionQueryInterface(constIID:
4、TGUID;outObj):HResult;stdcall;function_AddRef:Integer;stdcall;function_Release:Integer;stdcall;每次都要实现这三个方法是比较麻烦的,而且更重要的是,我不知道Delphi什么时候用以及怎么用这三个方法?所以我也不知道怎么实现这三个方法。如果不想自己实现这三个方法,你可以使用TComponento因为TComponent已经实现了这三个方法,所以可以从它继承,就不用实现这三个方法了。这样就可以放心使用了吗?答案是否认的。因为Delphi在你把接口变虽置为nil时偷偷的因为很出乎我的意料调用了_Releas
5、eofunction_IntfClear(varDest:Ilnterface):Pointer;varP:Pointer;beginResult:=Dest;ifDest<>nilthenbeginP:=Pointer(Dest);Pointer(Dest):=nil;IInterface(P)._Release;end;end;而_Release时乂做了什么呢?functionTComponent._Release:Integer;beginifFVCLComObject=nilthenResult:=-1/-1indicatesnoreferencecount
6、ingistakingplaceelseResult:=IVCLComObject(FVCLComObject)._Release;end;不是Com对象的话,就什么也没作。我们作的不是Com对象,是不是就没有任何问题了呢?答案依然是否认的,考虑如下情况:OBJ2:=TC2.Create;tryIntf1:=OBJ2;Intf1.DO;FinallyOBJ2.Free;Intf1:=nil;End;会怎么样呢?会出非法地址访问错误。为什么?上面说过把接口引用设为nil时,会调用_IntfClear,而_IntfClear乂会调用对象的_Release,而这时这个对象已经释放了,自然就出非法地址
7、访问错误啦。有人说多此一举吗,接口引用只是个地址,没必要手动设为nil。OBJ2:=TC2.Create;tryIntf1:=OBJ2;Intf1.DO;FinallyOBJ2.Free;End;结果可能还会出你的意料,还是非法地址访问错误。为什么?因为Delphi编译器要了个小聪明,它认为你忘记把这个地址引用置为nil了,所以你会自动给你加上,看来Delphi编译器聪明过头了Jo怎么解决呢?方法1,先把接口引用置为nil,再释放对象。Intfl:=nil;OBJ2.Free;方法2,把接口引用强制转成指针类型再置为nil。Pointer(Intfl):=nil;此时相当于直接把地址清零,不会
8、调用_IntfClear。我倾向于使用第二种方法,这样你就不用考虑先释放谁的问题了。而且有些设计模式中你可能只持有接口引用,而且你也不知道引用的对象什么时候释放,此时就必须使用方法2例如考虑Composite模式。TComposite=class(TComponent,I1)PrivateinterList:TXContainer;/一个容器类,存放“叶子”的接口引用PublicProcedureAdd(AIntf:I1;functionDO:Boolean;End;它应该释放它的“叶子”吗?显然不是,那“叶子”是不是一定会晚于这个“合成对象”对象释放呢?我想也不一定吧。如果强制这样规定的话,
9、就失去很多的灵活性。所以我们肯定想这些接口引用置nil时,不会和原对象发生什么关系,以免对象被释放后出非法地址访问错误。考虑使用什么容器呢?array?TList?TInterfaceList?首先想到肯定是TInterfaceList了,因为我们是要容纳的就是接口。但是对他进行Free时,它会把它所有容纳的接口置为nil,这正是我们不想要的。或者我们可以在Free之前先把它存储的接口引用转为指针再置为nil。forI:=0tointerList.Count-1doPointer(interList.Itemsi):=nil;可惜的是,编译错误“ErrorXXXX.pas(XX):Leftsi
10、decannotbeassignedto”。然后我们试一下array。interList:ArrayofI1;动态数组是不要释放的。好似很好用,但是编译器释放它时还是会对每个元素置为nil的,而且是作为接口,仍然有非法地址访问错误的可能。可以这样fori:=Low(arr)toHigh(arr)doPointer(arri):=nil;但是这毕竟是违反编码习惯的,而且每次使用都要记得作,不记得作也可能不会马上出错,所以有可能成为隐患。最后,就是使用TList。不过TList中是指针,所以Add时必须这样procedureXXX.Add(AIntf:I1)BeginInterList.Add(P
11、ointer(AIntf);End;由于它本来就保存的是指针,所以释放时也不需要特殊处理。好似比较完美,但是还是有一个陷阱,如果你写了这样的代码会怎么样呢?interList.Add(TC2.Create);或者Obj2:=TC2.Create;interList.Add(Obj2);错!因为保存的是纯粹的指针,所以转化为接口时,对象引用到接口引用的地址转换没有进行它也不知道如何进行所以调用接口声明的方法时就乂是一个非法地址访问错误。只能这么写:interList.Add(Pointer(I1(TC2.Create);虽然有些麻烦,相比之下这已是最正确方案我所知的了因为你如果你忘记转会在第一次
12、调用时就出错,比较容易发现错误相比于使用array。1、使用Tlist来管理接口引用。2、增加时要把对象转型成Interface再转型成Pointer,如果本来就是接口引用的话直接转为Pointer即可。3、对于没有使用Tlist来管理的接口引用。对于接口的引用要用下面的方法手动置为nil:PointerIntfRef:=nil;另外,TInterfacedObject也实现了Ilnterface的三个方法。所以从它继承也可以省去自己实现这三个方法的麻烦。但是它的_Release是这样实现的:functionTInterfacedObject._Release:Integer;beginResult:=InterlockedDecrement(FRefCount);ifResult=0thenDestroy;end;接口引用的置nil会调用接口的Release,所以有可能会把对象给释放掉,我当时可是被它吓了一跳,多亏我没用过它。也就是这样实现下比从TComponent继承带来更大的麻烦。除非特殊用途,不建议使用。上面对接口的所有讨论,只限于普通使用的语言级
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030抗菌肽生物农药登记政策松绑预期与有机农业市场导入策略研究报告
- 2025-2030抗病毒涂层材料在医疗领域的应用场景与商业化路径评估报告
- 2025-2030托育从业人员心理压力源分析与职业保障研究
- 2025-2030微量营养素缺乏与幼儿工作记忆损伤的分子机制研究汇编
- 2025-2030律师行业人工智能应用场景与效率提升方案报告
- 2025-2030律师事务所行政管理体系优化与运营效率提升研究
- 2025-2030律师事务所行业教育法律业务市场需求研究报告
- 华为企业管理经典案例分析
- 半导体制造流程标准操作手册
- 七年级英语听力练习及答题技巧
- 预防医学考试题+答案
- 二年级上册数学北师大版课件第5课时 小熊开店
- 跌倒坠床原因分析预防措施
- 52206马工程组织行为学课件
- 我和我的祖国课件
- 各类食物营养与配餐(蛋类的营养)课件
- 公司内账管理系统
- 全国细菌耐药监测网信息系统-附件
- 妇产科产前诊断技术服务临床医师考核题(附答案)
- 校园欺凌工作台账(完整资料)
- DB33∕T 1146-2018 浙江省城市轨道交通规范
评论
0/150
提交评论