2013-06-15 9 views
8

Chciałbym procedurę obiektu korzystać w rekordzie, tak:Jak mogę dołączyć wskaźnik metody do wpisanej stałej?

TCommandRec = record 
    name: string; 
    fn: procedure of object; 
end; 

mogę utworzyć tablicę z tym za zadanie:

commands: array [0..1] of TCommandRec; 

... 

commands[0].name := '-help'; 
commands[0].fn := DoHelp; 
commands[1].name := '-load'; 
commands[1].fn := DoLoad; 

Co naprawdę chciałbym robić jest stała:

const 
    cmds: array [0..1] of TCommandRec = 
    (
    (name: '-help'; fn: DoHelp), 
    (name: '-load'; fn: DoLoad) 
); 

Jednak otrzymuję błędy dla DoHelp i DoLoad - oczekiwane stałe wyrażenie. Są to dwie metody klasy. Czy jest jakaś składnia, której potrzebuję do wykonania tej pracy, czy też utknąłem budując tablicę w czasie wykonywania?

+0

nie, metoda wskaźnika nie kwalifikuje się jako stałą ekspresję (głównie ze względu na przykład wskaźnik - patrz TMethod.Data). – OnTheFly

+0

@ user539484 Wskaźniki metod ze stałymi tematami to wyrażenia stałe –

+0

@ David Heffernan, czy masz przykład? – OnTheFly

Odpowiedz

7

Metoda obiektu to tak zwany typ dwóch wskaźników. Zawiera następujące informacje:

  1. Adres funkcji.
  2. Adres obiektu lub tematu.

Pierwszy z nich jest znany w czasie kompilacji, ale ogólnie to drugie nie jest. Dlatego zwykle musisz tworzyć te rzeczy w czasie wykonywania.

Jeśli możesz ustawić, że temat jest znany podczas kompilacji, możesz zadeklarować stałą wpisaną dla twojego typu rekordu. Na przykład:

type 
    TMyRecord = record 
    Foo: procedure of object; 
    end; 

    TMyStaticClass = class 
    class procedure Foo; 
    end; 

class procedure TMyStaticClass.Foo; 
begin 
end; 

const 
    MyRecord: TMyRecord = (Foo: TMyStaticClass.Foo); 

Oczywiście, będzie to przydatne tylko wtedy, gdy twoje funkcje będą funkcjonować jako metody klasowe, a nie metody instancji. Dodaję tylko powyższy kod, aby zilustrować, że możesz mieć stałe wskaźniki metod, o ile temat jest stałą czasu kompilacji.

+0

Podoba mi się ta odpowiedź - mogę używać procedur klasowych, ponieważ klasa działa po prostu jako dyspozytor dla argumentów linii poleceń. – imekon

2

można przechowywać wskaźniki do metod w dokumentacji (są znane w czasie kompilacji, więc nie ma problemu, określając je w const definicji):

TCommandRec = record 
    name: string; 
    fn: Pointer; 
end; 

... 
const 
    cmds: array [0..1] of TCommandRec = 
    (
    (name: '-help'; fn: @DoHelp), 
    (name: '-load'; fn: @DoLoad) 
); 

Wtedy, kiedy trzeba zadzwonić fn z cmds[i] (Przypuszczam, że rozmowa odbywa się wewnątrz tej samej klasy, który definiuje metody DoHelp i DoLoad), napisać coś takiego:

type TObjectProc = procedure of object; 
var m: TMethod; 
... 
m.Code := cmds[i].fn; 
m.Data := Self; 
TObjectProc(m); 
+0

W przypadku nowoczesnego Delphi możesz użyć nowego stylu RTTI dla takiego podejścia do środowiska wykonawczego. Poproś o stałą nazwę metody i wywołaj za pomocą RTTI na konkretnej instancji. –

+0

Tak, dziękuję. Jeśli dobrze pamiętam, RTTI działa tylko dla "opublikowanych" metod. Ale jest to mniej efektywne niż przechowywanie wskaźnika (chociaż prawdopodobnie nie ma tu pewności), a kompilator nie ostrzeże nas, jeśli mamy literówkę w nazwie metody lub jeśli zmienimy nazwę odpowiedniej metody w klasie. – Inspired

+1

Nowy styl RTTI nie jest oparty na opublikowanych. Jest to kompromis pomiędzy wydajnością i nie poleganiem na szczegółach implementacji. –

Powiązane problemy