Передача метода C++ в метод Objective-C

У меня есть класс C++ 'Expression' с методом, который я хотел бы использовать в своем классе Objective-C 'GraphVC'.

class Expression {
    double evaluate(double);
}

И мой класс Objective-C:

@implementation GraphVC : UIViewController {
- (void)plot:(double(*)(double))f;
@end

Я думал, что проще всего будет обойти указатели функций, которые принимают значение типа double и возвращают значение типа double, в отличие от объектов C++, но я не добился большого успеха, используя functional.h. Как лучше всего использовать мой метод С++ из Objective-C?

РЕДАКТИРОВАТЬ: Спасибо за ваши быстрые ответы. Позвольте мне немного уточнить... У меня есть бэкенд, написанный на C++, где я манипулирую объектами типа Expression. Существуют подклассы для рациональных, полиномиальных, мономиальных и т. д. Моя первоначальная идея состояла в том, чтобы использовать mem_fun from , но мне не удалось компилировать код таким образом. У меня также были проблемы с использованием bind1st для привязки указателя this.

  • Написание оболочки Objective-C возможно, но я бы предпочел использовать уже существующую функцию evaluate() и не хочу нарушать четкое разделение между серверной частью и классами графического интерфейса iPhone.
  • Я не могу иметь глобальное выражение или использовать статический метод (мне нужно построить произвольные экземпляры Expression.

Я должен был более явно указать, что мне нужно передать функцию-член C++ (не статическую функцию или существующую функцию C) объекту Objective-C. Удалось ли кому-нибудь использовать <functional> С++ для превращения функций-членов в указатели, которые я могу использовать в объекте Objective-C, или мне следует использовать оболочку Objective-C?


person Robert Karl    schedule 27.07.2009    source источник


Ответы (5)


Если вы хотите сделать указатель на метод в C++, вам нужно включить имя класса, например:

class Foo
{
  public:
    double bar(double d)
    {
      return d;
    }
};

void call_using_obj_and_method(Foo *f, double (Foo::*m)(double d))
{
  (f->*m)(3.0);
}

int main()
{
  Foo f;
  call_using_obj_and_method(&f, &Foo::bar);
  return 0;
}

Обратите внимание, что вам также нужен экземпляр класса. В моем примере это еще один параметр, хотя вы можете сделать его глобальной переменной или одноэлементным экземпляром класса Foo.

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

EDIT: я не уверен, правильно ли я понял ваш вопрос. Я не думаю, что вам нужно использовать функционал. Вот как мой пример будет выглядеть в Objective-C++:

#include <Cocoa/Cocoa.h>

class Foo
{
  public:
    double bar(double d)
    {
      return d;
    }
};

typedef double (Foo::*fooMethodPtr)(double d);

@interface Baz : NSObject
{
}
- (void)callFooObj:(Foo *)f method:(fooMethodPtr)m;
@end

@implementation Baz
- (void)callFooObj:(Foo *)f method:(fooMethodPtr)m
{
  (f->*m)(3.0);
}
@end

int main()
{
  Foo f;
  Baz *b = [[Baz alloc] init];
  [b callFooObj:&f method:&Foo::bar];
  return 0;
}
person sarnesjo    schedule 27.07.2009

Я бы предложил обернуть класс C++ в класс Objective-C, а затем также предоставить

- (void) plotWithObject:(id)obj
{
   double result = [obj evaluate: 1.5];
   // ... etc ...
}

в дополнение к сюжету: метод.

person Logan Capaldo    schedule 27.07.2009

Я думаю, что проблема здесь в том, что вы пытаетесь передать функцию-член вашего класса Expression классу Objective-C. Это не сработает, потому что он ожидает указатель this в качестве первого аргумента этой функции (поэтому сигнатура не совпадает с той, которую ожидает метод plot:.

Если вы сделаете метод C++ статическим, вы сможете сделать это, но тогда вы не сильно купитесь на использование стандартной функции C.

IE, если бы класс Expression выглядел так:

class Expression {
    static double evaluate(double);
}

Вы должны иметь возможность называть это так:

[self plot:myExpression.evaluate(&Express::evalulate)];

Однако, как я уже сказал, в этом нет большой ценности, потому что вы можете также использовать стандартную функцию C (если вы не можете сделать что-то в классе C++, что более полезно для вас).

Однажды я пытался соединить результаты boost::bind() с методами Objective-C, но не продвинулся очень далеко. Я уверен, что если вы достаточно глубоко покопаетесь в среде выполнения C++, вы сможете это сделать.

person jkp    schedule 27.07.2009

Если ваша функция-член C++ возвращает значение типа double, разве ваш код не может выглядеть так?

- (void)plot:(double)f;

...

[self plot:myExpression.evaluate(aDouble)];

Или что-то подобное. Я не использовал много смешивания Obj-C и C++, но я бы подошел к этому так. Вам также может понадобиться расширение .mm в файле Objective-C++, если вы смешиваете их таким образом.

person jbrennan    schedule 27.07.2009
comment
Я думаю, он хочет передать методу plot: функцию, а не одно значение. - person dreamlax; 27.07.2009

Почему бы вам не передать экземпляр класса С++ внутри NSValue, а затем напрямую вызвать метод С++?

- (NSValue*)getExpression
{
    Expression* e = new Expression();
    return [[NSValue alloc] initWithPointer:e];
}

- (void)callExpression(NSValue*)expression
{
    Expression* e = [expression pointerValue];
    e->evaluate();
}
person silicontrip    schedule 17.01.2021