Быстрый вопрос. Кто-нибудь знает, как получить указатель функции объектного метода c? Я могу объявить С++-метод как указатель функции, но это метод обратного вызова, так что метод С++ должен быть частью класса , ТАК, ЧТО ЭТО МОЖЕТ ДОСТУПИТЬ ИНСТРУМЕНТАЛЬНЫЕ ПОЛЯ. Я не знаю, как сделать часть метода С++ объектного класса c. Любые предложения?
Указатели функций в Objective C
Ответ 1
Как правило, вам нужно две части информации, чтобы перезвонить в Objective-C; метод, который нужно вызвать, и объект для его вызова. Ни один из селекторов или только IMP - результат instanceMethodForSelector:
- будет достаточно информации.
Большинство API обратного вызова предоставляют указатель контекста, который рассматривается как непрозрачное значение, которое передается обратному вызову. Это ключ к вашей загадке.
т.е. если у вас есть функция обратного вызова, которая объявляется как:
typedef void (*CallBackFuncType)(int something, char *else, void *context);
И некоторый API, который потребляет указатель указанного типа функции обратного вызова:
void APIThatWillCallBack(int f1, int f2, CallBackFuncType callback, void *context);
Затем вы выполнили бы свой обратный вызов примерно так:
void MyCallbackDude(int a, char *b, void *context) {
[((MyCallbackObjectClass*)context) myMethodThatTakesSomething: a else: b];
}
И тогда вы бы назвали API похожим на это:
MyCallbackObjectClass *callbackContext = [MyCallbackObjectClass new];
APIThatWillCallBack(17, 42, MyCallbackDude, (void*)callbackContext);
Если вам нужно переключаться между разными селекторами, я бы рекомендовал создать небольшой класс клея, который находится между обратным вызовом и API Objective-C. Экземпляр класса клея может содержать необходимую конфигурацию или логику, необходимую для переключения между селекторами на основе входящих данных обратного вызова.
Ответ 2
Вы можете сделать это с помощью @selector
и SEL
:
SEL sel = @selector(myMethod:);
/* Equivalent to [someObject myMethod:Paramater] */
[someObject performSelector:sel withObject:Parameter]
Существует также тип IMP
...
IMP imp = [someObject methodForSelector:sel];
/* don't remember if this syntax is correct; it been a while...
* the idea is that it like a function pointer. */
imp(someObject, sel, Parameter);
Обновление на основе ваших комментариев
Если вы не хотите указывать объект, в этом случае вы просите что-то ужасно не переносное. По сути, вам нужны лямбда-выражения, которые не являются признаком C, хотя он приходит в С++ 0x.
Итак, мое решение будет "там", отрывочным и не переносимым...
НО... возможно, вы можете сделать это с генерацией кода времени выполнения...
Вы можете начать с написания функции заглушки в сборке (если вы хотите x86)
push dword 0 ; SEL will go here
push dword 0 ; Object will go here
push dword 0 ; IMP will go here
pop eax ; eax = imp
call eax ; call imp
add esp, 8 ; cleanup stack
ret ; return
Эта команда собрана для:
0068 0000 6800 0000 0000 0068 0000 5800 d0ff c481 0004 0000 00c3
Обратите внимание, что инструкция push dword 0
- это байты 68 00 00 00 00
. Мы будем заполнять нули указателем во время выполнения.
Итак, мы можем скопировать это в буфер malloc()
'd, исправить его и вызвать mprotect()
, чтобы сделать его исполняемым.
Ниже приведен код для иллюстративных целей, и я понятия не имею, работает ли он.: -)
/* x86 code... */
char code[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0x68,
0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
0x00, 0x00, 0x00, 0x58, 0xff, 0xd0,
0x81, 0xc4, 0x04, 0x00, 0x00, 0x00,
0xc3 };
char *buf = malloc(sizeof(code));
SEL Selector = @selector(Method);
IMP Imp = [object methodForSelector:Selector];
/* Copy template */
memcpy(buf, code, sizeof(code));
/* Patch the "push dword 0" parts with your arguments
* This assumes everything is 32-bit, including SEL, IMP, etc. */
memcpy(buf + 1, &Selector, sizeof(Selector));
memcpy(buf + 6, &object, sizeof(object));
memcpy(buf + 11, &Imp, sizeof(Imp));
/* Now here comes the sketchy part...
* Make it executable and turn it into a function pointer. */
mprotect(buf, sizeof(code), PROT_EXEC);
void (*Function)() = (void(*)())buf;
/* Now, crazy as it sounds, you should be able to do: */
Function();
Возможно, вы захотите сделать [object retain]
до тех пор, пока эта функция существует, и [object release]
, когда и если вы должны ее освободить. (Вероятно, лучше всего обернуть эту sketcyness внутри объекта в любом случае, а затем использовать обычный objc refcounting для управления буфером и ссылкой на object
.) Возможно, вы также захотите использовать mmap()
для размещения вместо malloc()
..
Если это звучит излишне сложно, потому что это так.: -)
Ответ 3
Вы можете создать класс С++ в качестве обертки. И вызовите сообщение цели C из этого класса. Не забудьте сделать свой файл yoursource.mm вместо yoursource.cpp.
Ответ 4
Вы можете сделать это с помощью instanceMethodForSelector:
Подробнее... Документация NSObject.