其实要了解这些东西,适当的学些反汇编,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;

最后给大家个例子:

type
TNotifyEvent = procedure(Sender: TObject) of object;
TMainForm = class(TForm)
procedure ButtonClick(Sender: TObject);
end;

var
MainForm: TMainForm;
OnClick: TNotifyEvent

OnClick := MainForm.ButtonClick;

参考:http://blog.sina.com.cn/s/blog_78024c8601013cdn.html

Delphi 中的 procedure of object (类方法存在一个隐藏参数self),简单深刻 good的更多相关文章

  1. Delphi 中的 procedure of object

    转载:http://www.cnblogs.com/ywangzi/archive/2012/08/28/2659811.html 总结:TMyEvent = procedure of object; ...

  2. Delphi函数指针的两种定义(对象方法存在一个隐藏参数self,所以不能相互赋值)

    delphi中经常见到以下两种定义 Type TMouseProc = procedure (X,Y:integer); TMouseEvent = procedure (X,Y:integer) o ...

  3. 在Delphi中动态地使用SQL查询语句 Adoquery sql 参数 冒号

    在Delphi中动态地使用SQL查询语句 在一般的数据库管理系统中,通常都需要应用SQL查询语句来提高程序的动态特性.下面介绍如何在Delphi中实现这种功能.在Delphi中,使用SQL查询语句的途 ...

  4. Vue中如何将数据传递到下一个页面(超级简单哒)

    先展示效果:注意URL中值是有变化的 一:在goodslist.vue文件夹绑定 <router-link :to="'/goodsinfo/'+subitem.artID" ...

  5. delphi的procedure of object

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

  6. procedure of object 对象的函数指针

    应用:http://www.cnblogs.com/del88/p/6361117.html 有 class of object ----- 类的类型 那么自然有 方法的类型,方法的类型 分为两种: ...

  7. Delphi 中 COM 实现研究手记(一)

    前言 前些日子用 Delphi 写了一个 Windows 外壳扩展程序,大家知道 Windows 外壳扩展实际上就是 COM 的一种应用 -- Shell COM,虽然整个程序写得还算比较顺利,但写完 ...

  8. delphi中一切皆指针

    unit Unit1; interface uses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Form ...

  9. Java菜鸟学习笔记--面向对象篇(十六):Object类方法

    Object类 什么是Object类? Object类是所有Java类的祖先,每个类都使用 Object 作为超类,所有对象(包括数组)都实现这个类的方法Object类是类层次结构的根,Object类 ...

随机推荐

  1. ios 录音

    http://code4app.com/ios/%E5%BD%95%E9%9F%B3%E5%92%8C%E6%92%AD%E6%94%BE/51ba821b6803fa6901000000

  2. ASP.NET MVC4学习笔记之总体概述

    断断续续使用ASP.NET MVC框架也有一年多了,也算积累了一些经验,唉,一直想写一些笔记好好总结一下,人太懒不想动笔,今天终于决定开始.希望自己能坚持下去. 这篇文章大体介绍ASP.NET MVC ...

  3. eclipse 安装插件不生效

    操作: 下载了一个插件,插件中只有一个jar包,解压放到plugins目录,插件没生效. 解决方法: 把jar包直接扔到dropins目录下,并且删除eclipse\configuration\org ...

  4. .NET开发之窗体间的传值转化操作

    DOTNET开发之窗体间的传值转化操作 好想把自己最近学到的知识写下来和各位朋友分享,也希望得到大神的指点.今天终于知道自己要写点什么,就是关于WPF开发时简单的界面传值与简单操作. 涉及两个界面:一 ...

  5. Excel REPT函数使用

    需要制作1K大小的数据 使用Excel REPT函数可以迅速制造 Excel REPT 函数 =REPT(1,1024) 结果直接黏贴进txt文件,注意删除尾空格.

  6. VC2010 MFC文档类菜单快捷键无法加载问题

    问题1. 在菜单中项中输入&Run\tF5, 运行显示Run,而不是Run F5. 问题2.在Accelerator中绑定了快捷键,但运行程序不起作用. 以上2中问题在VC++2008和VC+ ...

  7. ios系统 处理内存警告

    iPhone下每个app可用的内存是被限制的,如果一个app使用的内存超过20M,则系统会向该app发送Memory Warning消息.收到此消息后,app必须正确处理,否则可能出错或者出现内存泄露 ...

  8. C预处理,条件编译

    预处理是指在编译器之前运行,常以“#”开头 包含3个方面的内容: 1)宏定义与宏替换 2)文件包含 3)条件编译 宏定义与宏替换: 宏名一般大写,替换发生在编译之前,且是机械替换,不做语法检查,也不分 ...

  9. Array.Copy

    var bt = new byte[] { 0x03, 0x00, 0x01, 0xD9, 0x23 }; var result = new byte[] { 0x01, 0x00, 0x03, 0x ...

  10. android开发修改相机扫描二维码框的高宽

    我用的是网上一个现成的例子,可以直接用,但是高宽不合适,现在主流都是大屏幕手机了,所以需要更改. 找到CameraManager 类,更改下面的方法 public Rect getFramingRec ...