|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Функция из переменной
Подскажите пожалуйста, как вызвать функцию из переменной?
Задача такая: Имеется пять функций (одностроковых например: f4:=500*1.2*1000/(Rvar/100*x+R880)) и процедура (многострочная), строящая график на канве. Можно конечно и пять процедур накопипастить, под каждую функцию... Но.. Не могу понять, как в процедуру ввести переменную (например F) и согласно условию подставлять в неё какую-либо из фцнкций (тиапа F:=f1, F:=f2, и т.д.). |
#2
|
||||
|
||||
Указатель на функцию. Как это делается при динамическом вызове dll.
Пишу программы за еду. __________________ |
Этот пользователь сказал Спасибо NumLock за это полезное сообщение: | ||
shonty (23.08.2017)
|
#3
|
|||
|
|||
Дополню немного.
Есть 2 типа функций. Просто функции и методы класса. Для первого варианта можно так: Код:
type TFunc = function (x : double) : double; function f1(x : double) : double; begin result := x+1; // просто для примера end; function f2(x : double) : double; begin result := x-1; end; function CalcFunc(x1, x2, dx : double; func : TFunc) : double; var i : double; begin // просто бред для примера result := 0; i := x1; while i <= x2 do begin result := result + func(i); i := i + dx; end; end; // где-то вызов begin writeln('f1 ->', CalcFunc(1,5,0.2,f1); writeln('f2 ->', CalcFunc(1,5,0.2,f2); end; Для второго случая есть 2 подварианта. а. Тоже самое, только тип описан как Код:
type TFunc = function (x : double) : double of object; б. Передавать объект класса. тогда их можно "нанаследовать" от одного родителя. Там есть еще вариант с мета классом. Код:
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 TFuncClass = class class function Name : String; virtual; class function f(x : double) : double; virtual; end; TMetaClass = class of TFuncClass; TF1 = class(TFuncClass) class function Name : String; override; class function f(x : double) : double; override; end; TF2 = class(TFuncClass) class function Name : String; override; class function f(x : double) : double; override; end; TForm2 = class(TForm) Memo1: TMemo; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } function Calc(x1, x2, dx : double; cls : TMetaClass) : double; public { Public declarations } end; var Form2: TForm2; implementation {$R *.dfm} class function TFuncClass.Name : String; begin result := 'TFuncClass'; end; class function TFuncClass.f(x : double) : double; begin Raise Exception.Create('Should not be called.'); end; class function TF1.Name : String; begin result := 'f1'; end; class function TF1.f(x : double) : double; begin result := x + 1; end; class function TF2.Name : String; begin result := 'f2'; end; class function TF2.f(x : double) : double; begin result := x - 1; end; function TForm2.Calc(x1, x2, dx : double; cls : TMetaClass) : double; var i : double; begin result := 0; i := x1; while i <= x2 do begin result := result + cls.f(i); i := i + dx; end; end; procedure TForm2.Button1Click(Sender: TObject); begin Memo1.Lines.Add(Format('class %s, name %s -> %.4f',[TF1.ClassName,TF1.Name,Calc(1,5,0.2,TF1)])); Memo1.Lines.Add(Format('class %s, name %s -> %.4f',[TF2.ClassName,TF2.Name,Calc(1,5,0.2,TF2)])); end; end. Код:
class TF1, name f1 -> 78,0000 class TF2, name f2 -> 38,0000 ЗЫ. Я там совместил вызов собственно функции, форматирование строки и ее добавление в Memo. Думаю, разберешся. ЗЗЫ. Для особо умных. Мне просто было интересно - помню ли я как работать с метаклассами, последний раз делал такое лет 8 назад. Что-то еще помню, написал с первого раза без ошибок. Последний раз редактировалось lmikle, 23.08.2017 в 06:17. |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
shonty (23.08.2017)
|
#4
|
|||
|
|||
Цитата:
Цитата:
PS Мне, как простому советскому радиолюбителю, для подбора резисторов в регуляторе тока (а зависимости сильно нелинейны) нужна программа для отображения графиков. А хотел выкрутится так: var a, b, c, d, e; F:=a*(fnc1)+b*(fnc2)+c*(fnc3)+d*(fnc4)+e*(fnc5) и подстановкой переменных a,b,c,d,e в "0" и "1" выбирать нужный участок выражения Теперь сделаю как положено |
#5
|
|||
|
|||
Если пишешь для себя, то сойдет. Если собираешься делиться, то еще приделай возможность грузиить эти функции из dll, тогда можно будет расширять набор функций не меняя основную программу. Код не намного сложнее получится. Только надо будет сделать получение адресов таких же функций из dll'ей и сохранение их в спике для дальнейшего вызова.
Ну и , насколько я помню, там еще куча интересных зависимостей есть, фильтров от емкостей и индуктивностей, например). |
#6
|
||||
|
||||
Эх, эмбаркадера им лямбды с дженериками дала — используй лямбды с дженериками, используй — не хочу.
Код:
function demo(f1, f2: TFunc<integer, Integer>): integer; begin result := f1(f2(1)); // compose functions end; ... foo := demo( function (a: integer): integer begin result := a+1; end, function (a: integer): integer begin result := a-1; end) ... использование лямбд из переменных f1 = function (a: integer): integer begin result := a+1; end; f2 = function (a: integer): integer begin result := a-1; end; bar = demo(f1, f2) — Как тебя понимать? — Понимать меня не обязательно. Обязательно меня любить и кормить вовремя. На Delphi, увы, больше не программирую. Рекомендуемая литература по программированию Последний раз редактировалось M.A.D.M.A.N., 25.08.2017 в 08:49. |
Этот пользователь сказал Спасибо M.A.D.M.A.N. за это полезное сообщение: | ||
shonty (25.08.2017)
|
#7
|
|||
|
|||
Угу, Мэд. С какой версии лямбда доступна?
А дженерики тут явно будут менее удобны, бо как разница как раз не в типах данных, а в самой формуле. Так что классическое решение с указателем на функцию в данном конкретном случае самое оптимальное. Как я уже писал, даже тот код, через мета класс, это явный overkill и просто был написан что бы вспомнить самому как с ними работать. |
#8
|
||||
|
||||
Цитата:
Дженерики для динамической типизации, в примере они лишние, но ТСу будет полезно знать про них. Почему я против указателей: использование анонимных методов делает код по структуре более логичным и более гибким (композиция функций, каррирование, замыкания), в виде некоего лаконичного решения, тебе как программисту не надо перетыркиватсья в кучу мест и смотреть где что объявлено и как (а еще перегрузка функций — злое зло). Использование указателей — это какое-то получистемное программирование получается, программист вместо того, чтоб решать проблему задачи — решает проблему языка программирования/компилятора, в этом нет ничего плохого, если будешь во всей этой херне ориентироваться и понимать что там и про что. Резюмируя вышеописанное: если инструмент программирования предоставляет инструментарий для решения задачи лаконично и понятно (и, уж тем более, быстро — время-деньги), то решать задачу используя устаревшие и/или достаточно сложные инструментарии я считаю моветоном. В общем, тут дело хозяйское, решайте задачу как хотите, целью моего поста было показать, что задачу можно решить несколько более элегантно и лаконично. — Как тебя понимать? — Понимать меня не обязательно. Обязательно меня любить и кормить вовремя. На Delphi, увы, больше не программирую. Рекомендуемая литература по программированию |
Этот пользователь сказал Спасибо M.A.D.M.A.N. за это полезное сообщение: | ||
shonty (27.08.2017)
|
#9
|
|||
|
|||
Цитата:
А указатель на функцию можно потом использовать для имплементации расширений в виде плагинов, собственно, только надо будет дописать загрузку функций из библиотек. Так что я бы сам в реальной задаче остановился бы, скорее всего, на первом способе, т.к. достаточно простой, при правильной струкрутизации кода проблем с поддержкой нет, и расширяемый в будущем. |