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

总结:TMyEvent = procedure of object; 与 TMyProc = procedure;区别就是 TMyEvent可以再过程内部调用self,而TMyProc不可以

其实要了解这些东西,适当的学些反汇编,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 中的 procedure of object的更多相关文章

  1. Delphi 中的 procedure of object (类方法存在一个隐藏参数self),简单深刻 good

    其实要了解这些东西,适当的学些反汇编,WINDOWS内存管理机制,PE结构,看下李维的VCL架构剖析可以很好理解type TMyEvent = procedure of object;这是一种数据类型 ...

  2. 在 DELPHI 中 procedure 型变量与 method 型变量的区别

    Procedure型变量: 在DELPHI中,函数.过程的地址可以赋给一个特殊类型的变量,变量可用如下方式声明: var p : procedure(num:integer); //过程 或: var ...

  3. delphi的procedure of object

    delphi的procedure of object(一个特殊的指针类型) 理论: //适用于实现不是某一特定过程或函数 type TNotifyEvent = procedure(Sender: T ...

  4. Delphi调用爷爷类的方法(自己构建一个procedure of Object)

    Delphi通过inherited 可以调用父类的方法,但是没有提供直接调用父类的父类的方法(爷爷类),通过变通的方式实现如下: 假设父类是TFather,爷爷类TGrand,调用爷爷类的Write方 ...

  5. Delphi中使用比较少的一些语法

    本文是为了加强记忆而写,这里写的大多数内容都是在编程的日常工作中使用频率不高的东西,但是又十分重要. ---Murphy 1,构造和析构函数: a,构造函数: 一般基于TComponent组件的派生类 ...

  6. Delphi中的函数指针判断是否为空

    delphi函数指针 只有@@p才代表了函数指针本身的地址   assigned(p) 判断是否为空 或者用 @p=nil 来判断函数指针是不是为空 Delphi中的函数指针实际上就是指针,只是在使用 ...

  7. Delphi中线程类TThread实现多线程编程1---构造、析构……

    参考:http://www.cnblogs.com/rogee/archive/2010/09/20/1832053.html Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大 ...

  8. 用SPCOMM 在 Delphi中实现串口通讯 转

      用Delphi 实现串口通讯,常用的几种方法为:使用控件如MSCOMM和SPCOMM,使用API函数或者在Delphi 中调用其它串口通讯程序.利用API编写串口通信程序较为复杂,需要掌握大量通信 ...

  9. 教程-Delphi中Spcomm使用属性及用法详解

    Delphi中Spcomm使用属性及用法详解 Delphi是一种具有 功能强大.简便易用和代码执行速度快等优点的可视化快速应用开发工具,它在构架企业信息系统方面发挥着越来越重要的作用,许多程序员愿意选 ...

随机推荐

  1. 非阻塞socket学习,select基本用法

    server #include <stdio.h> #include <winsock2.h> #include <iostream> #pragma commen ...

  2. Java观察者设计模式

    在java.util包中提供了Observable类和Observer接口,使用它们即可完成观察者模式. 多个观察者都在关注着价格的变化,只要价格一有变化,则所有的观察者会立即有所行动. //==== ...

  3. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【九】——API变了,客户端怎么办?

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 一旦我们将API发布之后,消费者就会开始使用并和其他的一些数据混在一起.然而,当新的需求出现 ...

  4. 在项目中那个少用if else 语句,精简代码,便于维护的方法(1)

    一般我在写一个函数的时候,可能需要一个回调函数,例如: function loadQtipCode(dom, title, content, width, showcb, hidecb) { $(do ...

  5. swiper 技巧

    全屏广告高度 ,加上属性. html, body { position: relative; height: 100%; } 停止自行播放 mySwiper.stopAutoplay(); 锁住状态, ...

  6. CSS3新增基础属性总结——20160409(易达客)

    1.box-shadow :h-shadow v-shadow blur spread color inset(outset) h-shadow:必须:水平阴影位置,允许负值. v-shadow:必须 ...

  7. php字符串常用算法--字符串加密解密

    /** * 加密.解密字符串 * * @global string $db_hash * @global array $pwServer * @param $string 待处理字符串 * @para ...

  8. jQuery简单实现iframe的高度根据页面内容自适应的方法

    同域下: //注意:下面的代码是放在和iframe同一个页面中调用 $("#myiframe").load(function () { var myiframeH = $(this ...

  9. Yii2 行为

    // Step 1: 定义一个将绑定行为的类 class MyClass extends yii\base\Component { // 空的 } // Step 2: 定义一个行为类,他将绑定到My ...

  10. winxp可以禁用的服务

    要注意的是: 虽然某个服务你设置成了手动, 而且在services.msc中好像也没有启动, 但是并不表示这个服务不可以被启动 因为某些软件, 可能在程序内部进行了编程的设置, 它可以在内部去启动 服 ...