1. 程式人生 > >delphi project of object

delphi project of object

ted gin log ash signed 函數的調用 end procedure string

http://www.cnblogs.com/ywangzi/archive/2012/08/28/2659811.html

其實要了解這些東西,適當的學些反匯編,WINDOWS內存管理機制,PE結構,看下李維的VCL架構剖析可以很好理解
type
TMyEvent = procedure of object;
這是一種數據類型的定義,他定義了一個可以在類中使用的函數類型
區別於
type
TMyProc = procedure;

TMyEvent 和 TMyProc 都定義了一個函數類型,他們的差別是,TMyProc 不可以用在類中定義事件,TMyEvent 卻可以。

如果你想知道問什麽,那就需要深入了解事件類型以及函數類型到底是個什麽?

procedure a();
begin
ShowMessage()
end;

var
Func1: TMyProc;
Func2: TMyEvent;

func1 := A;

func1 := A;

這句到底發生了什麽事情呢?

在32位的windows操作系統中,任何一個進程被執行,操作系統要完成的工作基本上包括:為這個進程開辟一個線性的虛擬地址表(從$00000000到$FFFFFFFF),然後把exe程序加載到這個地址表對應的內存中,然後跳入到exe程序的入口點,剩下的事情,就是exe自己從入口點開始一步一步幹自己的事情了。
程序中,所有的函數都被編譯到固定的位置,也就是每個函數都有一個地址與之對應,對函數的調用,實際上就是在寄存器或者堆棧中準備好參數,然後跳入到函數對應的地址繼續執行。

func1 := A;
這個動作,完成的就是把函數A的地址賦值給func1這個變量。


那麽,為Func2: TMyEvent 賦值又是完成了什麽呢?

類中的函數也是有地址的,編譯後,類中的函數也會被編譯到一個固定的地址上。
但是,func2不是表示一個函數地址,他是一個記錄類型的變量
這個可以通過 SizeOf(TMyEvent) 看到 SizeOf(TMyEvent) 返回值是8,而SizeOf(TMyProc)返回的是4
實際上,TMyEvent類型是包含兩個域的一個記錄,其中一個域是Code,也就是和TMyProc一樣的,另一個域是Data,他保存著一個對象。

Button2.OnClick := Button1Click;

這樣的賦值,實際上是將窗體類的對象form1給data域,將Button1Click這個函數的地址給Code域







1.
TMyEvent = procedure of object; TMyEvent 是方法類型 就等於 String 是一種數據類型

如在一個Txxx類中定義了一個過程
procedure Txxx.test;
begin
showmessage(‘1‘);
end;

那麽就可以把 Txxx.test 賦給 TMyEvent 了 (TMyEvent := Txxx.test);
因為 TMyEvent 的定義中有 of object 所以賦值給它的只能是類中的過程,而不能是普通過程。

2.
FOnHundred: TMyEvent; --> FOnHundred 是一個變量 它的類型是 TMyEvent,
就等於 icount : integer 這麽簡單

3.
property OnHundred: TMyEvent read FOnHundred write FOnHundred

OnHundred 是一個屬性 它的類型也是 TMyEvent 通過 FOnHundred 變量來存取 這個屬性的值。

當屬性不用過程去存取的時候 (如上例)調用 OnHundred 和 FOnHundred 是相同的

delphi中經常見到以下兩種定義

Type

TMouseProc = procedure (X,Y:integer);

TMouseEvent = procedure (X,Y:integer) of Object;

兩者樣子差不多但實際意義卻不一樣,

TMouseProc只是單一的函數指針類型;

TMouseEvent是對象的函數指針,也就是對象/類的函數/方法

區別在於類方法存在一個隱藏參數self,也就是說兩者形參不一樣,所以不能相互轉換。

這也就是為什麽delphi中可以這樣賦值 button1.onClick:=button2.onClick;

卻不能這樣賦值 button1.onclick=buttonclick; (buttonclick為本地函數,button2.onclick為類方法)的原因!


方法類型定義:TMethod = procedure of object;

Procedural types allow you to treat procedures and functions as values that can be assigned to variables or passed to other procedures and functions. For example, suppose you define a function called Calc that takes two integer parameters and returns an integer:

function Calc(X,Y: Integer): Integer;

You can assign the Calc function to the variable F:

var F: function(X,Y: Integer): Integer;

F := Calc;

If you take any procedure or function heading and remove the identifier after the word procedure or function, what’s left is the name of a procedural type. You can use such type names directly in variable declarations (as in the example above) or to declare new types:

Type

TIntegerFunction = function: Integer;

TProcedure = procedure;

TStrProc = procedure(const S: string);

TMathFunc = function(X: Double): Double;

Var

F: TIntegerFunction;{ F is a parameterless function that returns an integer }

Proc: TProcedure; { Proc is a parameterless procedure }

SP: TStrProc; { SP is a procedure that takes a string parameter }

M: TMathFunc; { M is a function that takes a Double (real) parameterand returns a Double }

procedure FuncProc(P: TIntegerFunction); { FuncProc is a procedure whose only parameter is a parameterless integer-valued function }

The variables above are all procedure pointers—that is, pointers to the address of a procedure or function. If you want to reference a method of an instance object (see Classes and objects), you need to add the words of object to the procedural type name. For example

Type

TMethod = procedure of object;

TNotifyEvent = procedure(Sender: TObject) of object;

These types represent method pointers. A method pointer is really a pair of pointers; the first stores the address of a method, and the second stores a reference to the object the method belongs to. Given the declarations

Type

TNotifyEvent = procedure(Sender: TObject) of object;

TMainForm = class(TForm)

procedure ButtonClick(Sender: TObject);

...

end;

var

MainForm: TMainForm;

OnClick: TNotifyEvent

we could make the following assignment.OnClick := MainForm.ButtonClick;

Two procedural types are compatible if they have the same calling convention,the same return value (or no return value), and the same number of parameters, with identically typed parameters in corresponding positions. (Parameter names do not matter.)

Procedure pointer types are always incompatible with method pointer types. The value nil can be assigned to any procedural type.

Nested procedures and functions (routines declared within other routines) cannot be used as procedural values, nor can predefined procedures and functions. If you want to use a predefined routine like Length as a procedural value, write a wrapper for it:

function FLength(S: string): Integer;

begin

Result := Length(S);

end;

delphi project of object