Qual a diferença entre os dois?
- unit Unit2;
- interface
- uses
- Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
- Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
- type
- TProc = procedure(AParametro: String) of object;
- PProc = ^TProc;
- TForm2 = class(TForm)
- Button1: TButton;
- procedure Button1Click(Sender: TObject);
- private
- { Private declarations }
- public
- procedure Proc1;
- procedure Proc2(AParametro: String);
- { Public declarations }
- end;
- var
- Form2: TForm2;
- implementation
- {$R *.dfm}
- procedure TForm2.Button1Click(Sender: TObject);
- var
- A: TProc;
- B: PProc;
- begin
- // A contém uma referência a Proc2. Como A é um ponteiro de método e não
- // ponteiro comum, a referência pode ser direta, pois TProc define uma
- // assinatura que é compatível com "Proc2".
- A := Proc2;
- // B não é um ponteiro de método. B é um ponteiro para um ponteiro de método,
- // pois ele aponta para TProc (que é o ponteiro de método). Por ser um
- // ponteiro para algo, ele precisa ter sua memória alocada antes de ser usado,
- // do contrário haverá lixo dentro dele. Para alocar se usa GetMem. Como B
- // aponta para TProc, o segundo parâmetro de GetMem será o "tamanho do
- // apontado", por isso usa-se SizeOf(TProc)
- GetMem(B,SizeOf(TProc));
- try
- // Neste ponto, B é um espaço de memória alocada que espera receber um
- // TProc, mas ainda está apontando para nil. Se você fizer B := @A, você
- // estará descartando a memória alocada na instrução anterior e estará
- // dizendo que B e A estão no mesmo lugar da memória, já que @A significa
- // "endereço de A" ou "local da memória onde A está". Como B é um ponteiro
- // para um ponteiro de método, se você fizer B := @A, B vai assumir que
- // aquele endereço contém um "poneiro para um ponteiro de método", quando na
- // verdade ele possui apenas um "ponteiro de método", ou seja, você estará,
- // grosso modo, formatando um espaço de memória de forma errada e é por isso
- // que o Access Violation ocorria. Ao fazer B^ := A, por outro lado, você
- // está dizendo que "o valor apontado por B é A". Ora, se B aponta para um
- // TProc e A é um TProc, ao fazer B^ := A, você estará preenchendo as
- // lacunas que faltavam para que B seja uma variável completa e carregada
- // com o valor correto! Novamente, grosso modo, fazendo desta forma você
- // estará formatando a memória corretamente
- B^ := A;
- // Ao executar o ShowMessage, você vai notar que os endereços de B e de A
- // são diferentes e isso é natural, porque B foi alocado com GetMem e também
- // porque "B aponta para um ponteiro de método" enquanto "A é um ponteiro de
- // método", logo, são variáveis que apontam para coisas distintas e é
- // natural que seus endereços sejam diferentes. Por outro lado, o endereço
- // daquilo que é apontado por B é igual ao endereço de A, como se pode
- // imaginar
- 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));
- // Como A é um ponteiro de método, ele não precisa de maiores artifícios. A
- // é um alias para um método (no caso Proc2) e por isso pode ser chamado
- // diretamente. Note que é A indistinguível de Proc2, pois pode ser
- // executado inclusive com parâmetros sem problema algum
- A('Via variável A');
- // B, por outro lado é um ponteiro para um ponteiro de método, logo,
- // executar diretamente B não é possível, porque B sozinho é só um ponteiro
- // para um ponteiro de método. Aquilo que B aponta é que pode ser executado
- // e é por isso que para que B possa ser executado como Proc2 precisamos
- // acessar aquilo que ele está apontando (TProc, o ponteiro de método) e
- // para isso se usa a deferência
- B^('Via variável B');
- finally
- // Dispensa comentários;
- FreeMem(B);
- end;
- end;
- procedure TForm2.Proc1;
- begin
- ShowMessage('Chamou Proc1');
- end;
- procedure TForm2.Proc2(AParametro: String);
- begin
- ShowMessage('Chamou Proc2: ' + AParametro);
- end;
- end.