| 4 | 1/1 | 返回列表 |
| 查看: 1458 | 回復: 3 | ||||
[交流]
【轉(zhuǎn)帖】delphi語法進階 已有3人參與
|
|
一,模塊化編程 所有的Delphi應用程序都有相同的基本結(jié)構(gòu)。程序模塊 = 可選擇的說明部分 + 實現(xiàn)語句部分。 工程程序模塊=?庫單元模塊==>模塊說明部分interface ==>事件處理模塊implementation=?說明部分 ==>實現(xiàn)語句部分 所有的Delphi應用程序都有相同的基本結(jié)構(gòu)。當程序逐漸復雜時,在程序中加入模塊即可。例如在庫單元模塊中加入事件處理模塊,向工程中加入庫單元模塊等。模塊化編程使得程序結(jié)構(gòu)良好,并且對數(shù)據(jù)具有保護作用。delphi模塊化的編程有利于針對性的分工和利于維護等,不過用Delphi做模塊最簡捷的辦法就是用 bpl,至于自動發(fā)現(xiàn)和注冊機制就簡單了,統(tǒng)一調(diào)用接口,可以找找插件化的代碼。另外每個模塊編譯輸出是以CM為后綴名的,然后是通過主程序加載的CM后 綴名的模塊,如果在界面中有哪塊不要了,直接刪掉目錄下的CM后綴名的相應的模塊即可,那界面就不會顯 示出那個模塊了。 1,庫單元Unit的結(jié)構(gòu):單元是源程序代碼的載體,帶有.pas擴展名。庫單元也是程序模塊。 unit <庫單元名稱> interface //程序模塊的說明部分。庫單元的接口部分。將過程或函數(shù)的標題部分放interface部分則可被公有訪問,而其函數(shù)實體必須在implementation部分出現(xiàn),可以使用標題簡寫:procedure或function+過程或函數(shù)的名稱即可+程序的實現(xiàn)部分 uses <選擇性的庫單元列表> //uses列出想要包含進來的單元 {全局聲明} implementation //語句部分,事件處理模塊。可以且只能被此庫單元的事件處理過程使用 uses <選擇性的庫單元列表> {局部聲明} {過程和函數(shù)的執(zhí)行部分} initialization {選擇性的} //某程序的每個庫單元中的initialization部分都會被編譯器優(yōu)先執(zhí)行再運行其他代碼,且只運行一次 {選擇性的初始化程序} finalization {選擇性的} //包含了單元退出時的代碼。在程序退出時運行并且只運行一次。參見:Delphi中initialization和finalization {選擇性的退出時程序} end. 2,事件處理過程的結(jié)構(gòu) procedure TForm.Button1Click(Sender Tobject); var {程序模塊的說明部分} Name : string; begin {程序模塊的語句部分} Name := Edit1.Text; Edit2.Text := 'Welcome to Delphi'+Name; end; {程序模塊結(jié)束} 二,庫單元 1,庫單元的使用 VCL就是由多個程序庫單元組成,當創(chuàng)建窗體時,系統(tǒng)自動建立一個和窗體有關(guān)的庫單元;當往窗體中加入可視化控件時,系統(tǒng)自動在程序庫單元中加入了和控件有關(guān)的庫單元。Delphi還提供許多其他預定義的程序庫單元。要使用非可視化控件則把它先加入uses子句中。 * 庫單元A接口中USE單元B,單元B接口USE 單元C,則單元A可以直接訪問單元C。注意單元B接口不能再USE單元A,否則會循環(huán)單元引用編譯錯誤。 * 庫單元A實現(xiàn)部分中USE單元B,單元B實現(xiàn)部分中USE單元C,則單元A仍然不可以直接訪問單元C。而單元B實現(xiàn)部分中可以再USE單元A,這種循環(huán)單元引用不會有編譯錯誤。 2,建立與窗體無關(guān)的新庫單元:選用File|New Unit。這時一個新的庫單元加入了工程,新庫單元的代碼如下: unit Unit2; //系統(tǒng)按次序自動生成單元文件名稱,該文件會被編譯成具有.DCU后綴的文件,而鏈接到工程的可執(zhí)行文件上。 interface implementation end. 3,將已有的庫單元加入工程:(可用Open Project)先打開該工程|再選用File|Open File|選擇該單元文件(.PAS文件)|選OK。 三,包 包是若干個單元集中在一起以類似于DLL的形式存儲的BPL文件模塊(Borland Package Library)。BPL獨立編譯(可減小EXE),只是在EXE運行時候鏈入。 1,類型: ? 運行期包,EXE運行時才被調(diào)用。如VCL50.DPL包。 ? 設(shè)計期包,包包含了組件、屬性和組件編輯器等在設(shè)計程序時需要的元素,可以用Component|Install Package命令將一個設(shè)計期的包安裝到組件庫中, 如DCL*.BPL包 ? 既是運行期又是設(shè)計期的包,使用方便但因內(nèi)容繁雜而低效。 ? 既不是運行期又不是設(shè)計期的包,該包很少見,通常被其他包引用,而不是直接被應用程序引用。 2,包使用設(shè)置:在Project|Options的Packages對話框中選中Build with Runtime Packages復選框,以后當編譯和運行應用程序時,應用程序就會包文件分出來。 3,包的語法 DDPK包源文件常用包編輯器(啟動方式:File | New | Package)創(chuàng)建。DPK的語法格式如下: package PackageName; requires Package1,Package2….; //這個包需要調(diào)用的其他包 contains //這個包所包含的單元(單元所引用的單元也會間接地包含到包中,除非已列入requires子句中)。注意此處的單元不能被requires子句中的包所包含 Unit1 in 'Unit1.pas', Unit2 in 'Unit2.pas', …; end. 四,面向?qū)ο缶幊?br /> 1,OOP:從D5開始Delphi已經(jīng)完全脫離Pascal而獨立,Object Pascal在語法上與Pascal大致相同,但是編程思想已經(jīng)完全轉(zhuǎn)向了面向?qū)ο蟮某绦蛟O(shè)計(OOP)。有利于代碼重用和擴展維護。Delphi用戶不需了解OOP就可編程。當用戶在建立新窗體、添加新組件以及處理事件時,大部分相關(guān)代碼會由Delphi自動產(chǎn)生。但是了解OOP可以更好地理解Delphi尤其是組件編程。 以下是OOP的3個基本概念: (1)封裝性:隱藏封包內(nèi)部細節(jié)。 (2)繼承性:繼承以共享代碼。能用來建立VCL這樣的多層次的對象。Delphi不支持多繼承(但可通過包含類或接口來實現(xiàn)) (3)多態(tài)性:相同的表達式,不同的操作,能以靈活的擴展實現(xiàn)最終的代碼重用 2,對象的術(shù)語: * 類/對象:如記錄般有各種域的封裝了數(shù)據(jù)和方法的抽象結(jié)構(gòu),經(jīng)?梢员焕斫鉃榭梢暬M件,如按鈕、標簽、表等。Delphi提供了一系列組件,正是這些組 件構(gòu)成了Delphi面向?qū)ο蟪绦蛟O(shè)計的基礎(chǔ)。Delphi的對象通過全面支持繼承、封裝和多態(tài)性,提供了面向?qū)ο缶幊痰膹姶蠊δ堋? * 對象/類的實例instance:是由類定義的數(shù)據(jù)類型的變量。當程序運行時實例占用一些內(nèi)存。實例與對象/類的關(guān)系就像變量與類型的關(guān)系。 * 域(field):也被稱為域定義或?qū)嵗兞,域是包含在對象中的?shù)據(jù)變量。在對象中的一個域就像是在Pascal記錄中一個域,在C++中它被稱為數(shù)據(jù)成員。 * 方法( method ):屬于一個對象的過程和函數(shù)名,在C++中它被稱為成員函數(shù)。 * 屬性( property ):屬性是外部代碼訪問對象中的數(shù)據(jù)和代碼的訪問器,屬性隱藏了一個對象的具體實現(xiàn)的細節(jié)。 3, 面向?qū)ο蟮木幊汰h(huán)境:在某些工具中你能操縱對象但不能創(chuàng)建對象, 如VB中的ActiveX 控件(OCX )。能用但不能創(chuàng)建或派生它。這樣的環(huán)境被稱為基于對象的環(huán)境。Delphi是完全的面向?qū)ο蟮沫h(huán)境,這表示能用現(xiàn)存組件創(chuàng)建新的可視或不可視的對象,甚 至可以是設(shè)計時的窗體。 五,使用對象 1,讓我們結(jié)合Delphi的實例討論對象的概念: 當您要建立一個新工程時,Delphi 將顯示一個窗體作為設(shè)計的基礎(chǔ)。在程序編輯器中,Delphi將這個窗體說明為一個新的對象類型,并同時在與窗體相關(guān)聯(lián)的庫單元中生成了創(chuàng)建這個新窗體對象的程序代碼。 unit Unit1; interface uses SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) {窗體的類型說明開始} //使用保留字Class聲明了一個名叫TForm1的類類型,該類型是從類TForm繼承下來的一個對象。注意,類類型的標識符一般以“T”打頭,以區(qū)別于其他數(shù)據(jù)類型。另 外,在Delphi中,大量的構(gòu)造數(shù)據(jù)類型都是以“T”打頭的。如果不指明祖先類,Delphi默認該類繼承自TObject類。 Button1: TButton; //現(xiàn)在TForm1對象有了一個名為Button1的域:它是您在窗體中加入的按鈕。TButton是一個對象類型,Button1是Tbutton的一個實例。它被TForm1對象所包含,作為它的數(shù)據(jù)域。每當您在窗體中加入一個部件時,部件的名稱就會作為TFom1的域加入到類型說明中來。在Delphi中,您所編寫的事件處理過程都是窗體對象的方法。每當您建立一個事件處理過程,就會在窗體的對象類型中說明一個方法。 procedure Button1Click(Sender: TObject); // private // 對象私有域,其中的數(shù)據(jù)域和方法只能被本庫單元訪問 { Private declarations } public //對象公有域,其中的數(shù)據(jù)域和方法可以被其它庫單元訪問 { Public declarations } end; {窗體的類型說明結(jié)束} var Form1: TForm1; {說明一個窗體變量} //聲明TForm1類的一個實例Form1 implementation //對象過程或函數(shù)的程序代碼可以放在庫單元的implementation部分。 {$R *.DFM} end. * 當您使用Object Inspector來改變對象(部件)的名稱時,這個名稱的改變會反映到程序中。例如,在Object Inspector中將Form1的Name屬性命名為ColorBox,您會發(fā)現(xiàn)在類型說明部分,會將前文的TForm1改為:TColorBox=class(TForm); 并且在變量說明部分,會說明ColorBox為TColorBox類型的變量,由Delphi自動產(chǎn)生的事件處理過程名稱會自動改為TColorBox.Button1Click;但您自行編寫的實現(xiàn)部分的代碼卻不會被自動修改。因此,如果您在改變Name屬性前編寫了程序,則您必須將事件處理過程中的對象名稱進行改變。所以,原先的Form1.Color要改為ColorBox.Color。 2,對象變量的賦值 如果兩個變量類型相同或兼容,您可以把其中一個對象變量賦給另一個對象變量。例如,對象TForm1和TForm2都是從TForm繼承下來的類型,而且Form1和Form2已被說明過,那么您可以把Form1賦給Form2: 祖先 :=后代 Form2 :=Form1; type TDataForm = class(TForm) Button1:TButton; Edit1:TEdit; DataGrid1:TDataGrid; Database1:TDatabase; TableSet1:TTableSet; VisibleSession1:TVisibleSession; private{私有域說明} public {公有域說明} end; var AForm:TForm; DataForm:TDataForm; AForm :=DataForm; //祖先 :=后代 ,是合法的: procedure TForm1.Button1Click(Sender:TObject); //Sender是TObject類型即最頂?shù)淖嫦龋匀魏螌ο蠖伎梢再x值給它。此處雖然您沒有看見賦值的程序代碼,但事實上發(fā)生事件的部件或控制部件已經(jīng)賦給Sender了,這就是說Sender的值是響應發(fā)生事件的部件或控制部件的! begin end; procrdure TForm1.Memo1DragOver(Sender,Source:TObject;X,Y:integer; //Source參數(shù)也是TObject類型,被賦值為那個被拖曳的對象 State:TDragState;var Accept:Boolean); begin Accept :=Source is TLabel; //確保只有標簽可以被拖曳,Accept只有在用戶拖曳一個標簽時才為真,并作為變參輸出到函數(shù)之外。 end; procedure TForm1.Memo1DragDrop(Sender,Source:TObject;X,Y:Integer); //把Memo字型賦值成和放入的標簽一樣的字型 begin Memo1.Font := (Source as TLabel).Font; //只有當Source是一個標簽時,這個事件處理過程才允許這個賦值發(fā)生。 end; 3,對象的聲明,實例化,構(gòu)造,析構(gòu)/撤銷,自定義方法, 建立非可視化對象:在Delphi中使用的大部分對象都是您在設(shè)計和運行期間可以看見的部件,例如編輯框、按鈕等;一些部件,如通用對話框(Common dialog box)等,在設(shè)計時看不見,而在運行時可以看見;另外有些部件,例如計時器(Timer)、數(shù)據(jù)源(Data Source)部件等,在程序的運行期間沒有任何可視化的顯示,但您卻可以在您的應用程序中使用它們。 type TBoogieNights = class //等效于TBoogieNights = Class(TObject),因為所有的對象都是TObject對象的后代 Dance:Boolean; procedure DoTheHustle; //聲明方法 end; procedure TBoogieNights.DoTheHustle; //定義方法體時必須用完整的名字。注意對象的Dance域能被直接訪問,不提倡。 bigin Dance:=True; end; Var BoogieNights :TBoogieNights; BoogieNights := TBoogieNights.Create( ); //調(diào)用構(gòu)造器來實例化對象。編譯器將對對象的每一個域進行初始化,所有數(shù)字被賦值為0,所有指針為nil,所有字符串為空。等效于 BoogieNights := TBoogieNights.Create; BoogieNights.Free( ); //析構(gòu)/撤銷 Free( ) = If not Nil then Destroy( ) ,直接調(diào)用Destroy( )有危險。Free方法也是從TObject中繼承過來的。把注銷放在try…finally程序模塊的finally部分,而把對象的程序代碼放在try部分是編程的好習慣。這樣,即使您的程序代碼在使用對象時發(fā)生了異常事件,也會確保您為這個對象分配的內(nèi)存會被釋放。 * 構(gòu)造器主要用來為對象創(chuàng)建實例并為對象中的域分配內(nèi)存并進行初始化使得對象處在可以使用的狀態(tài)。Object Pascal的對象至少有一個構(gòu)造器稱為Create( ),但一個對象可以有多個構(gòu)造。根據(jù)不同的對象類型, Create( )可以有不同的參數(shù)或不帶參數(shù)。Create方法繼承自TObject類型 * 警告:凡是創(chuàng)建的,都需要釋放。在Object Pascal中(C++也是),一個靜態(tài)聲明的對象在離開它的作用域時自動調(diào)用它的析構(gòu)方法,但要對隱式動態(tài)生成的對象手動調(diào)用析構(gòu)方法。例外:第一條是 當對象被其他對象擁有時,第二種情況是引用計數(shù)的對象(像TInterfaceObject和TComObject),當最后一個引用釋放時,它將被析 構(gòu)。 *注意最好不要直接訪問對象的域,因為實現(xiàn)對象的細節(jié)可能改變。相反用訪問器屬性來訪問對象,它不受對象細節(jié)的影響 4,方法的類型 |
程序語言箱 |

