Pointer a funkcje klas

0

Może Od razu opiszę problem jakoże dla mnie generalnie klasy i obiekty to ciągle troche czarna magia :P .
Mam sobie x metod o nazwach Foo1, Foo2 itd. . Są one różnie pogrupowane w Klasach TFoo1, TFoo2 itd. . Każda z tych klas dziedziczy z TFirstFoo. W klasie TFirstFoo jest sobie metoda Init która jest wirutalna. W kazdej Klasie TFoo1, TFoo2 itd. jest definiowana procedura Init która nadpisuje tamtą. Procedura Init ma za zadanie wywołanie metody Add która jest również zdefiniowana w TFirstFoo. Procedura Add potrzebuje pointera do funkcji Foo1, Foo2 itd. zależnie od klasy ma różne metody Foo.

I tutaj zaczyna się problem: Póki nie było to w klasach, mogłem to po prostu wywołać Add(@Foo1);Add(@Foo2); itd. . Teraz w klasach tak nie mogę (po szukaniu znalazłem że poza wskaźnikiem do procedury jest potrzebny jeszcze do obiektu. Dodatkowym problemem jest to, że nie każda metoda FooX ma taką samą listę parametrów, dokładnie to są dwa typy parametrów które lekko się różnią.

Teraz pytanie: Czy w jakiś prosty sposób (bo tych metod jest dużo) da się pobrać pointer do metody a potem w procedurze Add skleić go z pointerem do obiektu (to akurat może być trudniejsze trochę, bo procedura Add jest tylko jedna).

Jeśli tak, to jak :P .

Jeśli nie, to jakie inne rozwiązanie mi polecacie? :-]

**Z góry dzięki za pomoc i przepraszam za chaotyczne pisanie ale jest już późno ;) .

0

jeśli zarówna metoda Add jak i Foo jest w tej samej klasie to dlaczego chcesz przekazywać ją jako parametr?

Może zrób to tak

type
  TFirstFoo = class
  protected 
    procedure Init; virtual;
    procedure Add; virtual;
    procedure Foo(a: Integer); virtual; abstract;
    procedure Foo(b: string); virtual; abstract;
  end;

  TFoo1 = class(TFirstFoo)
  protected 
    procedure Foo(a: Integer); override;
    procedure Foo(b: string); override;
  end;

  TFoo2 = class(TFirstFoo)
  protected 
    procedure Foo(a: Integer); override;
    procedure Foo(b: string); override;
  end;

implementation

procedure TFirstFoo.Init; 
begin
  Add;
end;

procedure TFirstFoo.Add; 
begin
  Foo(1);
  Foo('aaa');
end;

procedure TFoo1.Foo(a: Integer); override;
begin
  writeln('foo1 int');
end;

procedure TFoo1.Foo(b: string); override;
begin
  writeln('foo1 string');
end;

procedure TFoo1.Foo(a: Integer); override;
begin
  writeln('foo2 int');
end;

procedure TFoo1.Foo(b: string); override;
begin
  writeln('foo2 string');
end;

///////
var
  f1: TFoo1;
  f2: TFoo2;
begin
  f1 := TFoo1.Create;
  f2 := TFoo2.Create;
  f1.Init;
  //wyswietli
  //foo1 int
  //foo1 string
  f2.Init;
  //wyswietli
  //foo2 int
  //foo2 string
0

Źle zrozumiałeś, TFirstFoo nie ma metody Foo (które powinny według przykładu nazywać się Foo1, Foo2 itd.).

Procedura Add nie polega na ich wykonaniu, ale tak naprawdę to wysyła dane o danej metodzie do rodzica, który w zależności od potrzeby będzie się odwoływać do danej metody.

Tak pomyślałem, czy nie ma może jakiegoś typu na który dałoby się łatwo przerzucić metodę. Czy typ 'procedure of object' będzie ok? Czy nie będzie on potrzebować procedury która nie zawiera parametrów? I czy potam uda się go przekształcić na coś w stylu 'function (a,b:x; c:y) of object' ?

0

to może napisz co to ma robić bo jak na razie to mi się wydaje, że próbujesz wymyślić koło od nowa

0

Jest to związane z przeprojektowaniem systemu obsługi procedur do mojego języka skryptów.
Wcześniej w obiekcie głównym była sobie procedura AddProc (i AddProcV2 - którą wykonuje się gdy procedura która dodajemy jest rozszerzonego standardu). Powodowała ona po prostu dodanie wskaźnika i innych danych o procedurze do listy procedur. Potem było to zamieniane na typ proceduralny i wykonywane (gdy była potrzeba wykonania takiego polecenia).

