6--Delphi的源头TObject
用过delphi的朋友都知道,在Delphi里编代码,所有的类都会继承一个TObject的对象。TObject可以说是DELPHI各类的源头,万物起源之鼻主。它之所以这么重要,因为DELPHI的VCL框架的各类都是因为它而出来的。该类是有OBJECT PASCAL语言定义的,之前我多次提到我看框架的感受:那就是要重视生命周期。既然是面向对象的方法来定义,有开始便有结束。如果一个对象没有开始和结束的话,那么在创建该对象的时候是无法给它分配内存也就无法完成初始化的工作了。所以结合万物起源之根本,肯定有一个Create方法和Destory方法。当然这个方法肯定需要由一个constuctor和destructor的函数来修饰。所以我们会在VCL的类源码中可以看到各个类都有自己的构造函数和析构函数。通过构造函数为对象分配了内存,因此当该对象的生命周期结束时就需要将所占用的内存归还给系统,这是一个反向的动作了。
我们在调试程序时,在一个对象析构的时候经常会发现系统先析构自己占用的资源然后再去释放TOBJECT为其分配的资源。通常TOBJECT对象会将destructor Destrory方法设为虚方法(virtual)。这就是为了解决TObject的派生类可能分配额外资源,所以派生类通常是覆盖的(override)方法。
当对象分配了内存之后,有一个过程我们可能是看不到的。那就是将对象分配的内存转成实际存储在内存中对象。这应该是VCL有一个专门的内存编译器做的事情。对象初始化的工作跟RTTI和接口等都息息相关起来。当然创建和销毁是需要同时考虑的事情,要不然就会出现内存泄漏的问题。纵观VCL的TOjbect对象,一般具备了对象的创建、销毁、消息分配及对象的识别等功能。
当然当然,TObject对象要做这些事情,是需要一个强大的数据结构来支撑的。在DELPHI7版本的SYSTEM.PAS里我曾看到过关于这个结构的定义。也许你要问VMT是什么?VMT起初我的理解也很晦涩,后来仔细阅读相关资料有一个叫MetaData的术语围绕着它。MetaData的意思就是描述数据结构欣喜的数据,就像我们在数据库中描述一个表的字段名称、字段格式及字段大小等的信息。所以在程序在调试中,代码中相应的对象都是存储在该数据结构里的,该结构都是保存着相应方法对应的地址,我们在调试程序时BUG信息通常会出现一些地址。是的,这些信息就是从该结构中读取出来。这么一说,VMT实际上还是比较简单的,它无非就是编译器用来处理对象的数据结构而已。
好了要说说一个最重要的概念,在我用JAVA开发代码经常听到什么泛型编程之类的术语。后来仔细发现,这些概念其实在VCL里早就做了详细的描述,相应的方法:upcast和downcast。upcast是指派生类转父类的过程,也就是我们常说的向上转型,而downcast则是说父类转变类型变成派生类的过程,也就是我们常说的向下转型了。运用向上转型,和向下转型其实是需要有相应的理解才能将代码写好的。在前些年电子商务网站的开发过程,我曾看过一段泛型代码,大概描述一下:定义了一个父类定义了基本的消息的基本字段,定义了一个派生类定义处理实际业务的字段。这个程序员用了工厂模式实现复杂的业务,实际的业务在派生的对象中装填字段,而在实际的处理却是向上转型的方式,用父类对象处理!这样的写法却是真正理解的泛型编码的真意!其实DELPHI的VCL都诠释了这些方法,只是它过于向上转型,强大的RAD工具让程序员只是做了简单的事情。当然,你也可以在代码中用这样的方式编写,当然在泛型编码中我们一直不是很提倡向下转型的方法,在实际编码中我们实在无法预计到这个过程中会发现什么问题。在delphi的窗口控件form有许多与窗体相关的功能像show,showmodal之类的方法,而这些方法非窗体之外的并没有,如果采取类型转换,势必会出现错了。
TObject对象深入下去还是有许多的内容,比如TObject对象提供了许多类方法,这些类方法都是供子类调用的。有获取类名,占用内存大小等,这些都是在使用编码中的高级用法,不过这些方法却是给真正的DELPHI程序员以帮助。