Delphi 中的 procedure of object

Delphi 中的 procedure of objectwindows

 


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


TMyEvent 和 TMyProc 都定義了一個函數類型,他們的差異是,TMyProc 不能夠用在類中定義事件,TMyEvent 卻能夠。app


若是你想知道問什麼,那就須要深刻了解事件類型以及函數類型究竟是個什麼?less


procedure a();
begin
  ShowMessage()
end;ide


var
  Func1: TMyProc;
  Func2: TMyEvent;函數


  func1 := A;操作系統


func1 := A;指針


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


在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;


最後給你們個例子:

type  TNotifyEvent = procedure(Sender: TObject) of object;  TMainForm = class(TForm)    procedure ButtonClick(Sender: TObject);    ...  end;var  MainForm: TMainForm;  OnClick: TNotifyEvent im..... OnClick := MainForm.ButtonClick;

相關文章
相關標籤/搜索