从Turbo Pascal到Delphi

●  牢骚

我是在高一接触pascal语言,因为参加NOI的需要,顺理成章的要使用Turbo Pascal来写程序了。半年后,我开始想着如何编写Windows程序,又理所当然的找上Delphi。初见Delphi,除了begin,end让我觉得倍感亲切外,Object Pascal里的增加的面向对象的语法却让我很是吃惊,当时的我可根本不懂什么叫面向过程,面向对象;最可恶的是,国内那些教育家们,除了会拿着清华的那本精简的不能再精简的pascal教材照本宣科外,似乎再也没有什么实质性的工作了,传说中的《Turbo Pascal大全》更是无处可寻,所以关于unit,interface这些Delphi里随处可见的关键字我也很不明白。所幸,其后不久,我得到一本名为《计算机反病毒技术》的书,里面统统都是用Turbo Pascal编写的源代码,通过它我迅速明白了早已存在于Turbo Pascal中unit,interface等关键字的含义和用法,又以Delphi中的Help文档为扶手,开始蹒跚学步了。

 

印象中,国内Delphi作家似乎更偏爱编写应用实例类的技术书籍,至于语法这种东西,没有几个人愿意多去涉及,即使书中必须谈及,也是寥寥数笔,匆匆带过,或者干脆与某本书类似。对Object Pascal语法讲解最好,最权威的恐怕就算《Delphi5开发人员指南》了,这本书至今也是备受推崇的。但与如今泛滥的C++书籍相比,Delphi仍然逊色许多,也难怪很多新手特别是从来没有接触过pascal语言的新手,在学习Object Pascal时会遇到不少困难。自己的感觉是:在从Turbo Pascal向Delphi过渡的过程中,由于没有正确的指引,走了很多弯路;由于没有正确的桥梁,必须要一步实现大跨越。所以,在这里,我提出自己曾经遇见的沟壑,路标性给出我自己的认识和总结,希望给入门的同学们一些帮助。我不打算详细介绍语法知识,并假设你已经有一点pascal语言和面向对象概念的基础。要想学习相关详细知识,我推荐各位一定要阅读《Delphi开发人员指南》和Delphi Help文档中的相关章节。

 

 

●     Record,Class,Object

习惯了在一个Program模块内写完所有面向过程代码的我,有几天的时间一直未能彻底明白在非Unit模块中,自定义类的框架,语法是如何的,VCL源代码虽然经典,却过于繁杂,不能让我迅速掌握根本,我需要一个最简单又最能说明问题,完整的可运行的代码,苦于无处寻求答案,只好亲自动手,探索对应关系,终成其下两段代码。

 

program TP;

{本代码在Turbo Pascal 7.0下编译通过}

 

type

  MyRecord = record

     {...}

  end;

 

var

  MR: MyRecord;

  procedure MyProcedure;

  begin

    {MyProcedure Code}

  end;

{=========== main ===========}

begin

{以这个begin为标志,主程序开始,其作用相当于C/C++中的main函数}

  MyProcedure;

end.

 

上面是一段极其简单的包含记录类型声明和过程声明的代码,二者基本规则如下:用户自定义的数据类型,需要放在以保留字“type”开头的代码段中;过程(procedure)和函数(function)要放在以保留字“var”开头的代码段中;最后一个夹在begin和end间的代码段是主程序的开始,也就是整个程序的入口,作用相当于C/C++里的main函数,请注意,只有在以program保留字开头的代码模块中,这个begin和end才具有程序入口的作用。

 

再看下面的代码:

 

program Delphi;

{代码在Delphi7.0下编译通过}

 

{$APPTYPE CONSOLE}

 

uses

  SysUtils;

 

type

TMyClass = class(TObject)

  public

    constructor Create;

    procedure PrintClassName;

  private

    ClassName: string;

  end;

 

var

  MyClass: TMyClass;

 

  constructor TMyClass.Create;

  begin

    ClassName := 'TMyClass';

  end;

 

  procedure TMyClass.PrintClassName;

  begin

    writeln(ClassName);

  end;

 

{=========== main ===========}

begin

  MyClass := TMyClass.Create;

  MyClass.PrintClassName;

  MyClass.Free;

  readln;

end.

 

类作为用户自定义的一种数据类型,其声明的规则,成员函数、过程的实现方法都符合经典 Pascal的基本规则,唯一不同的是保留字变了,从记录体变成了类(详细比较代码结构和语法规则),这也说明Object Pascal是在经典Pascal的基础上进行了面向对象内容的语法扩充。当然,内部的运行机制并没有表面语法扩充这么轻松,可那是编译器的事情,在这里,我们完全不用理会。差点忘记告诉读者怎么调试上面的代码了:在IDE环境主菜单里选择 File | New | Other ,在New Item项里选择Console Application,这时出现了代码编辑框,再将上面的代码贴入,F9,完成!

 