Teraz chcę to przeprojektować tak, aby procedury dzieliły się na paczki (TFoo1, TFoo2) które dodaje się do interpretera. No i jakoże projekt ten jest dosyć spory, to im mniej pracy to lepiej, zrobiłem to bez zbytnich zmian, mając tylko pointer do procedury, ale mogę to zmienić, tylko nie zabardzo wiem na co :P .

0

Koledzy wybaczą za bump, ale problem jest wciąż nierozwiązany. Jeśli ktoś ma jakiś pomysł, pisać śmiało. :-/

0

Bo nikt nie rozumie, co chcesz zrobić. Probujesz ominąć językowe mechanizmy obiektowości do własnych celów. Tymczasem prawie na pewno nie trzeba tego robić, tylko przeprojektować program.

Teraz w klasach tak nie mogę (po szukaniu znalazłem że poza wskaźnikiem do procedury jest potrzebny jeszcze do obiektu.

  1. wydaje mi się, że metody statyczne (class function, class procedure) nie mają parametru „self”, więc można ich używać jako normalnych wskaźników na funkcje.
  2. zainteresuj się „wskaźnikiem na metodę”, czyli składnią „type TMetoda = procedure(a:integer) of object;”. takie wskaźniki magicznie pamiętają, z którego obiektu pochodzą.

Teraz w klasach tak nie mogę (po szukaniu znalazłem że poza wskaźnikiem do procedury jest potrzebny jeszcze do obiektu
tak, metody pobierają ukryty parametr „Self”, będący obiektem na rzecz którego są wywoływane. takie coś:

f1.Foo(5);

w rzeczywistości robi coś takiego:

TFoo1.Foo(f1,5);
0
Azarien napisał(a)

Bo nikt nie rozumie, co chcesz zrobić. Probujesz ominąć językowe mechanizmy obiektowości do własnych celów. Tymczasem prawie na pewno nie trzeba tego robić, tylko przeprojektować program.

Nic nie omijam... Nie da się tego inaczej zrobić, czytaj dalej to się dowiesz czemu.

Azarien napisał(a)
  1. wydaje mi się, że metody statyczne (class function, class procedure) nie mają parametru „self”, więc można ich używać jako normalnych wskaźników na funkcje.

to są metody statyczne, ale jak widać w debugerze mają (przynajmniej tak wynika z moich doświadczeń). Zresztą jak w jednym pointerze chcesz mieć wskaźnik do obiektu (bo w SPACJA końcu każda metoda ma do tego dostęp) i na dodatek miejsce procedury do wykonania?

Azarien napisał(a)
  1. zainteresuj się „wskaźnikiem na metodę”, czyli składnią „type TMetoda = procedure(a:integer) of object;”. takie wskaźniki magicznie pamiętają, z którego obiektu pochodzą.

A myślisz że jak wykonuje? =] Nie mogę tak pobrać danych, gdyż mają one różne parametry, i kompilator (FPC swoją drogą) czepia się o listę parametrów.

Azarien napisał(a)

tak, metody pobierają ukryty parametr „Self”, będący obiektem na rzecz którego są wywoływane. takie coś:

f1.Foo(5);

w rzeczywistości robi coś takiego:

TFoo1.Foo(f1,5);

Tyle to ja wiem =] .

A co do problemu samego w sobie, zapytałem na kanale IRC Free Pascala i niejaki Laksen (któremu oczywiście dziękuje) dał mi taki przykład:

type
 TMyClass = class
  procedure SomeProc(x,y,z: longint);
 end;
 
 TMyProc = function(x,y,z: longint) of object;

...

var MyProcVar: TMyProc;
    MyObj: TMyClass;

procedure SetProcedure;
begin
   TMethod(MyProcVar).Code := @TMyClass.SomeProc;
end;

procedure CallProcForObject(Obj: TMyClass);
begin
   TMethod(MyProcVar).Data := Obj;
   MyProcVar(1,2,3); // Same as Obj.SomeProc(1,2,3);
end;

begin
   SetProcedure;
   MyObj := TMyClass.Create;
   CallProcForObject(MyObj);
end.

Nie testowałem póki co tego, ale jeśli będzie potrzeba wiedzieć coś więcej co do problemu, wspomnę o tym. Póki co problem uważam za rozwiązany.

1 użytkowników online, w tym zalogowanych: 0, gości: 1