|
TFoo = class procedure IAmAStatic; procedure IAmAVirtual; virtual; procedure IAmADynamic; dynamic; procedure IAmAMessage(var M:Tmessage); message wm_SomeMessage; end; * 1. 靜態(tài)方法:是方法的缺省類型,如同過程和函數(shù)那樣調(diào)用。編譯時到其地址把運行信息靜態(tài)地鏈入EXE文件。靜態(tài)方法執(zhí)行的速度最快,但不能被覆蓋來支持多態(tài)性。 * 2. 虛擬方法:如同過程和函數(shù)那樣調(diào)用。由于虛擬方法能被覆蓋所以編譯時建立虛擬方法表(VMT)以在運行時找地址。一個對象的VMT表包括自己和祖先的所有虛擬方法,所以比動態(tài)方法占更多內(nèi)存多,但它執(zhí)行得比較快。 * 3. 動態(tài)方法:和虛擬方法基本相似,只是它們的調(diào)度系統(tǒng)不同。編譯器為每一個動態(tài)方法的指定唯一數(shù)字和其地址構(gòu)造一個動態(tài)方法表(DMT )。DMT表中僅有自身聲明的動態(tài)方法,有可能需要祖先的DMT表來訪問它其余的動態(tài)方法。所以動態(tài)方法比虛擬方法用的內(nèi)存要少,但執(zhí)行起來有可能較慢。 * 4. 消息處理方法:在關(guān)鍵字message后面的值指明了這個方法要響應的消息。用消息處理方法來響應Windows的消息,這樣就不用直接來調(diào)用它。 5,方法的覆蓋 在Object Pascal覆蓋一個方法用來實現(xiàn)O O P的多態(tài)性概念。通過覆蓋使一方法在不同的派生類間表現(xiàn)出不同的行為。 TFooChild = class(TFoo) procedure IAmAVirtual; override; //編譯器就會用新的方法覆蓋替換VMT中原先的方法,原方法仍在 procedure IAmADynamic; override; //編譯器就會用新的方法覆蓋替換DMT中原先的方法,原方法仍在 procedure IAmAVirtual; virtual; //等效于重新聲明,新建方法,而非覆蓋 procedure IAmADynamic; dynamic; //等效于重新聲明,新建方法,而非覆蓋 procedure IAmAStatic; override; //對一個靜態(tài)方法進行覆蓋,新方法將完全覆蓋替換在祖先類中的同名方法,原方法不再存在了。 end; *如果Delphi顯示了一個標識符被重復定義的信息,就有可能是一個數(shù)據(jù)域和其祖先對象(例如TForm)的一個數(shù)據(jù)域有了相同的名稱?梢試L試改變這個標識符的名稱。 您可以覆蓋(Override)一個方法。通過在后代對象中覆蓋說明一個與祖先對象重名的方法,就可以覆蓋一個方法。如果想使這個方法在后代對象中作和祖先對象中一樣的工作但是使用不同的方式時,您就可以覆蓋這個方法。Delphi不推薦您經(jīng)常覆蓋方法,除非您想建立一個新的部件。覆蓋一個方法,Delphi編譯器不會給出錯誤或警告提示信息。 6,方法的重載 就像普通的過程和函數(shù),方法也支持重載,使得一個類中有許多同名的方法帶著不同的參數(shù)表,能重載的方法必須用o v e r l o a d指示符標識出來,可以不對第一個方法用o v e r l o a d。下面的代碼演示了一個類中有三個重載的方法: type TFoo = class procedure AMethod(I:Integer);overload; procedure AMethod(S:String);overload; procedure AMethod(D ouble);overload; end; 7,重新引入方法名稱 有 時候,需要在派生類中增加一個方法,而這個方法的名稱與祖先類中的某個方法名稱相同。在這種情況下,沒必要覆蓋這個方法,只要在派生類中重新聲明這個方 法。但在編譯時,編譯器就會發(fā)出一個警告,告訴你派生類的方法將隱藏祖先類的同名方法。要解決這個問題,可以在派生類中使用r e i n t r o d u c e指示符,下面的代碼演示了r e i n t r o d u c e指示符的正確用法: type TSomeBase = class procedure Cooper; end; TSomeClass = class procedure Cooper;reintroduce; end; *Self:在所有對象的方法中都有一個隱含變量稱為S e l f,S e l f是用來調(diào)用方法的指向類實例的指針。S e l f由編譯器作為一個隱含參數(shù)傳遞給方法。 8,屬性 可以把屬性看成是能對類中的數(shù)據(jù)進行修改和執(zhí)行代碼的特殊的輔助域。對于組件來說,屬性就是列在Object Inspector窗口的內(nèi)容。下面的例子定義了一個有屬性的簡單對象: T M y O b j e c t是包含下列內(nèi)容的對象:一個域(被稱為S o m e Va l u e的整型數(shù))、一個方法(被稱為S e t S o m e Va l u e的過程)和一個被稱為v a l u e的屬性。S e t S o m e Va l u e過程的功能是對S o m e Va l u e域賦值,Va l u e屬性實際上不包含任何數(shù)據(jù)。Va l u e是S o m e Va l u e域的輔助域,當想得到Va l u e中的值時,它就從S o m e Va l u e讀值,當試圖對Va l u e屬性設(shè)置值時,Va l u e就調(diào)用S e t S o m e Va l u e對S o m e Va l u e設(shè)置值。這樣做的好處有兩個方面:首先,通過一個簡單變量就使得外部代碼可以訪問對象的數(shù)據(jù),而不需要知道對象的實現(xiàn)細節(jié)。其次,在派生類中可以覆蓋諸 如S e t S o m e Va l u e的方法以實現(xiàn)多態(tài)性。 修改對象域的屬性或調(diào)用方法:對象的名稱.屬性名稱或調(diào)用方法 Edit1.Text := 'Welcome to Delphi'; //改變編輯框Text屬性 Edit1.ClearSelection; //清除編輯框部件中選中的文本 beginwith (Edit1) do //可以使用With語句進行簡化 begin ClearSelection; //等效于Edit1.ClearSelection; Text := 'Welcome to Delphi'; end; 9,可見性表示符 Object Pascal能通過在聲明域和方法時用p o r t e c t e d、p r i v a t e,p u b l i c,p u b l i s h e d和a u t o m a t e d指示符來對對象提供進一步的控制。使用這些關(guān)鍵字的語法如下: 在每一個指示符下能聲明任意多個方法或域。書寫時要注意縮進格式。下面是這些指示符的含義: ? p r i v a t e,對象中的這部分只能被相同單元的代碼訪問。用這個指示符對用戶隱藏了對象實現(xiàn)的細節(jié)并阻止用戶直接修改對象中的敏感部分。 ? p r o t e c t e d,對象中的這部分成員能被它的派生類訪問,這樣不僅能使對象向用戶隱藏實現(xiàn)的細節(jié)并為對象的派生類提供了最大的靈活性。 ? p u b l i c,這部分的域和方法能在程序的任何地方訪問,對象的構(gòu)造器和析構(gòu)方法通常應該是p u b l i c。 ? p u b l i s h e d,對象的這一部分將產(chǎn)生運行期類型信息( RT T I ),并使程序的其他部分能訪問這部分。Object Inspector用RT T I來產(chǎn)生屬性的列表。 ? a u t o m a t e d,這個指示符其實已經(jīng)不用了,保留這個指示符的目的是為了與Delphi 2.0的代碼兼容, 下面的代碼是以前介紹過的T M y O b j e c t對象,其中通過增加指示符提高了對象的完整性: 現(xiàn)在,對象的用戶不能直接修改S o m e Va l u e的值了,要修改對象的數(shù)據(jù)就必須通過Va l u e屬性來實 現(xiàn)。 10,友類 在C + +語言中有友類的概念(允許在其他類中訪問私有數(shù)據(jù)和私有函數(shù)的類)。在C + +中這是通過關(guān)鍵字f r i e n d來實現(xiàn)的,嚴格地說,在Object Pascal中沒有類似的關(guān)鍵字,但有類似的功能。凡是在相同單元聲明的對象都認為是友類,都可以訪問其他對象的私有成員。 11,對象的范圍 procedure TForm1.Button1Click(Sender:Tobject); begin Color :=clFuchsia; //為整個窗體Form1著色,等效于Form1.Color :=clFuchsia; 當前對象可以省略對象變量的名稱 Edit1.Color :=clLime;end; //當前對象的部件就要加上對象變量的名稱, //如果Edit1是在另一個窗體Form2之中,那么您需要把Unit2加入Unit1的uses子句中,然后將第二句改為:Form2.Edit1.Color := clLime; 12, 對象的秘密 在Object Pascal中的類實例實際上是指向堆中的類實例數(shù)據(jù)的3 2位指針。當訪問對象的域、方法和屬性時,編譯器會自動產(chǎn)生一些代碼來處理這個指針。因此對于新手來說,對象就好像是一個靜態(tài)變量。這意味著, Object Pascal無法像C++那樣在應用程序的數(shù)據(jù)段中為類分配內(nèi)存,而只能在堆中分配內(nèi)存。 13,TObject所有對象的祖先 所有的窗體對象都是TForm的后代。 TForm類型=?TForm1類型 (雖只含有域Button1和方法Button1Click,但繼承到TForm的全部屬性和方法) =?Form1 當您在窗體中加入了部件或編寫了事件處理過程時,F(xiàn)orm1才成為您自己的類型。 TObject類在Delphi的Visual Component Library的頂部,這就意味著所有的Delphi對象都是TObject的后代。TObject==>TComponent=?TControl 繼承祖先所有功能,并有自己特殊功能 因 為所有對象都是從TO b j e c t繼承來的,每一個類都從TO b e j c t繼承了一些方法,所以可以對對象的性能進行一些特殊的假定。每一個類都能告訴你它的名字、類型和它是否從某個類派生而來。作為一個程序員,不必關(guān)心編譯 器的實現(xiàn)細節(jié)而只要能利用對象所提供的功能就夠了。 TO b j e c t是一個特殊的對象,它在s y s t e m單元中定義,編譯器對TO b j e c t是完全清楚的,下面是TO b j e c t的定義: 在D e l p h i的聯(lián)機幫助中你將看到每一個方法的文檔。 在 這里特別要注意那些前面有c l a s s關(guān)鍵字的方法。在一個方法前加上關(guān)鍵字c l a s s,使得方法向其他通常的過程和函數(shù)一樣調(diào)用而不需要生成一個包含這個方法的類的實例,這個功能是從C + +的s t a t i c函數(shù)借鑒來的。要小心,不要讓一個類方法依賴于任何實例信息,否則編譯時將出錯。 六,接口 對于Object Pascal語言來說,最近一段時間最有意義的改進就是從Delphi 3開始支持接口(interface), 接口定義了能夠與一個對象進行交互操作的一組過程和函數(shù)。對一個接口進行定義包含兩個方面的內(nèi) 容,一方面是實現(xiàn)這個接口,另一方面是定義接口的客戶。一個類能實現(xiàn)多個接口,即提供多個讓客 戶用來控制對象的“表現(xiàn)方式”。 正如名字所表現(xiàn)的,一個接口就是對象和客戶通信的接口。這個概念像C++中的PURE VIRTUAL 類。實現(xiàn)接口的函數(shù)和過程是支持這個接口的類的工作。 在本章你將學到接口的語言元素,要想在應用程序中使用接口,請參考第2 3章“COM和ActiveX; 1. 定義接口 就像所有的Delphi類都派生于TObject一樣,所有的接口都派生于一個被稱為是IUnknown的接口,IUnknown在system單元中定義如下: 正如你所看到的,接口的定義就像是類的定義,最根本的不同是在接口中有一個全局唯一標識符(GUID),它對于每一個接口來說是不同的。對IUnknown的定義來自于Microsoft的組件對象模型(COM)規(guī)范。在第2 3章有詳細的介紹。 如果你知道怎樣創(chuàng)建Delphi的類,那么定義一個定制的接口是一件簡單的事情,下面的代碼定義了一個新的接口稱為IFoo,它包含一個被稱為F1( )的方法: 提示在Delphi的IDE中,按Ctrl+Shift+G鍵可以為一個接口生成一個新的GUID。 下面的代碼聲明了一個稱為IBar的接口,它是從I F o o接口繼承來的: 2. 實現(xiàn)接口 下面的代碼演示了在一個類TFooBar中怎樣實現(xiàn)IFoo和IBar接口: 注意,一個類可以實現(xiàn)多個接口,只要在聲明這個類時依次列出要實現(xiàn)的接口。編譯器通過名稱來把接口中的方法與實現(xiàn)接口的類中的方法對應起來,如果一個類只是聲明要實現(xiàn)某個接口,但并沒有具體實現(xiàn)這個接口的方法,編譯將出錯。 如果一個類要實現(xiàn)多個接口,而這些接口中包含同名的方法,必須把同名的方法另取一個別名,請看下面的程序示例: 3. implements指示符 implements指示符是在Delphi 4中引進的,它的作用是委托另一個類或接口來實現(xiàn)接口的某個方法,這個技術(shù)有時又被稱為委托實現(xiàn),關(guān)于implements指示符的用法,請看下面的代碼: 在上面例子中的implements指示符是要求編譯器在Foo屬性中尋找實現(xiàn)IFoo接口方法。屬性的類型必須是一個類,它包含IFoo方法或類型是IFoo的接口或IFoo派生接口。implements指示符后面可以列出幾個接口,彼此用逗號隔開。 implements 指示符在開發(fā)中提供了兩個好處:首先,它允許以無沖突的方式進行接口聚合。聚合(Aggregation)是COM中的概念。它的作用是把多個類合在一起 共同完成一個任務,詳見第2 3章。其次,它能夠延后占用實現(xiàn)接口所需的資源,直到確實需要資源。例如,假設(shè)實現(xiàn)一個接口需要分配一個1MB的位圖,但這個接口很少用到。因此,可能平 時你不想實現(xiàn)這個接口,因為它太耗費資源了,用implements指示符后,可以只在屬性被訪問時才創(chuàng)建一個類來實現(xiàn)接口。 4. 使用接口 當 在應用程序中使用接口類型的變量時,要用到一些重要的語法規(guī)則。最需要記住的是,一個接口是生存期自管理類型的,這意味著,它通常被初始化為n i l,它是引用計數(shù)的,當獲得一個接口時自動增加一個引用計數(shù);當它離開作用域或賦值為n i l時它被自動釋放。下面的代碼演示了一個接口變量的生存期自管理機制。 關(guān)于接口變量的另一個規(guī)則是,一個接口變量與實現(xiàn)這個接口的類是賦值相容的,例如,下面的代碼是合法的: 最后,類型強制轉(zhuǎn)換運算符a s可以把一個接口類型的變量強制類型轉(zhuǎn)換為另一種接口(在第2 3章詳細介紹)。示例如下: 七,運行期類型信息 運行期類型信息(RTTI)是一種語言特征,能使應用程序在運行時得到關(guān)于對象的信息。RTTI是Delphi的組件能夠融合到IDE中的關(guān)鍵。它在IDE中不僅僅是一個純學術(shù)的過程。 由于對象都是從TObject繼承下來的,因此,對象都包含一個指向它們的RTTI的指針以及幾個內(nèi)建的方法。下面的表列出了TObject的一些方法,用這些方法能獲得某個對象實例的信息。 函數(shù) 返回類型 返回值 ClassName() string 對象的類名 ClassType() TClass 對象的類型 InheritsFrom() Boolean 判斷對象是否繼承于一個指定的類 ClassParent() TClass 對象的祖先類型 InstanceSize() word 對象實例的長度(字節(jié)數(shù)) ClassInfo() Pointer 指向RTTI的指針 Object Pascal提供了兩個運算符as和is,用它們通過RTTI能對對象進行比較和強制類型轉(zhuǎn)換。 關(guān)鍵字as是類型轉(zhuǎn)換的一種新的形式。它能把一個基層的對象強制類型轉(zhuǎn)換成它的派生類,如果轉(zhuǎn)換不合法就產(chǎn)生一個異常。假定有一個過程,想讓它能夠傳遞任何類型的對象,它應該這樣定義: Procedure Foo(AnObject:TObject); 在這個過程如果要對AnObject進行操作,要把它轉(zhuǎn)換為一個派生對象。假定把AnObject看成是一個TEdit派生類型,并想要改變它所包含的文本(TEdit是一個Delphi VCL編輯控件),用下列代碼: (FOO as TEdit).Text:= 'Hello World.'; 能用比較運算符來判斷兩個對象是否是相兼容的類型,用is運算符把一個未知的對象和一個已知類型或?qū)嵗M行比較,確定這個未知對象的屬性和行為。例如,在對AnObject進行強制類型轉(zhuǎn)換前,確定AnObject和TEdit是否指針兼容: If (Foo is TEdit) then TEdit(Foo).Text:= 'Hello World.'; 注意在這個例子中不能用as進行強制類型轉(zhuǎn)換,這是因為它要大量使用RTTI,另外還因為,在第一行已經(jīng)判斷Foo就是TEdit,可以通過在第2行進行指針轉(zhuǎn)換來優(yōu)化。 |