代码内的{$APPTYPE CONSOLE}是一个编译开关,它告诉编译器,这是控制台程序,在格式上它与注释的差别就是那个“$”符号;TMyClass = class(TObject)可以简写为

TMyClass = class,表示TMyClass类从TObject类继承而来,TObject是Delpi中所有类的祖先,这也是为什么我在代码中没有声明Destroy过程却仍然能够使用的原因;Delphi中类的构造很有趣,请注意MyClass := TMyClass.Create这一句,这与C++不同[注1]。readln使程序停顿下来,直到用户按下回车键才结束程序退出。更多详细内容请参考《Delphi开发人员指南》2.17.1节。

 

   上面两段代码相互对应,虽然很简单,不过我却认为他们在某种程度上很容易让同学发现由经典Pascal向Object Pascal过渡的一些方法,对Object Pascal的类定义语法有个初步了解,这是很重要的一步。当初我要是能够看到这两段代码,或许能少浪费很多时间了。

 

另外,在TP5.5 –Delphi 7.0中都支持Object类型(对象类型)。语法如下:

 

object
Field;
Field;
...
Method;
Method;
end;

 

Method允许以下几种形式:

procedure MethodName(<parameter(s)>:type);
或者function MethodName(<parameter(s)>:type):type;
或者constructor MethodName(<parameter(s)>: type [;<parameter(s)>:type]); [virtual];
或者destructor MethodName[(<parameters>: type)];[virtual];

 

不错的,构造函数和析构函数都支持virtual,在构造函数中,还有一个有用的东西是Fail函数,当构造函数的初始化失败时,它可以用来释放已经分配的资源。

 

接下来的代码,是Turbo Pascal的Help文档中,关于Fail函数的演示代码,可以让大家对此有个较深的认识。Turbo Pascal确实是很强大和优秀的。

 

type

 PBase = ^TBase;

 TBase = object(TObject)  {在这里就已经出现Tobject了,是不是很亲切?}

   constructor Init(FailMe: Boolean);

 end;

 

 PDerived = ^TDerived;

 TDerived = object(TBase)

   constructor Init(FailMe: Boolean);

 end;

 

constructor TBase.Init(FailMe: Boolean);

begin

 inherited Init;

 if FailMe then Fail;

end;

 

constructor TDerived.Init(FailMe: Boolean);

begin

 if not inherited Init(FailMe) then

{判断父类的初始化是否成功}

   { Ancestor failed to construct, we must fail too }

   Fail;

 { Otherwise, proceed with construction }

 {...}

end;

 

var

 P: PObject;

 X: Boolean;

begin

 for X := False to True do

 begin

   P := New(PDerived, Init(X));

   if P <> nil then

   begin

     writeln('Object constructed sucessfully');

     Dispose(P, Done);

   end

   else

     writeln('Object failed to construct');

 end;

end.

 

自定义的Object不一定要从Tobject继承下来,因此它也没有内建的构造、析构和其他方法,通常使用New过程和Dispose过程建立和销毁它的实例。Delphi中仍旧支持Object,并有property成员了,但是仍然不允许published。KOL[注2]也使用该类型实现自己的构架。但是对此关键字的保留主要是为了兼容,建议用户改用class关键字。

 

●  unit模块

在Turbo Pascal的Help文档里,是这样说明unit功能的:Units are the basis of modular programming inBorland Pascal. You use units to createlibraries and to divide large programs into logically related modules。小规模的程序,我们可能将所有代码集中在一个program中,可是面对更加复杂的大型工程时,正确的划分功能封装功能对代码管理和以后的维护有着重要的作用,而使用unit模块正好解决了这些问题。其语法规则如下:

 

unit identifier;  { Heading }

 

 interface  { Public symbols }:

  uses      { Uses clause }

  const     { Constants }

  type      { Types }

  var       { Variables }

  procedure { Procedures }

  function  { Functions }

 

 

 implementation   { Private symbols }:

  uses            { Uses clause }

  label           { Labels }

  const           { Constants }

  type            { Types }

  var             { Variables }

  procedure       { Procedures}

  function        { Functions }

 begin           { Initialization }

  statement;      { Statements }

    statement

 end.

 

