牢騷
我是在高一接觸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呢人總要有點信仰喜好不是嗎?所以我認為與其花時間咒罵一個工具的不足之處不如花時間研究如何解決這個問題
From:http://tw.wingwit.com/Article/program/Delphi/201311/24962.html