几个声明的问题,高手请指点一下。 ( 积分: 100 )

  • 主题发起人 主题发起人 javesun
  • 开始时间 开始时间
J

javesun

Unregistered / Unconfirmed
GUEST, unregistred user!
1.procedure DoOnMessage(var Message: TMessage)
Message WM_XXXXXX;
2.procedure TObject.Dispatch(var Message)


在1中,不用var行不行?还有后面的 Message WM_XXXXXX;是什么意思?是否只能处理
WM_XXXXXX的消息,其它的不行?
在2中,只有var Message,而不是象1一样 var Message: TMessage一样??
还有就是普通的procedure 中,传递参数时不加var啊?

高手能给解释一下吗?
 
1.procedure DoOnMessage(var Message: TMessage)
Message WM_XXXXXX;
2.procedure TObject.Dispatch(var Message)


在1中,不用var行不行?还有后面的 Message WM_XXXXXX;是什么意思?是否只能处理
WM_XXXXXX的消息,其它的不行?
在2中,只有var Message,而不是象1一样 var Message: TMessage一样??
还有就是普通的procedure 中,传递参数时不加var啊?

高手能给解释一下吗?
 
procedure TObject.Dispatch(var Message)

里面的Message是指传递系统的message.
procedure DoOnMessage(var Message: TMessage)
Message WM_XXXXXX;
里面的Message是指声明一个TMessage类型的变量。
 
procedure TObject.Dispatch(var Message)

里面的Message是指传递系统的message.
那怎么还加了一个var?有什么作用?
 
加var是传回来的。不加是传进去的,就这么理解吧。所有函数都一样

procedure tt(var mm:string)
begin
mm:='aa';
end;
button.click
var
z:string;
begin
tt(Z);
showmessage(z)
//'aa'这里是这个值
end;
 
楼上写的什么?!
;//add
 
1.不用var当然可以.
Message WM_XXXXXX:表示当收到这个消息时则执行前面的这个过程.
用var,是指传址参数,不用var是指传值参数,用var可以在消息处理过程中更改消息内容.
 
第一种明白了,第二种还是不太明白。。。

用var,是指传址参数,不用var是指传值参数,用var可以在消息处理过程中更改消息内容???
czcn,能再解释一下吗?
 
用了var/const修饰词是把参数的首地址传入过程, 不用的话是把参数复制到堆栈中传递, 比如:
procedure test(R: TRect) 传的就是R整个副本(传递前delphi会在堆栈中先把R复制一份)16字节,
而procedure test(var R: TRect)/procedure test(const R: TRect) 传的就是R这个变量的首地址--4字节.

这样一来第二种调用也很好理解了, 首先它传的是一个变量的首地址, 其次, 这个变量的数据类型在传递时未知(也就是说这个变量内容具体占多少字节内存不知道).
因此:
procedure test(var Buf) 和
procedure test(Buf: Pointer) 对test过程内部的代码来说可以认为是一样的,
不同只针对调用者, 比如下面需要把Buf分别传递给test和test1时:
var
Buf: array [0..100] of Char;

procedure test(var Param);
procedure Test1(Param: Pointer);

调用时:
test(buf) ;// or test(buf[0])
test1(@buf);

顺便说一句: const 修饰词和var修饰词传递方式一样, 不同的就是对const修饰词编译器会对代码进行检查, 当发现对const修饰的变量进行了修改就会报编译错误, 这些检查都是在编译时完成的, 而在运行时没有任何限制, 因此通过代码中的一些小技巧完全可以做到对const关键字传入的参数进行修改同时也改变了原始变量的内容(只是看上去完全没有必要这么做)

一个特例: string和dynamic array不管有没有var/const修饰词传递的都是首地址, 只是没有var/const修饰词时编译器会在你对这个参数进行修改时生成语句先复制一份副本然后让你改变副本, 通过这样做到修改参数内容而不会影响原始string的
 
1、(var Message)和(var Message: TMessage)有什么区别,前面的那个Message是否有调用这个函数之前已定义???如果没有定义,怎么知道它是什么样的??
2、另外,后面的那个TMessage能否省略?
 
1. 对被调用者(过程/函数内部)来说(var Message: TMessage)传过来的是一块内存的首地址, 这块内存中存放的是个TMessage类型的数据, 它的长度是TMessage类型所占的长度.
而(var Message)传过来的就是一个内存首地址, 至于这块内存是否有效, 占用了多大空间, 存放的是什么类型的数据都是未知的. 也就是你说的没有定义.
至于怎么知道它是怎么样的, 一般对这种参数的处理时都必须使用强制类型转换将这个无类型参数转换成你代码预期的那个类型再进行处理. 至于这个参数是否真是你代码所预期的那个数据类型则是未知的, 在编译期无法对参数是否合法作出检查, 所有一切都要等到运行时才能知道. 因此编写此类参数的过程/函数时一般都需要特别关注对错误的处理(除非你肯定调用者不会传来非法数据), 搞得不巧的话就不是弹出错误框的问题而是整个程序(甚至整个操作系统)崩溃的问题了.
2. 如果你要调用的过程函数是外部函数(比如在dll中), 你完全可以声明一个省略TMessage的函数原型并把它关联到这个外部函数上.
例如API CopyFile在delphi中原来的声明是:
function CopyFile(lpExistingFileName, lpNewFileName: PChar
bFailIfExists: BOOL): BOOL
stdcall;
你完全可以另外定义一个函数形式实际也是调用windows API CopyFile:
// 这里的ExistingFileName, NewFileName都作为无类型参数
function MyCopyFile(var ExistingFileName, var NewFileName
FailIfExists: BOOL): BOOL
stdcall
external kernal32 name 'CopyFileA';
调用:
var
OldFileName, NewFileName: string;
begin
OldFileName := ...;
NewFileName := ...
MyCopyFile(OldFileName[1], NewFileName[1], False);
end;
 
加Var 表示在方法里面对 参数的修改会放回到方法的外面;
在消息处理时,有一个标志该消息是否被处理完成,
Message.Result := 0
表示该消息未被处理,消息就继续传送了;

Message.Result := 1
表示该消息被处理了,消息就不会继续传送了;

所以在函数
1.procedure DoOnMessage(var Message: TMessage)
Message WM_XXXXXX;
2.procedure TObject.Dispatch(var Message)

都是要添加Var的
 
多人接受答案了。
 

Similar threads

后退
顶部