Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.08.20;
Скачать: [xml.tar.bz2];

Вниз

Создание массива констант из указателей method pointers   Найти похожие ветки 

 
Fosgen   (2006-07-29 10:55) [0]

Вопрос в следующем:
1. Есть класс TObject1
2. У этого класса имеется куча отднотипных методов (около 100), использующих соответственно поля и св-ва класса TObject1
3. Есть класс TObject2, имеющий св-во OnEvent, по типу совпадающее с методами класса TObject1
4. В процессе работы создается один объект класса TObject1, и много-много объектов класса TObject2. При создании множества объектов класса TObject2, им надо назначать в св-во OnEvent обработчики из класса TObject1.
5. Для этого счастья я планировал завести массив констант. Где будут храниться указатели на методы-обработчики класса TObject1... НО...

1) Создать такой массив на этапе компиляции не представляется возможным, поскольку адреса объекта класса TObject1 еще нет и сл-но адеса его методов также не известны. Дельфя ругается.
2) Массив получается создать если предварительно объявить процедурный тип навроде TNotifyEvent и задать все методы-обработчики класса TObject1  как class procedure, но в этом случае они теряют доступ к св-вам и полям класса TObject1. Почему? Да фиг его знает... Я так этого и не понял, пробовал работать на уровне private\public\published - не помогает.
3) Была идея создать массив переменных где формировать указатели типа method pointers на методы-обработчики класса TObject1. Но в Дельфи я не обнаружил ни одной функции, по имени (либо еще как-то) возвращающей указатель на метод, а не просто нетипизированный указатель. Последний - никуда не впился...

В общем я свои идеи исчерпал, через case ... of либо if ... then делать присвоения 100 различных вариантов меня как-то ломает... Ну как-то тупо это получается...
Пожалуйста, подскажите что в таком случае можно сделать, либо есть какой-то вариант решения?


 
Loginov Dmitry ©   (2006-07-29 16:35) [1]

Букв слишком много...


 
Пусик ©   (2006-07-29 16:58) [2]


> Loginov Dmitry ©   (29.07.06 16:35) [1]
> Букв слишком много...


Ну так не читай.


> Fosgen   (29.07.06 10:55) 


Сконструируй простейший пример для демонстрации твоей задачи и положи сюда, тогда можно будет разобраться в проблеме.


 
tesseract ©   (2006-07-29 17:37) [3]

> 3) Была идея создать массив переменных где формировать указатели
> типа method pointers на методы-обработчики класса TObject1.
> Но в Дельфи я не обнаружил ни одной функции, по имени (либо
> еще как-то) возвращающей указатель на метод, а не просто
> нетипизированный указатель. Последний - никуда не впился...


а через typecasting?

только процедырный тип должен быть один на всех.

а не проще TObject2 от Tobject1 унаследовать? и потом assign-ить?


 
Fosgen   (2006-07-29 20:56) [4]

2: Пусик ©   (29.07.06 16:58) [2]
Значит так по вариантам:

В одном модуле (всегда):

type TObject2 = class
 private
 public
     Event: Byte;
     FonClick: TGLNotify;
 published
   property onClick: TGLNotify read FonClick write FonClick;
 end;


В другом модуле (module2):

Вариант № 1:


Uses module2;

type TObject1 = class
   FrameCount: Word;
   Visible: Boolean;
   Elements: array of TObject2;
 private
   procedure CheckBoxChange(Sender: TGLWidget);
   procedure CheckChange(Sender: TGLWidget);
   procedure NoAction(Sender: TGLWidget);
   procedure ChgHullCond(Sender: TGLWidget);
end;

