Вызов целевого метода c с использованием указателя функции из метода c++

У меня есть класс С++, которому нужно вызвать объектный метод c, используя указатель на этот метод. Этот метод возвращает значение void и принимает аргумент типа «статус», где статус — это простое целочисленное перечисление.

 enum status
 {
       status_valid = 0,
       status_invalid,
       status_unknown
 };

У меня есть указатель на метод obj-c, настроенный следующим образом. Указатель на метод также передается классу c++ и

typedef void (*FuncPtr) (status);
FuncPtr myObjCSelectorPointer = (void (*)(status))[self methodForSelector:@selector(statusChanged: )];
cppClassInstance->setFuncPointer(myObjCSelectorPointer)

myObjCSelectorPointer удерживается cppClass следующим образом:

void cppClass::setFuncPointer(FunctPtr *ptr)
{
     this->funcPtr = ptr;
}

Теперь где-то еще, когда я пытаюсь вызвать метод, на который указывает этот указатель, вот так:

status s;
funcPtr(s);

Метод вызывается правильно, но значение, переданное в метод, теряется. Метод obj-c получает совершенно случайное значение. Когда я пытаюсь вызвать метод в классе cpp таким же образом, он проходит и получает правильное значение.

Что я делаю неправильно? Вы не можете вызвать объектный метод c таким образом?


person halfwaythru    schedule 14.05.2013    source источник
comment
Опубликуйте определение статуса, я предполагаю, но попробуйте передать статус по ссылке   -  person makc    schedule 14.05.2013
comment
Я добавил определение статуса в сообщение. Кроме того, я пытался передать его по ссылке, но это тоже не сработало. У меня тоже была такая же проблема с этим.   -  person halfwaythru    schedule 14.05.2013
comment
@halfwaythru Ваш прототип функции неверен - смотрите мой ответ.   -  person    schedule 14.05.2013


Ответы (1)


Проблема в том, что сигнатура функций методов Objective-C не так проста, как вы думаете.

Чтобы сделать объектно-ориентированное программирование возможным, методы Objective-C принимают два неявных аргумента: id self, SEL _cmd, вызывающий объект и отправленный селектор — их необходимо передать. Вам нужно будет получить объект для вызова метода, и вы также должны сохранить селектор. Затем измените определение типа функции на правильное:

typedef void (*FuncPtr) (id, SEL, status);

Для прочтения: [1], [2] (возле части typedef id (*IMP)(id, SEL, ...))

person Community    schedule 14.05.2013
comment
Звучит полезно, но есть две вещи: 1.) Если прототип функции неверен, то не должно ли это приводить к тому, что функция не вызывается? Мой метод obj-c вызывается очень хорошо с этим прототипом. 2.) Когда я пытаюсь изменить прототип функции ptr, мне нужно включить его в заголовок C++, где «id» — это необъявленный идентификатор. Как мне это обойти? - person halfwaythru; 14.05.2013
comment
@halfwaythru 1. Почему это должно приводить к тому, что функция не вызывается? Инструкция CALL выдается компилятором просто отлично... 2. Скомпилируйте как Objective-C++. - person ; 14.05.2013
comment
@halfwaythru 1) нет. он все равно будет вызываться, и это может привести к неопределенному поведению. 2) среда выполнения objc - это C -- #include <objc/objc.h> или, как сказал H2CO3 моментом ранее, вы также можете скомпилировать его как objc++. - person justin; 14.05.2013
comment
@justin (и я даже не упомянул случай функций fpret и stret, где соглашение о вызовах снова что-то другое... Я ‹3 несоответствия...) - person ; 14.05.2013
comment
@H2CO3 да. лично я бы просто скомпилировал этот файл как objc++ и позволил компилятору сделать всю работу за меня. - person justin; 14.05.2013
comment
Поэтому я сделал небольшую структуру с объектом, селектором и указателем и передал ее классу cpp вместо одного указателя. И это прекрасно работает! Спасибо.! - person halfwaythru; 14.05.2013
comment
@halfwaythru Добро пожаловать - обязательно изучите среду выполнения Objective-C, это будет очень полезно. - person ; 14.05.2013
comment
Еще одна вещь, хотя мой файл cpp уже .mm. Это заголовочный файл для класса cpp, который не распознает идентификатор. Как скомпилировать конкретный заголовочный файл как Objective-C++? Кроме того, мои файлы являются частью гораздо более крупного проекта, в котором уже есть много смешанного кода objc/cpp. - person halfwaythru; 14.05.2013
comment
@halfwaythru Вы всегда можете передать компилятору флаг -x obj-c++ для явной компиляции как Objective-C++. Этот аргумент работает как для GCC, так и для Clang. - person ; 14.05.2013
comment
Большое спасибо! Я очень ценю это! - person halfwaythru; 14.05.2013
comment
@halfwaythru: файлы заголовков не компилируются. Исходные файлы компилируются и могут включать заголовочные файлы. Если в вашем заголовочном файле есть материал C++, то ВСЕ исходные файлы, включающие его, также должны быть исходными файлами Objective-C++. Вот почему вы должны максимально избегать C++ в файлах заголовков. - person newacct; 15.05.2013