Qual a diferença entre os dois?

格式
Pascal
提交日期
2019-03-13 05:30
Publication Period
Unlimited
  1. unit Unit2;
  2. interface
  3. uses
  4. Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  5. Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
  6. type
  7. TProc = procedure(AParametro: String) of object;
  8. PProc = ^TProc;
  9. TForm2 = class(TForm)
  10. Button1: TButton;
  11. procedure Button1Click(Sender: TObject);
  12. private
  13. { Private declarations }
  14. public
  15. procedure Proc1;
  16. procedure Proc2(AParametro: String);
  17. { Public declarations }
  18. end;
  19. var
  20. Form2: TForm2;
  21. implementation
  22. {$R *.dfm}
  23. procedure TForm2.Button1Click(Sender: TObject);
  24. var
  25. A: TProc;
  26. B: PProc;
  27. begin
  28. // A contém uma referência a Proc2. Como A é um ponteiro de método e não
  29. // ponteiro comum, a referência pode ser direta, pois TProc define uma
  30. // assinatura que é compatível com "Proc2".
  31. A := Proc2;
  32. // B não é um ponteiro de método. B é um ponteiro para um ponteiro de método,
  33. // pois ele aponta para TProc (que é o ponteiro de método). Por ser um
  34. // ponteiro para algo, ele precisa ter sua memória alocada antes de ser usado,
  35. // do contrário haverá lixo dentro dele. Para alocar se usa GetMem. Como B
  36. // aponta para TProc, o segundo parâmetro de GetMem será o "tamanho do
  37. // apontado", por isso usa-se SizeOf(TProc)
  38. GetMem(B,SizeOf(TProc));
  39. try
  40. // Neste ponto, B é um espaço de memória alocada que espera receber um
  41. // TProc, mas ainda está apontando para nil. Se você fizer B := @A, você
  42. // estará descartando a memória alocada na instrução anterior e estará
  43. // dizendo que B e A estão no mesmo lugar da memória, já que @A significa
  44. // "endereço de A" ou "local da memória onde A está". Como B é um ponteiro
  45. // para um ponteiro de método, se você fizer B := @A, B vai assumir que
  46. // aquele endereço contém um "poneiro para um ponteiro de método", quando na
  47. // verdade ele possui apenas um "ponteiro de método", ou seja, você estará,
  48. // grosso modo, formatando um espaço de memória de forma errada e é por isso
  49. // que o Access Violation ocorria. Ao fazer B^ := A, por outro lado, você
  50. // está dizendo que "o valor apontado por B é A". Ora, se B aponta para um
  51. // TProc e A é um TProc, ao fazer B^ := A, você estará preenchendo as
  52. // lacunas que faltavam para que B seja uma variável completa e carregada
  53. // com o valor correto! Novamente, grosso modo, fazendo desta forma você
  54. // estará formatando a memória corretamente
  55. B^ := A;
  56. // Ao executar o ShowMessage, você vai notar que os endereços de B e de A
  57. // são diferentes e isso é natural, porque B foi alocado com GetMem e também
  58. // porque "B aponta para um ponteiro de método" enquanto "A é um ponteiro de
  59. // método", logo, são variáveis que apontam para coisas distintas e é
  60. // natural que seus endereços sejam diferentes. Por outro lado, o endereço
  61. // daquilo que é apontado por B é igual ao endereço de A, como se pode
  62. // imaginar
  63. Showmessage('Endereço de A: 0x' + IntToHex(Integer(@a),2) + #13#10'Endereço de B: 0x' + IntToHex(Integer(@b),2) + #13#10'Endereço de B^ (aquilo que B aponta): 0x' + IntToHex(Integer(@b^),2));
  64. // Como A é um ponteiro de método, ele não precisa de maiores artifícios. A
  65. // é um alias para um método (no caso Proc2) e por isso pode ser chamado
  66. // diretamente. Note que é A indistinguível de Proc2, pois pode ser
  67. // executado inclusive com parâmetros sem problema algum
  68. A('Via variável A');
  69. // B, por outro lado é um ponteiro para um ponteiro de método, logo,
  70. // executar diretamente B não é possível, porque B sozinho é só um ponteiro
  71. // para um ponteiro de método. Aquilo que B aponta é que pode ser executado
  72. // e é por isso que para que B possa ser executado como Proc2 precisamos
  73. // acessar aquilo que ele está apontando (TProc, o ponteiro de método) e
  74. // para isso se usa a deferência
  75. B^('Via variável B');
  76. finally
  77. // Dispensa comentários;
  78. FreeMem(B);
  79. end;
  80. end;
  81. procedure TForm2.Proc1;
  82. begin
  83. ShowMessage('Chamou Proc1');
  84. end;
  85. procedure TForm2.Proc2(AParametro: String);
  86. begin
  87. ShowMessage('Chamou Proc2: ' + AParametro);
  88. end;
  89. end.
下载 可打印视图

网址

Embed with JavaScript

Embed with iframe

原始文本