Interface部分用来声明对外接口,也就是可以被外部引用该文件的程序使用的函数和过程;implementation部分包含接口部分声明的各种函数、过程具体实现的代码;begin一直到最后的end.之间都是初始化部分,可以为本unit内的各种变量,过程,函数初始化。如果没有内容需要初始化,那么begin可以省略,但end.必须存在。

 

在Delphi下经典Pascal中的unit部分有了变动,请看来源于Delphi Help文档的说明:

unit Unit1;

 

interface

 

uses 

{ List of units goes here }

 

  { Interface section goes here }

 

implementation

 

uses 

{ List of units goes here }

 

  { Implementation section goes here }

 

initialization

  { Initialization section goes here }

 

finalization

  { Finalization section goes here }

 

end.

 

可见Initialization部分的开始关键字begin,被Initialization取代了,并且增加了一个finalization部分。Initialization部分的代码可以这样写:

 

initialization

begin

  {do something…}

end;

 

也可以这样写:

 

initialization

  {do something…}

 

finalization部分的功能,有点类似于析构函数,它主要针对本unit模块中initialization部分初始化的资源进行释放,并且是在程序结束时运行,如果程序以Halt过程结束了,该部分的程序将不能执行。

 

Unit模块中的interface等关键字和结构初看似乎有些限制程序员的自由度,但也正是这种语法规定体现出Pascal语言的严谨和优美,为减少程序出错的几率做出保证。

 

program相当文章的提纲挈领,unit则是文章的各个段落。Delphi里,program模块包含在.prj文件中,unit模块包含在传统的.pas文件中。这就是为什么在Delphi中我们经常面对的是为各个窗口服务的unit模块,而非在一个program中写完所有代码。不过我在Delphi的Help中看到这样一句话:In traditional Pascal programming, all source code, including the main program, is stored in .pas files.不知道这算思考角度不同还是算bug,毕竟这种语法并非Delphi中才有,Turbo Pascal程序员也一直在采用这种方法组织程序结构。

 

给出一个简单的initialization例子。在菜单中选择File | New | Application,再在窗体上放置一个按钮,双击该按钮编写它的Click事件处理代码,完整代码如下:

 

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls;

 

type

  TForm1 = class(TForm)

    Button1: TButton;

    procedure Button1Click(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

  Msg: string;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  ShowMessage(Msg);

  Msg := 'second';

end;

 

initialization

  Msg := 'first';

 

end.

 

   以上所述,是过渡中两个基本的重要问题,弄懂它们方可初步明白自己为什么要这样编写代码,该在哪里编写代码,如何扩展代码功能。

 

●  我推荐的参考书籍

    

     Delphi参考书籍

《Delphi 5 开发人员指南》机械工业出版社

《Inside VCL》李维 电子工业出版社

《Delphi深度历险》陈宽达 科学出版社

《Pascal精要》网络下载电子版

 

Windows参考书籍

《Programming Windows》Charles Petzold

《Windows2000开发人员指南》中国水利水电出版社

 

Delphi组件参考书我暂时没有发现特别好的,平时我主要依靠论坛,源代码,Delphi自带的Demo和文档来学习组件的使用。

 

●     再说点

现在有一些大学取消了Pascal语言课程,去年的ACM大赛也取消了Pascal语言的使用,不禁心寒,启蒙教育没有人做了,这些都使得Delphi在学生中的处境更加艰难。在国内的Delphi论坛上,常常见到许多半吊子程序员在享受Delphi的快速开发的时候,嘴巴里还在责备Delphi功能太弱,不能搞什么底层开发,甚至直接责怪Pascal语言,殊不知,在Dos年代,有多少著名软件使用Pascal开发出来的呢,有多少底层控制程序有着Pascal的身影呢?现在我手头上还有Pascal编写的病毒代码,反病毒代码,IC芯片控制代码。

 

或许正是Delphi的RAD能力降低了程序开发的门槛,让很多半吊子进入了程序界,RAD开发蒙蔽了许多半吊子编程者(称呼他们为程序员或许稍欠火候)的眼睛,但是国内的教育界同样有着不可推卸的责任,选修课开VB的不少,讲Delphi的很少,我曾经还遇到过一个从心底里就瞧不起Delphi,不啻谈论的老师,而事实上他根本就没有用过Delphi。我现在常去外国网站,发现国内被争论不休的问题,在国外早就有人在做,并且做的非常棒。

 

似乎我在为Delphi翻案,不停的维护它,没辙,谁要我是它的fans呢,人总要有点信仰,喜好不是吗?所以我认为,与其花时间咒骂一个工具的“不足之处”,不如花时间研究如何解决这个问题。
posted @ 2004-06-13 14:58  monkeyking  阅读(1046)  评论(1编辑  收藏  举报