views:

656

answers:

4

I have a C++ class 'Expression' with a method I'd like to use in my Objective-C class 'GraphVC'.

class Expression {
    double evaluate(double);
}

And my Objective-C class:

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

I thought that it would be easiest to pass around function pointers that take a double and return a double, as opposed to C++ objects, but I haven't had much success using functional.h. What's the best way to use my C++ method from Objective-C?

EDIT: Thanks for your quick responses. Allow me to elaborate a bit... I have a backend written in C++ where I manipulate objects of type Expression. There's subclasses for rational, polynomial, monomial, etc. My initial idea was to use mem_fun from , but I wasn't able to get code compiling this way. I also had trouble using bind1st to bind the this pointer.

  • Writing an Objective-C wrapper is a possibility, but I'd rather use the already existing evaluate() function, and I don't want to break the clean separation between the backend and the iPhone GUI classes.
  • I can't have a global expression or use a static method (I need to plot arbitrary Expression instances.

I should have more explicitly stated that I need to pass a C++ member function (not a static function or existing C function) to an Objective-C object. Has anyone had luck using C++'s <functional> to turn member functions into pointers I can use in an Objective-C object, or should I use an Objective-C wrapper?

A: 

If your C++ member function returns a double, can't your code just look like this?

- (void)plot:(double)f;

...

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

Or something similar. I've not used much mixing of Obj-C and C++, but this is how I would approach it. You also might have to have a .mm extension on your Objective-C++ file if you're mixing them like that.

jbrennan
I think he wants to pass a function to the `plot:` method, not a single value.
dreamlax
+1  A: 

I think the problem here is that you are trying to pass a member function of your Expression class to the Objective-C class. This will not work because it's expecting a this pointer as the first argument to that function (therefore the signature is not the same as the one expected by the plot: method.

If you make the C++ method a static, you can do this, but then you don't buy yourself a lot over using a standard C function.

IE, if the Expression class looked like this:

class Expression {
    static double evaluate(double);
}

You should be able to call it like this:

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

As I say though, there isn't a huge amount of value in this because you may as well be using a standard C function (unless you can do something in the C++ class that is more useful to you).

I did once look at trying to bridge boost::bind() results with objective-c methods but didn't get very far. I'm sure if you dig deep enough in the C++ runtime you could do it though.

jkp
+2  A: 

If you want to make a pointer to a method in C++, you need to include the class name, like this:

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;
}

Note that you need an instance of the class as well. In my example this is another parameter, though you could let it be a global variable, or a singleton instance of class Foo.

Though, like jkp said, you can also solve the problem by making the method static or turning it into a regular function.

EDIT: I'm not sure if I understand your question correctly. I don't think you need to use functional. Here is how my example would look in 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;
}
sarnesjo
+2  A: 

I would suggest wrapping the C++ class in an Objective-C class, and then also providing a

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

in addition to the plot: method.

Logan Capaldo