牢骚
我是在高一接触pascal语言因为参加NOI的需要顺理成章的要使用Turbo Pascal来写程序了半年后我开始想着如何编写Windows程序又理所当然的找上Delphi初见Delphi除了beginend让我觉得倍感亲切外Object Pascal里的增加的面向对象的语法却让我很是吃惊当时的我可根本不懂什么叫面向过程面向对象最可恶的是国内那些教育家们除了会拿着清华的那本精简的不能再精简的pascal教材照本宣科外似乎再也没有什么实质性的工作了传说中的《Turbo Pascal大全》更是无处可寻所以关于unitinterface这些Delphi里随处可见的关键字我也很不明白所幸其后不久我得到一本名为《计算机反病毒技术》的书里面统统都是用Turbo Pascal编写的源代码通过它我迅速明白了早已存在于Turbo Pascal中unitinterface等关键字的含义和用法又以Delphi中的Help文档为扶手开始蹒跚学步了
印象中国内Delphi作家似乎更偏爱编写应用实例类的技术书籍至于语法这种东西没有几个人愿意多去涉及即使书中必须谈及也是寥寥数笔匆匆带过或者干脆与某本书类似对Object Pascal语法讲解最好最权威的恐怕就算《Delphi开发人员指南》了这本书至今也是备受推崇的但与如今泛滥的C++书籍相比Delphi仍然逊色许多也难怪很多新手特别是从来没有接触过pascal语言的新手在学习Object Pascal时会遇到不少困难自己的感觉是在从Turbo Pascal向Delphi过渡的过程中由于没有正确的指引走了很多弯路由于没有正确的桥梁必须要一步实现大跨越所以在这里我提出自己曾经遇见的沟壑路标性给出我自己的认识和总结希望给入门的同学们一些帮助我不打算详细介绍语法知识并假设你已经有一点pascal语言和面向对象概念的基础要想学习相关详细知识我推荐各位一定要阅读《Delphi开发人员指南》和Delphi Help文档中的相关章节
记录体和类
习惯了在一个Program模块内写完所有面向过程代码的我有几天的时间一直未能彻底明白在非Unit模块中非继承的自定义类的框架语法是如何的VCL源代码虽然经典却过于繁杂不能让我迅速掌握根本我需要一个最简单又最能说明问题完整的可运行的代码苦于无处寻求答案只好亲自动手探索对应关系终成其下两段代码
program TP;
{本代码在Turbo Pascal 下编译通过}
type
MyRecord = record{}
end;
var
MR: MyRecord;
procedure Procedure;
begin
{Procedure Code}
end;
{=========== main ===========}
begin
{以这个begin为标志主程序开始其作用相当于C/C++中的main函数}
Procedure;
end
上面是一段及其简单的包含记录类型声明和过程声明的代码二者基本规则如下用户自定义的数据类型需要放在以保留字type开头的代码段中过程(procedure)和函数(function)要放在以保留字var开头的代码段中最后一个夹在begin和end间的代码段是主程序的开始也就是整个程序的入口作用相当于C/C++里的main函数请注意只有在以program保留字开头的代码模块中这个begin和end才具有程序入口的作用
另外在Turbo Pascal中已经支持原始的面向对象它的声明关键字是Object与现在我们常见的Class不同语法如下
object
Field;
Field;
Method;
Method;
end;
Method允许以下几种形式
procedure MethodName(:type);
或者function MethodName(:type):type;
或者constructor MethodName(: type [;:type]); [virtual];
或者destructor MethodName[(: type)];[virtual];
不错的构造函数和析构函数都支持virtual在构造函数中还有一个有用的东西是Fail函数当构造函数的初始化失败时它可以用来释放已经分配的资源遗憾的是Object里面还没有区分私有共有接下来的代码是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 TBaseInit(FailMe: Boolean);
begin
inherited Init;
if FailMe then Fail;
end;
constructor TDerivedInit(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
回到Delphi中再看下面的代码
program Delphi;
{代码在Delphi下编译通过}
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TMyClass = class(TObject)
public
constructor Create;
procedure PrintClassName;
private
ClassName: string;
end;
var
MyClass: TMyClass;
constructor TMyClassCreate;
begin
ClassName := TMyClass;
end;
procedure TMyClassPrintClassName;
begin
writeln(ClassName);
end;
{=========== main ===========}
begin
MyClass := TMyClassCreate;
MyClassPrintClassName;
MyClassFree;
readln;
end
类作为用户自定义的一种数据类型其声明的规则成员函数过程的实现方法都符合经典 Pascal的基本规则唯一不同的是保留字变了从记录体变成了类(详细比较代码结构和语法规则)这也说明Object Pascal是在经典Pascal的基础上进行了面向对象内容的语法扩充当然内部的运行机制并没有表面语法扩充这么轻松可那是编译器的事情在这里我们完全不用理会差点忘记告诉读者怎么调试上面的代码了在IDE环境主菜单里选择 File | New | Other 在New Item项里选择Console Application这时出现了代码编辑框再将上面的代码贴入F完成!
代码内的{$APPTYPE CONSOLE}是一个编译开关它告诉编译器这是控制台程序在格式上它与注释的差别就是那个$符号TMyClass = class(TObject)可以简写为
TMyClass = class表示TMyClass类从TObject类继承而来TObject是Delpi中所有对象的祖先这也是为什么我在代码中没有声明Destroy过程却仍然能够使用的原因Delphi中类的构造很有趣请注意MyClass := TMyClassCreate这一句这与C++不同readln使程序停顿下来直到用户按下回车键才结束程序退出更多详细内容请参考《Delphi开发人员指南》节
上面两段代码相互对应虽然很简单不过我却认为他们在某种程度上很容易让同学发现由经典Pascal向Object Pascal过渡的一些方法对Object Pascal的类定义语法有个初步了解这是很重要的一步当初我要是能够看到这两段代码或许能少浪费很多时间了
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 Unit;
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中写完所有代码不过我在Delpi的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 Unit;
interface
uses
Windows Messages SysUtils Variants Classes Graphics Controls Forms
Dialogs StdCtrls;
type
TForm = class(TForm)
Button: TButton;
procedure ButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form: TForm;
Msg: string;
implementation
{$R *dfm}
procedure TFormButtonClick(Sender: TObject);
begin
ShowMessage(Msg);
Msg := second;
end;
initialization
Msg := first;
end
以上所述是过渡中两个基本的重要问题弄懂它们方可初步明白自己为什么要这样编写代码该在哪里编写代码如何扩展代码功能
推荐的参考书籍
Delphi参考书籍
《Delphi 开发人员指南》机械工业出版社
《Inside VCL》李维 电子工业出版社
《Delphi深度历险》陈宽达 科学出版社
《Pascal精要》网络下载电子版
Windows参考书籍
《Programming Windows》Charles Petzold
《Windows开发人员指南》中国水利水电出版社
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呢人总要有点信仰喜好不是吗?所以我认为与其花时间咒骂一个工具的不足之处不如花时间研究如何解决这个问题