加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 Delphi高手突破

Delphi高手突破.pdf

Delphi高手突破

caogang101
2013-07-25 0人阅读 举报 0 0 暂无简介

简介:本文档为《Delphi高手突破pdf》,可适用于工程科技领域

Delphi高手突破申旻著清华大学出版社(京)新登字号内容简介本书以理论结合实践的方式论述“如何在Delphi中使用面向对象编程方法构建良好设计的程序”的主题。本书第、、章以不同于一般书籍的方式介绍面向对象编程的基础知识及其在ObjectPascal中的语言实现。第、章介绍VCL库的相关知识其中第章为您剖析部分VCL的核心组件源码第章介绍定制、设计组件的方法。第、章介绍程序构架设计其中第章介绍一般性的代码设计准则其内容可以完全脱离Delphi因为这些准则是跨语言的第章是一个完整的代码设计实例以编写一个多工作区的文本编辑器为例从实践角度说明程序构架设计的方法。本书面向Delphi程序员特别是写给那些已经具有一定的实现能力而欲求寻找一种“突破”的Delphi程序员作为他们提高的参考用书同时也可以作为高校学生以及程序爱好者的参考用书。版权所有翻印必究。本书封面贴有清华大学出版社激光防伪标签无标签者不得销售。书名:Delphi高手突破作者:申旻编著出版者:清华大学出版社(北京清华大学学研大厦邮编)http:wwwtuptsinghuaeducn责任编辑:朱英彪印刷者:国防工业出版社印刷厂发行者:新华书店总店北京发行所开本:×印张:字数:千字版次:年月第版年月第次印刷书号:ISBN印数:~定价:元引言感谢您阅读本书!本书是写给程序员的确切地说是写给Delphi程序员的再确切些是写给已经有了一定的实现能力而欲求寻找一种“突破”的Delphi程序员的。在接触了两年的Delphi之后我曾经迷茫过。我可以写各种各样的程序我懂得VCL大多数组件的用法我知道应该调用哪个WindowsAPI来完成我要的功能……但时常会疑惑:这就是写程序了?那时候在大学里读书课余时间很多每天就不停地写写各种程序包括课堂的作业、在网上发布的免费软件以及接到的开发项目。每天都写代码有了Delphi的help和MSDN似乎不会有什么困难只是偶尔会觉得单调。不禁又问自己:这就是写程序了?我迷茫是因为我感到写程序不应该是件单调的事情我迷茫是因为自己总在寻求却始终没有找到一种“突破”的感觉我迷茫是因为我想成为“高手”却不知道如何去做……我有很多理由喜欢Delphi但是应该说正是Delphi的RAD开发方式让我陷入迷茫。我迷惑于RAD使人能力退化还是一种革命性的进步。我相信很多Delphi程序员都会和我有一样的经历。我很幸运就在我迷茫的时候认识了我的同学Lythm受其影响我开始涉猎面向对象编程类的书籍。从《ThinkinginC》到《C面向对象高效编程》、从《InsideCObjectModel》到《设计模式》……然而我一直在寻找却始终没有找到一本完整的以DelphiObjectPascal来讲述面向对象编程方法学的书其间只有一本CharlieCalvert的《DelphiUnleashed》赢得了我的欢心其中关于多态的描述非常精彩只可惜相关篇幅太少。即便如此我仍然感到找到了方向于是就暂时放下手中的键盘钻研起理论。这段时期已经不会再感到迷茫取而代之的是一种自身能感受到的“突破”的感觉。工作后更加有机会将自己所学的东西应用于实际开发之中并不断修正自己头脑中的理论体系。您是否曾经或正在经历我曾经的迷茫呢?如果是那么我想这本书应该是您所要寻找的因为我所要写的就是一本我自己梦寐以求在寻找的书一本以DelphiObjectPascal来讲述面向对象编程方法学、代码设计方法的书。我希望您和我一样幸运不!应该说您比我更幸运因为您比我多了这本书。本书的书名是《Delphi高手突破》我并没有任何文字暗示自己已经成为“高手”Delphi高手突破所谓“高手突破”的解释并不是高手来帮助您突破。写这样一本书我只是希望能把自己的“突破”的感觉与经验和大家共享同时它也是我对前一段时间学习的一个总结。我很喜欢这本书的英文名称是我自己起的我愿意将它叫作《DesigninDelphi》不过请原谅我无法用中文准确地、优美地将它表述出来。~这本书没有什么这是本特殊的Delphi编程方面的书它不会教您如何使用Delphi也不会教您如何使用类似TListBox那样的组件更不会涉及诸如多线程、DLL、API等Windows编程的内容也没有热门的COMDCOM、WebService等。~这本书有什么这本书会告诉您面向对象编程的基础理论会为您剖析VCL的部分源码会告诉您在开始敲键盘写代码之前应该做什么怎样使您的代码的构架被更良好地设计以致便于更容易被维护和修改。~这本书还没有什么看起来这是一本更侧重于讲设计的书。请不要误会这本书还不会教您关于面向对象分析设计(OOAOOD)的内容更没有UML。~这本书究竟有什么就本质来说这本书只讲OOP当然是用Delphi作为载体因为它是写给Delphi程序员的。其中有设计的内容但仅限于代码设计。本书第章就一个实例向您展示代码构架设计的一种可能的方式但此方式并不是惟一的。实例不需要照搬而需要领会。~本书章节介绍本书第、、章介绍OOP的基础知识基本上所有编程语言的书都会有这样的内容但本书一定会带给您不同的感觉。第、章介绍VCL相关的知识。其中第章为您剖析部分VCL的核心组件源码第章介绍定制、设计组件的方法。第、章介绍程序构架设计。第章介绍一般性的代码设计准则其内容可以完全脱离Delphi因为这些准则是跨语言的。第章是一个完整的代码设计实例以编写一个多工作区的文本编辑器为例从实践角度说明程序构架设计的方法。·II·引言~本书的支持网页本书的支持网页为:http:wwwsunistudiocomnicrosoftbookdid作者Email:nicrosoftsunistudiocom希望您喜欢本书以及它的作者我!谢谢。~感谢在此我要感谢为这本书的诞生给予过我帮助的人们。首先我要感谢我的女友Esan在我的写作过程中她一直陪伴在我身边不断地给我鼓励和支持使我得以最终完成写作。其次我要感谢我的同事兼拍档唐沐是他为本书的每一章创作提供了精美、有趣而又富有创意的插图使得本书更富有一些活泼的气氛。再次我要感谢CSDN以及大富翁论坛的热心网友们当我在网络上发表了本书的一些预览节选后他们给我提出了许多宝贵的意见和建议。最后我要感谢清华大学出版社的朱英彪编辑他的宽容和给予我的帮助使得我们的合作非常愉快也使得本书能够顺利完成及出版。申旻年月于珠海·III·第章重新认识Delphi简单性是这个世界上最难获得的东西:它是经验的最终界限也是天才的最终努力目标。GeorgeSandGotoDelphi!Delphi高手突破你已经是一位熟练的Delphi程序员可以运用Delphi快速地写出一个漂亮、实用的程序你热爱Delphi她已经成了你工作、学习中不可或缺的一部分。我假设这些都为真那么你当初选择Delphi作为自己的首选开发工具一定有自己的理由或原因。至少我自己是符合以上所有假设的。现在想和你分享的正是我选择Delphi的理由及原因以及我对Delphi的认识。你可以把我看作一个拥护Delphi的狂热分子虽然那样会让我感到你把我看得太过肤浅我并不承认但是我也不会介意。因为我真的热爱她。第一次接触Delphi的版本是那时候只不过是把她当作VisualBasic一样的RAD工具来用而已。但是随着时间的流逝从Delphi到Delphi、Delphi、Delphi以及Kylix对Delphi的认识也越来越深。她是一个有着丰富内涵的工具让人对她越了解就越对她迷恋越感觉离不开她虽然她只是一个工具而已。Pascal是一种讲究程序美学的语言毫无疑问Pascal代码是最优美的代码基于ObjectPascal(一种支持面向对象的Pascal语言)的Delphi让这种美达到了极至。现在你可以打开Delphi选择“Help”→“About”菜单出现About窗口后按住Alt键然后顺序输入“team”你看到了什么?是的Delphi开发人员名单。感谢他们创造出如此具有艺术气质的开发工具!开发工具“以人为本”论经常可以在各个编程论坛上看到类似这样的问题:“VB还有没有前途?”、“Delphi是不是要淘汰了?”、“MFC是不是要被NET取代了?”……其实这些问题在被提出的当时是没有人能给出答案的。这是因为一种技术、一个产品的前途并不完全是其本身所能左右的还与市场需求、出品公司的发展方向等因素有关。而我们所应该关注的是否就是这些问题的答案呢?我认为不是。我们知道世间万物由原子组成。千变万化的程序归根结底由顺序、循环、分支三种结构构成无论VC的MFC还是Delphi的VCL都是由面向对象技术构建的(暂且不论其面向对象的程度)。当你拨开事物表面的表象后看到的是相同的或近似的本质!而掌握了本质之后就会发现表象的表现形式是那么的理所当然。试想当你能像侯捷(《深入浅出MFC》的作者)那样把MFC剥得体无完肤时还会担心MFC被某某框架所取代吗?从这个角度来说对于一名专业程序员编程的理念是万变不离其宗的。发现问题、分析问题、解决问题的过程是存在着某种模式的当你掌握了这种模式后不同的编程语言、不同的开发环境对你来说是有共通之处的。我认为C是每个专业程序员所必须掌握的。当然并不是说单纯学习其语法(甚至可以忽略一些语法的学习)而是通过C学习面向对象的设计、编程方法。因为C博大精深无所不及。在C中你可以学习到面向对象理论的全部。学习之后你会被C所改造因为在面向对象理论中存在的、但有所争议的特性(如多重继承)在C中都得到了支持。只有在掌握之后才可能作出自己的选择(支持或反对)。在掌握了面向对··重新认识Delphi象的理论之后无论C、ObjectPascal或是Java乃至C#却会感觉到它们的异曲同工之处。那是否就是说开发工具(或许应该称为集成开发环境不过下文还是按我的习惯用开发工具来称呼)之间除了支持的语言不同外就不存在其他差异了?当然也不是。开发工具是帮助用户实现理念的工具也就是构建在基础理念上的上层建筑。开发工具对于用户所要实现的理念的支持程度以及对实现过程的简化程度就是开发工具的体贴度。开发工具于程序员犹如兵器于士兵兵器不顺手未战先败一半。我一直很喜欢诺基亚手机的广告词:科技以人为本!是的“人”才是本工具的使命是辅助人更快、更容易地达到目的。因此开发工具也应该以人为本!作为一名程序员作为开发工具的最直接的使用者我希望我所使用的开发工具真正是我的伙伴、助手它能给我带来自由的感觉让我自由地在代码的世界中驰骋它能迁就我、适应我而不是相反给我套上枷锁!如今在Windows平台上有许许多多的开发工具可以选择VisualC、VisualBasic、Delphi、CBuilder、JBuilder……它们基于不同的编程语言、忠于不同公司的产品理念。从这个角度来说它们之间的差异是非常大的。那什么样的开发工具才是优秀的、体贴的、以人为本的?我的标准是符合以下四点:()能够将要解决的问题简化并以某种理念快速实现之。()不隐藏任何用户想知道的细节。()可以忽略用户所不想知道的细节。()主动去适应不同层次的程序员。符合以上四点的开发工具有吗?我的答案是:有!那就是Delphi!她将一切化繁为简却从不阻止我寻求真实。用户可以在她构造的简化了的VCL的虚拟世界中完成任务。也可以钻进VCL的世界以探询她和现实世界(即Windows平台的真实接口)的映射关系学习她的Framework的设计。此外还可以扩展那个虚拟的VCL世界以适应自己的需要。我为存在着这样的开发工具而感到幸运更为幸运的是我可以选择她和她一起完成我的工作(现实中项目中使用什么编程语言、开发工具时常并不是个人所能左右的会受很多因素制约。例如客户的硬件环境、操作系统环境、开发环境、开发工具的成本、许可证等。因此能选择自己喜欢的开发工具进行开发工作实在是很幸运的)!通过C学习面向对象的理念用Delphi去解决现实世界的问题这是我的做法。同时也验证了那句话:学从难处学用从易处用。真正的程序员用C聪明的程序员用Delphi。那么真正聪明的程序员用C来理解Delphi!Delphi更多的优势用过很多的主流开发工具为什么还是选择了Delphi?也许是因为没有深入地去熟悉··Delphi高手突破其他开发工具吧但Delphi本身的优秀至少是原因之一!Delphi优秀在何处?‹开发的高效Delphi是一个RAD(RapidApplicationDevelopment快速开发工具)它有可视化的开发环境。当然具有类似功能的开发工具也不少(如VisualBasic)但Delphi有如下的独到之处:()Delphi是真正面向对象的。其基于OO技术构建的VCL库中的所有组件都可以被继承以创建新的组件包括窗体类TForm。相比之下ActiveX组件缺乏这种灵活性。()Delphi的CodeInsight技术(即代码自动完成功能)是建立在编译器信息上的而VB使用的是类型库信息。使用编译器信息的好处是更具灵活性。不过时常有程序员抱怨Delphi的代码提示时间太长。其实我个人感觉是习惯了其速度之后能体会到一种节奏的快感。‹语言的高效Delphi基于ObjectPascal语言。这是一种真正支持面向对象而又优雅美观的语言。它在功能的健全上毫不逊色于各种其他的面向对象语言但同时又不贪多不盲目地增加复杂性。使得开发者运用各种模式进行设计时都能得到完善的支持实现时却不用考虑太多语言编译器细节。‹编译的高效可以说Delphi是Windows平台上最快的高级语言本地代码编译器。编译速度快有什么好处呢?快速的编译器可以使用户频繁地在修改代码和编译运行的状态间切换。至少我自己已经非常习惯了这样的工作方式:运行程序看一下效果退出程序修改少量代码再运行程序。而Delphi的编译器从来不会让我有等待的感觉。‹执行的高效Delphi不但编译速度快生成的目标代码的执行效率也非常高。Delphi与CBuilder使用的是同一个后端优化器因此其生成的代码的效率跟优秀的C编译器生成的代码相同。Delphi生成完全本地代码因此Delphi编译结果的可执行文件可以被独立执行、分发(对于“绿色软件”的开发这一点十分重要)不需要其他运行库支持。当然也可以选择动态链接编译这样可以大大减小可执行文件的长度。不过在这种情况下分发程序时必须同时分发必要的运行库文件。‹维护的高效C把许多决策权给了程序员因此功能十分强大但同时要用C写出出色的面向对象的代码就要求程序员具有一定的素质。而VisualBasic则根本没有提供面向对象的编程机制(VB及先前版本都是基于对象而非面向对象)。而Delphi程序员虽然会在一定程度上被限制在VCL提供的框架中(当然完全可以在Delphi中摆脱VCL编程)但相对来说更容易建立良好设计的代码。代码框架的优良使得软件维护成本大大降低。··重新认识Delphi基于以上所有理由我选择Delphi!本书主题我们平时都会写很多代码为公司、为自己或者为朋友。有时为了验证自己的一个想法或学习某一种技术会写一些试验性的代码。这样的代码的生命周期很短基本不需要维护随意写一下就可以。但是当真正要完成一个项目的时候代码设计就显得非常重要了。因为这样的代码是需要长期维护不断修改或增强的。设计凌乱的代码会使得维护非常困难或者根本不可能修改这样的代码意味着产生更多的bug甚至是灾难。因此代码在被编写之前需要先被设计。这里所说的设计并不是指功能设计而是指程序员在编码之前先对代码框架的设计以使得今后代码更容易被理解、被维护。经常听到这样一种说法:程序员的编程寿命只到岁。我却从不相信此类说法也许岁以后实现能力(其实就是工匠能力)是有下降的可能而设计能力是随着经验的增加不降反升的。这才是最宝贵的。国外的软件开发小组一般的骨干都是岁上下的人那些才是大师级的程序员而所谓的过了岁就不能当程序员的程序员似乎根本没有资格被称为程序员。软件工程要将程序员变成编码员变成流水线上的一环设计工作由专门的设计师完成(如框架设计师)。也许分工细化是趋势但是是满足于做编码员还是希望成长为设计师取决于我们的眼光及努力。放开眼光而不是将自己局限、沉迷于“实现高手”。实现能力是基础有一定的实现能力才可能成长但是它只是必要条件而不是充分条件。否则就像爬到山腰就以为自己到了山顶停滞不前了。那么你只可能是编码员你的编程寿命也只到岁。在有了这样的眼光之后希望本书可以助你起步。国内出版的Delphi相关书籍基本都是讲解实现的。本书的书名是《Delphi高手突破》那么假设你现在已经是Delphi高手了。所以本书不会涉及太多的实现技巧虽然也有实例代码但重点在于其构架的设计而并非实现的讲解。至此读者也许已经猜出本书的主题了:如何在Delphi中使用面向对象技术构建良好设计的代码。在我看来写代码是艺术创作优雅的代码可以自解释而不需要过多的注释。当注释过多的时候就该考虑设计是否合理了。写书应该也是艺术创作如果能把自己的认识、经验艺术地告诉读者而不需要过多的“注释”(浪费篇幅的废话)就非常成功了。我希望自己能做到至少尽量吧。小结我相信走上编程这条路对于我来说是必然的。能成为专业程序员也是我所梦想··Delphi高手突破并实现了的。但是Delphi的出现以及被我所认识、熟悉、迷恋并成为工作的一部分应该说是一个意外的惊喜。在此我所想说的就是对于自己的志向就更坚持一些吧。当你清醒地定位了自己之后清楚地知道自己所选择的道路之后就不用有所疑问、有所顾忌了坚持走下去。最终虽然未必会成功(当然每个人对成功的定义是不一样的)但爱我所爱无怨无悔!··第章面向对象编程理论基础面向对象是一种思维方式(理念)是一种方法论。面向对象并不困难!Delphi高手突破每个软件开发人员都会经常听到、看到“面向对象”这个词程序员们也时常会把它挂在嘴上。那么什么是面向对象?什么是面向对象编程?是不是写几个类就算面向对象了?为什么要面向对象?因为别人都用所以我也要用?显然并不是在程序中写了几个类就算面向对象编程了用面向对象编程也并不是为了赶时髦。“结构化编程”(SP)是一种编程方法是用计算机的视角来抽象问题的方法。而“面向对象编程”(OOP)也是一种编程方法它从更接近真实世界的视角来分析问题使用更接近人们理解真实世界的方法来抽象问题这种方法称为“面向对象”(OO)。“面向对象”这个词代表的是一种认识世界、分析问题、解决问题的方法因此它是一种方法论。而面向对象编程(OOP)则是将之应用于编程的方法。当用户会使用面向对象的方法去思考用面向对象的模式去分析和解决问题的时候才是真正的“面向对象”了。本章会试图使用ObjectPascal语言来告诉用户面向对象编程的理论知识包括面向对象编程的特性以及这些特性在语言中的实现、在语义上对程序设计的影响。类和对象的本质“类”和“对象”是面向对象编程中最基本的概念很多人都可以轻易地回答出什么是类什么是对象:“类”是对一类事物的抽象(abstract)是创建对象的模板“对象”是类的实例(instance)。但这只是简单的概念解释而已除此以外还必须清楚类和对象的本质即从语言和语义本身的角度来看它们分别代表什么它们是如何支撑起庞大的面向对象的世界的。语言的“类”和“对象”从语言的角度来说“类”是用户自定义的数据类型“对象”则是“类”类型的变量。类定义了所生成的对象的模板于是也决定了对象所占用的内存空间。类成员分为两种:方法(即C中的“成员函数”笔者个人比较喜欢“成员函数”的叫法但“方法”已经是ObjectPascal的一个术语。在Delphi相关的书中称“方法”更合理一些因此下文全部以“方法”称呼)和数据成员。数据成员表示类对象的状态而方法则是改变类状态的操作。当用class关键字声明一种类型时就创造了一个类:typeTMyClass=classend··面向对象编程理论基础虽然在TMyClass中还没有为它定义任何成员但是它的确是一个类完全可以创建这个类的对象实例:varMyObj:TMyClassbeginMyObj:=TMyClassCreate()Create()是这个类的构造函数它负责初始化对象数据成员。生老病死是人之常情对象也一样会有被销毁的时候:MyObjFree()不过Free()方法不是类的析构函数Free()负责的是调用类的析构函数来销毁对象。至于采用这种机制的原因稍后会讲述。现在就来探讨一下ObjectPascal中对象生存与销毁的秘密吧!每个应用程序可以获得的内存空间分为两种:堆(heap)和栈(stack)。堆又称为“自由存储区”其中的内存空间的分配与释放是必须由程序员来控制的。例如用GetMem函数获取了一定大小的内存空间则在使用完后必须调用FreeMem函数将空间释放否则就会发生所谓的“内存泄漏”。“借债还钱天经地义”。栈又称为“自动存储区”其中的内存空间的分配与释放是由编译器和系统自动完成的不需要程序员过问。函数调用时按值传递的参数所占空间、函数中的局部变量等都是在栈中被分配空间的。比如函数:vari:Integerj:Integerbeginfori:=todoend其中i和j的空间是由编译器在栈中分配的。在函数末尾也不需要程序员手动去释放这两个变量所占的内存空间。ObjecgtPascal遵循所谓的“引用值”模型。无论在参数传递还是变量定义中简单类型(如Integer、Cardinal、char以及record等)被按值传递或使用其内存空间从栈中分配。··Delphi高手突破而复杂类型(class)则被按引用传递或使用其内存空间从堆中分配。在ObjectPascal中所有对象(类类型的)都被建立在内存的堆空间上而非栈上。因此在创建对象时其构造函数不会被编译器自动调用也没有C中所谓的“默认构造函数”。调用构造函数来创建对象以及调用析构函数来消灭对象都是程序员的职责。如何为自己的类编写构造函数呢?在调用了诸如MyObj:=TMyClassCreate()与MyObjFree()之后究竟发生了哪些事情呢?‹构造函数与对象内存的分配定义构造函数使用Constructor关键字。按惯例构造函数名称为Create(当然也可以用其他名称但那绝非优良的设计)。如:typeTMyFamily=class为你的家庭定义的类PrivateFMyFatherName:String你父亲的名字FMyMotherName:String你母亲的名字……你家庭中的其他成员PublicConstructorCreate(strFatherName,strMotherName:String)……其他方法End创建对象时则直接调用构造函数形式如下:MyFamilyObject:=TMyFamilyCreate(′Zhang′,′Li′)也许有人会问如果没有为自己的类提供构造函数它的对象能否被建立呢?答案是:可以。在了解了构造对象的过程之后就会明白为什么答案是“可以”。要创建出一个对象首先需要分配对象本身所占用的内存空间然后执行类的构造函数以初始化各数据成员、申请对象需要的资源或创建其内部包含的子对象。编译器在执行类似MyFamilyObject:=TMyFamilyCreate(‘Zhang’,‘Li’)这样的构造函数之前会插入以下几行汇编代码:testdl,dljz$addesp,$callClassCreate注意这行代码··面向对象编程理论基础以上代码的最后一行代码调用的是systempas文件的第行的ClassCreate函数(以Delphi为准)该函数具体为每个对象分配合适的内存。这个动作也就是所谓的“编译器魔法”(CompilerMagic)由这个动作完成真正的对象的内存分配一个对象在这个时候已经有了外壳。内存分配完成后是调用类的构造函数即TMyClassCreate()以初始化数据成员。构造函数由定义类的程序员编写也就是说将对象初始化成何种模样是由程序员决定的。至此一个对象已经诞生了。之后编译器会再插入以下几行汇编代码:testdl,dljz$fcallAfterConstructionpopdwordptrfs:$addesp,$c其中主要的工作是调用每个对象实例的AfterConstruction。Borland宣称这个调用在Delphi中没有用它的存在是为CBuilder所保留的。不过由于AfterConstruction被声明为虚方法(virtualmethod)因此完全可以利用它做一些善后的工作尤其是在编写组件时。这些内容将在后续章节讲述暂且不必理会。可见创建一个对象的步骤并不十分复杂比之“十月怀胎”轻松了不知道多少倍。由于对象本身所占内存的分配是由编译器完成的因此即使没有构造函数对象也一样可以被构造。构造函数的职责只是初始化对象的数据成员没有构造函数只意味着不会对数据成员进行初始化而已编译器会对所有数据进行清零初始化。此外由于ObjectPascal中所有类(除了TObject类本身)都是从TObject类派生因此编译器会调用TObjectCreate()构造函数。不过这个函数只是一个空函数。假如上面定义的TMyFamily类没有定义构造函数则TObjectCreate也不会对TMyFamily的数据成员(FMyFatherName、FMyMotherName)进行初始化因为TObjectCreate()根本就不认识你的父、母亲!‹析构函数与对象内存的回收定义析构函数使用Destructor关键字。按惯例析构函数名称为Destroy。如:typeTMyClass=classPublicDestructorDestroy()overrideEnd之所以在析构函数声明最后加上override声明是为了保证在多态的情况下对象能正··Delphi高手突破确被析构(关于多态将在节中详述)。如果不加override关键字则编译器会给出类似“Method‘Destroy’hidesvirtualmethodofbasetype‘TObject’”的警告提示。警告的意思是用户定义的Destroy隐藏了基类的虚方法TObjectDestroy()那样的话在多态的情况下就无法正确析构对象了(具体原因请查节)。È注意:析构函数都需要加override声明。与构造函数类似如果在类中没有特殊的资源需要被释放也可以不定义析构函数TObject同样定义了一个空的析构函数。在析构对象的时候应该调用对象的Free()方法而不是直接调用Destroy()。MyFamilyObjectFree()这是因为在TObject的Free()方法中会判断对象本身是否为nil如果不为nil则调用对象的Destroy()以增加安全性。既然有这样更安全的做法当然没有理由不这么做了。È注意:永远不要直接调用对象的Destroy()而应该是Free()。要销毁一个对象其顺序与创建对象正好相反。首先是释放对象申请的资源以及销毁内部的子对象之后是回收对象本身所占的内存空间。当程序执行到诸如MyFamilyObjectFree()这样的代码时首先执行TObjectFree()方法:procedureTObjectFreebeginifSelf<>nilthenDestroyend在TObject的Free()方法中调用了对象的析构函数。然后编译器会在执行完Free()方法之后插入以下几行汇编代码以完成第二个步骤(回收对象本身所占的内存空间):callBeforeDestructiontestdl,dljle$callClassDestroy这些代码所做的工作与构造对象分配内存时所做的是对应的其中所调用的ClassDestroy函数会精确地回收对象内存空间。以下一个例程说明了如何使用构造函数和析构函数:unitDllLoader··面向对象编程理论基础interfaceuseswindowsTypeTDllLoader=classProtected之所以是protected成员是为了在其派生类中具体实现加载某DLL时派生类能够访问该句柄FhDLL:HMODULEPublicConstructorCreate(strDLLName:String)DestroctorDestroy()overrideEndImplementationConstructorTDllLoaderCreate(strDLLName:String)BeginFhDLL:=LoadLibrary(strDLLName)构造函数中加载DLLASSERT(FhDLL<>)EndDestructorTDllLoaderDestroy()BeginIfFhDLL<>thenbeginFreeLibrary(FhDLL)析构函数中释放DLLFhDLL:=EndEndEnd‹对象所占空间大小前面为对象分配内存空间时谈到每个对象会占用一定的内存空间那么这个大小是如何确定的呢?对象的大小就是其数据成员所占用的内存空间的总和其方法(函数)是不占用对象空间的。不过它不是一个简单的加法还与编译器的“数据域对齐方式优化”有关稍后会详述。··Delphi高手突破È注意:对象的大小只取决于其拥有的数据成员。TObject实现了一个InstanceSize()方法它可以取得对象实例的大小。下面以一个示例说明对象在内存中的布局。首先定义一个TMyClass其中包含个数据成员和个方法。先看一下类的定义:TypeTMyClass=classPublicFMember:IntegerFMember:IntegerFMember:WORDFMember:IntegerProcedureMethod()End然后在Application的主Form中放入一个Memo和一个Button并在Button的OnClick事件中写下在Memo中显示出对象位置的代码。该程序源代码清单如下:unitUnitinterfaceusesWindows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,StdCtrlstypeTForm=class(TForm)Button:TButtonMemo:TMemoLabel:TLabelprocedureButtonClick(Sender:TObject)end自定义的TMyClass类TMyClass=classPublicFMember:IntegerFMember:IntegerFMember:WORD··面向对象编程理论基础FMember:IntegerProcedureMethod()EndvarForm:TFormimplementation{$R*dfm}procedureTFormButtonClick(Sender:TObject)varObj:TMyClassbeginObj:=TMyClassCreate()withmemoLinesdobeginAdd('对象大小:'IntToStr(ObjInstanceSize))Add('对象所在地址:'IntToStr(Integer(Obj)))Add('FMember所在地址:'IntToStr(Integer(ObjFMember)))Add('FMember所在地址:'IntToStr(Integer(ObjFMember)))Add('FMember所在地址:'IntToStr(Integer(ObjFMember)))Add('FMember所在地址:'IntToStr(Integer(ObjFMember)))endObjFree()end{TMyClass}procedureTMyClassMethodbeginnocodeendendButton的Click事件中所做的事情是首先创建TMyClass类的实例然后将对象大小以及每个数据成员的地址输出到Memo中。该程序的代码和可执行文件可在配书光盘的ObjectSize目录下找到运行程序并单击“开始”按钮后其界面如图所示。··Delphi高手突破图ObjectSize程序界面图的Memo中显示出了想要的结果。也许读者会看不清图片中的结果不妨介绍一下:其中显示了对象大小为个字节对象所在首地址是(也许每次运行对象被创建的地址会不同这没有关系在此主要关心的是各地址之间的差值)FMember所在地址是FMember为FMember为FMember为。现在来分析一下:根据对象首地址以及大小可以算出对象占用的内存空间范围为~。而第一个成员却在它与对象的首地址之间有一个字节的空缺这个字节存放的是一个指向对象的VMT(虚方法表)的指针。关于VMT将在节多态的本质中详细讨论此处暂且不表。~这个字节即FMember所占空间(位整数)。同样~为FMember所占空间。比较容易令人疑惑的是FMember计算可知它所占地址范围为~同样也是个字节但在此定义的FMember其实是Word类型(位)为什么它会占用位空间呢?这与编译器的字节对齐优化有关编译器会将无法合并的小于位空间的数据域填充到位大小以加快存取速度。也就是说FMember同样需要占用个字节空间。可以自己试一下如果将以上TMyClass类定义中的FMember也改成Word类型编译器会把FMember和FMember合并成一个位空间于是对象大小就变成了。FMember所占的空间没什么意外为~。整个对象的内存布局如图所示。内存地址VMT指向VMT的指针FMemberFMemberFMemberFMember图对象内存布局图(阴影部分为字节对齐优化时被填充的区域)··面向对象编程理论基础另外也可以看到TMyClass类中惟一的方法Method()没有在对象的空间中出现。‹“类方法”与“类引用”类型一般所称的“方法”都是指“对象方法”。也就是说执行该方法将可能导致对象的状态发生改变即该方法可以更改对象的数据成员的值。如:TMyClass=classprivateFMember:IntegerpubicprocedureSetValue(Value:Integer)endprocedureTMyClassSetValue(Value:Integer)beginFMember:=Valueend其中SetValue即为典型的对象方法。除了“对象方法”外还有所谓的“类方法”也就是属于类级别的函数(而非对象级别的)。它可以改变类的状态(而非对象的状态)。定义类方法只需要在一般的方法声明前加上class关键字。如:classfunctionTObjectClassName:ShortString既然类方法是进行类级别的操作因此在类方法中是无法对对象的数据成员进行访问的。在ObjectPascal中还有一种“类之类”的类型也就是所谓的“类引用”。一般所称的类是对其实例对象的抽象。定义一个类:TMyClass=class而“类引用”类型却是对“类”的抽象(元类)所以被称为“类之类”。定义一个“类之类”:TMyClassClass=classofTMyClass“类之类”可以直接调用“类”的“类方法”。如:TMyClass=classpublicclassprocedureShow()endTMyClassClass=classofTMyClass··Delphi高手突破varMyClass:TMyClassClassMyObj:TMyClassbeginMyObj:=MyClassCreate()MyClassShow()MyObjFree()end在此例中TMyClassClass作为TMyClass的元类可以直接调用TMyClass的类方法。此前提到过的类构造函数其实就是一个类方法因此可以如同MyObj:=MyClassCreate()来创建对象其结果与MyObj:=TMyClassCreate()完全相同。但是析构函数则不是类方法而是普通的对象方法。因为析构函数只能销毁一个对象实例其操作结果并非作用于该类的所有对象。因此销毁对象只能通过对象来调用析构函数而不能通过类方法:MyObjFree()“类方法”和“类引用”有什么作用呢?它主要用在类型参数化上因为有时在编译时无法得知某个对象的具体类型而需要调用其类方法(如构造函数)此时可以将类型作为一个参数来传递。在Delphi的帮助文档中有这样一个例子:typeTControlClass=classofTControlfunctionCreateControl(ControlClass:TControlClassconstControlName:stringX,Y,W,H:Integer):TControlbeginResult:=ControlClassCreate(MainForm)withResultdobeginParent:=MainFormName:=ControlNameSetBounds(X,Y,W,H)··面向对象编程理论基础Visible:=TrueendendCreateControl函数具体创建一个控件对象但是由于它在编译时期并不知道需要其创建的对象的具体类型因此其第一个参数ControlClass的类型是TControl的类引用类型TControlClass这样就可以将所需要创建控件的类型延迟到运行期去决定。例如在运行期要创建一个TButton类型的控件对象:varBtn:TButtonbeginBtn:=CreateControl(TButton,‘Button’,,,,)end还有经常可以在Delphi生成的Application的project文件中找到这样的代码:ApplicationCreateForm(TForm,Form)TApplication的CreateForm()方法的第一个参数也是类引用类型的:procedureTApplicationCreateForm(TComponentClass=classofTComponent类引用类型InstanceClass:TComponentClassvarReference)允许在运

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/49

Delphi高手突破

仅供在线阅读

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利