Passing a C++ method to an Objective-C method
-
19-09-2019 - |
Question
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?
Solution
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;
}
OTHER TIPS
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.
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.
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.