Advertisement
carlosfeitozafilho

Explicação Básica de Ponteiros versus Ponteiros de Método

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