const
    EventHandlers: array[0..100]  of TGLNotify =
    (NoAction, ChgHullCond, ChgHullCondT, ....


Вот на последнюю строку она и ругается. В принципе понятно почему.

Вариант № 2:


Uses module2;

type TGLNotify = procedure(Sender: TGLWidget) of object;

type TObject1 = class
 public
   FrameCount: Word;
   Visible: Boolean;
   Elements: array of TObject2;
 published
   class procedure CheckBoxChange(Sender: TGLWidget);
   class procedure CheckChange(Sender: TGLWidget);
   class procedure NoAction(Sender: TGLWidget);
   class procedure ChgHullCond(Sender: TGLWidget);
end;

const
    EventHandlers: array[0..100]  of TGLNotify =
    (TObject1.NoAction, TObject1.ChgHullCond, TObject1.ChgHullCondT, ....


В этом варианте из обработчиков TObject1.NoAction, TObject1.ChgHullCond и т.д. не видно св-в FrameCount: Word; Visible: Boolean и т.д.

2: tesseract ©   (29.07.06 17:37) [3]
а не проще TObject2 от Tobject1 унаследовать? и потом assign-ить?

Нет не проще. И совсем из другой оперы. Зачем мне допустим делать кнопку потомком формы (как пример)? А обработчики формы-то надо присваивать на события кнопки...


 
Fosgen   (2006-07-29 21:01) [5]

Косяк мой. В указанном коде во втором варианте строку:

type TGLNotify = procedure(Sender: TGLWidget) of object;

надо перенести в module2, ну и класс TGLWidget считать равным TObject2 это одно и то же, только заменить забыл...


 
jack128 ©   (2006-07-30 17:19) [6]

Fosgen   (29.07.06 10:55)
1) Создать такой массив на этапе компиляции не представляется возможным, поскольку адреса объекта класса TObject1 еще нет и сл-но адеса его методов также не известны.

адреса как раз известны.  P := @TObject.SameMethod. Нно событие - это не только адрес метода, но и указатель на собственно объект.  А этого вот этого объекта на этапе компиляции еще нет.

Fosgen   (29.07.06 10:55)
все методы-обработчики класса TObject1  как class procedure, но в этом случае они теряют доступ к св-вам и полям класса TObject1. Почему?

потому что ты они стали классовыми методами. То есть связанными  с классом, а конкретным экземпляром этого класса(читай с объектом).

Как это делается:

var
 Obj1: TObject1;
 Handlers: array [0..100 - 1] of TNotifyEvent;
 Obj2Arr: array [0..100 - 1] of TObject2;
begin
 // Гдето выше объект Obj1 должен быть уже создан!!!!!!!!!!!!!
 Handlers[0] := Obj1.CheckBoxChange;
 Handlers[1] := Obj1.CheckChange;
 Handlers[2] := Obj1.NoAction;
 Handlers[3] := Obj1.ChgHullCond;
 // и так далее...
 for I := low(Obj2Arr) to high(Obj2Arr) do
 begin
   Obj2Arr[I] := TObject2.Create;
   Obj2Arr[I].SameEvent := Handlers[I];
 end;
end;


 
Fosgen   (2006-07-30 20:42) [7]

2: jack128 ©   (30.07.06 17:19) [6]

Уважаемый, а Вы внимательно читаете предыдущие посты?

адреса как раз известны.  P := @TObject.SameMethod. Нно событие - это не только адрес метода, но и указатель на собственно объект.  А этого вот этого объекта на этапе компиляции еще нет.

Вроде я еще в первом своем посте так и написал:
поскольку адреса объекта класса TObject1 еще нет и сл-но адеса его методов также не известны...

А т.к. Ваш указатель  P := @TObject.SameMethod является относительным TObject, то на выходе получите Вы только тип Pointer, который интереса в данном контексте никому не представляет.

То есть связанными  с классом, а конкретным экземпляром этого класса(читай с объектом).

И с каким именно классом\объектом (по примеру) они стали связаны?

Как это делается:

Знаете ояпть же, как написано в ПЕРВОМ посте: делать присвоения 100 различных вариантов меня как-то ломает

Если Вам такое решение нравится - милости прошу, но для меня это не является ответом Как это делается:. Потому что гибкости в таком подходе - никакой. Количество методов изменилось, процесс заполнения массива тоже переделывай... Да и зачем тогда массив-то? В чем его смысл? Через case...of сразу и присваивай методы. Тем более что Вы не поняли  - я не утверждал что Obj2Arr[I].SameEvent := Handlers[I]; Будет применимо всегда. Тем более что даже количество элементов Obj2Arr может различаться (превышать) с кол-вом элементов Handlers... И не всегда первый элемент Obj2Arr должен содержать ссылку на первый элемент Handlers.


 
Джо ©   (2006-08-01 05:02) [8]

Не уверен, что я верно понял задачу.
Вот что-то в таком роде подойдет?

 
...
 TObject2 = class
 private
   FOnEvent: TOnEventProc;
 public
   property OnEvent: TOnEventProc read FOnEvent write FOnEvent;
 end;

 TObject1 = class
 published
   procedure A (Sender: TObject2);
   procedure B (Sender: TObject2);
   procedure C (Sender: TObject2);
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

const
 MethodNames: array [1..3] of string =
 (
   "A",
   "B",
   "C"
 );

var
 Objects2: array [1..3] of TObject2;
 Object1: TObject1;

procedure CreateAssignEventHandlers;
var
 I: Integer;
 MP: Pointer;
 Met: TMethod;
begin
 for I := Low(Objects2) to High (Objects2) do
 begin
   Objects2[I] := TObject2.Create;
   MP := Object1.MethodAddress(MethodNames[I]);
   Met.Code := MP;
   Met.Data := Objects2[I];
   Objects2[I].OnEvent := TOnEventProc(Met);
 end;
end;

{ TObject1 }

procedure TObject1.A(Sender: TObject2);
begin
 ShowMessage ("A")
end;

procedure TObject1.B(Sender: TObject2);
begin
 ShowMessage ("B")
end;

procedure TObject1.C(Sender: TObject2);
begin
 ShowMessage ("C")
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 I: Integer;
begin
 // проверка
 for I := Low(Objects2) to High (Objects2) do
   Objects2[I].OnEvent (Objects2[I]);
end;

initialization
 Object1 := TObject1.Create;
 CreateAssignEventHandlers;

finalization
 // ну, тут удаляем все объекты, это я опустил

end.


 
Джо ©   (2006-08-01 05:03) [9]

Перед этим кодом, разумеется:
type
 TObject2 = class;

 TOnEventProc = procedure (Sender: TObject2) of object;


 
Джо ©   (2006-08-01 05:05) [10]

Всё, точно спать пора... В процедуре CreateAssignEventHandlers вот так:

   Met.Code := MP;
   Met.Data := Object1;


 
Fosgen   (2006-08-01 20:14) [11]

Однако!
Благодарствую, Джо!

Решение, предложенное тобой, по крайней мере удовлетворяет все вышеизложенные конфликты. Проверить корректность работы структуры

MP := Object1.MethodAddress(MethodNames[I]);
  Met.Code := MP;
  Met.Data := Objects2[I];
  Objects2[I].OnEvent := TOnEventProc(Met);


Еще не успел, но как минимум все компилируется! Т.е. нет несовпадения типов и нет проблем с доступом к полям и переменным.
А я как раз и не мог найти тип, способный хранить двойной указатель на метод. Оказывается есть прямо TMethod...

Да, и откуда ты выкопал такую структуру: TOnEventProc(Met);??? Очень интересно, даже нигде намека не встречал... Но компилируется, млин!!!
Спасибо!!!


 
Джо ©   (2006-08-01 21:02) [12]

> Проверить корректность работы структуры
>
>  Met.Data := Objects2[I];

Тут я допустил машинальную ошибку. Исправился в посте [10] :)


 
DiamondShark ©   (2006-08-01 23:24) [13]