| 4 | 1/1 | 返回列表 |
| 最具人氣熱帖推薦 [查看全部] | 作者 | 回/看 | 最后發(fā)表 | |
|---|---|---|---|---|
|
[考研] 環(huán)境工程297分求調(diào)劑一志愿杭高院 +10 | GENJIOW 2026-03-31 | 10/500 |
|
|---|---|---|---|---|
|
[考研] 一志愿武理材料工程302調(diào)劑環(huán)化或化工 +11 | Doleres 2026-03-31 | 12/600 |
|
|
[考研] 070300化學專業(yè)279調(diào)劑 +10 | 哈哈哈^_^ 2026-03-31 | 10/500 |
|
|
[論文投稿]
chinese chemical letters英文版投稿求助
130+4
|
Yishengeryi 2026-03-30 | 4/200 |
|
|
[考研] 材料工程085601數(shù)二英一335求調(diào)劑 +5 | 雙馬尾痞老板2 2026-03-31 | 5/250 |
|
|
[考研] 086000調(diào)劑 +5 | 7901117076 2026-03-26 | 5/250 |
|
|
[考研] 080500-315分復試調(diào)劑 +9 | 上岸3821 2026-03-31 | 9/450 |
|
|
[考研] 考研調(diào)劑求助 +7 | 13287130938 2026-03-31 | 7/350 |
|
|
[考研]
|
小羊36 2026-03-30 | 4/200 |
|
|
[考研] 學碩274求調(diào)劑 +17 | Li李魚 2026-03-26 | 17/850 |
|
|
[考研] 287求調(diào)劑 +17 | land xuxu 2026-03-26 | 17/850 |
|
|
[考研] 282求調(diào)劑 +3 | 呼吸都是減肥 2026-03-31 | 3/150 |
|
|
[考研] 285求調(diào)劑 +6 | AZMK 2026-03-29 | 9/450 |
|
|
[考研] 327求調(diào)劑 +6 | 汲亦昊 2026-03-29 | 6/300 |
|
|
[考研] 求調(diào)劑 +6 | 蘆lty 2026-03-25 | 7/350 |
|
|
[考研] 070300化學求調(diào)劑 +4 | 起個名咋這么難 2026-03-27 | 4/200 |
|
|
[考研] 085600,材料與化工321分調(diào)劑 +4 | 大饞小子 2026-03-27 | 6/300 |
|
|
[考研] 材料求調(diào)劑 +5 | .m.. 2026-03-25 | 5/250 |
|
|
[考研] 081200-11408-276學碩求調(diào)劑 +3 | 崔wj 2026-03-26 | 3/150 |
|
|
[考研] 【2026考研調(diào)劑】制藥工程 284分 求相關(guān)專業(yè)調(diào)劑名額 +4 | 袁奐奐 2026-03-25 | 8/400 |
|