{$M+}
 TObject1 = class
 published
   procedure A (Sender: TObject2);
   procedure B (Sender: TObject2);
   procedure C (Sender: TObject2);
 end;
{$M-}


 
Джо ©   (2006-08-01 23:37) [14]

> [13] DiamondShark ©   (01.08.06 23:24)
> {$M+}

Оно для MethodAddress не нужно :)


 
DiamondShark ©   (2006-08-01 23:53) [15]

И ведь правда не нужно. :-Х


 
Fosgen   (2006-08-02 09:58) [16]

2: Джо ©   (01.08.06 21:02) [12]

Да там я разумеется исправил как должно быть. В конце концов, если я с такими вопросами на форум выпадаю, то думаю - не безнадежно тупой и уж основы-то знаю. :)

Однако, решение искалось почти две недели, за последнюю было "опрошено" около 10 программеров в живую, и сколько-то человеков просмотрело вопрос на форуме, а предложить настоящее решение смог только один... Мда...
Спасибо, Джо!



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2006.08.20;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.5 MB
Время: 0.043 c
15-1153073622
NAS
2006-07-16 22:13
2006.08.20
Оплачу програмку


6-1143832549
Новочеркасский Волк
2006-03-31 23:15
2006.08.20
Проводник удалённого компьютера.


3-1150214247
Klaus B.
2006-06-13 19:57
2006.08.20
проблема с SET TERM


15-1153845017
oldman
2006-07-25 20:30
2006.08.20
Как съезжают программисты...


15-1153472316
Strate
2006-07-21 12:58
2006.08.20
Тест браузеров





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский