Calling Objective-C method from C++ member function? Calling Objective-C method from C++ member function? objective-c objective-c

Calling Objective-C method from C++ member function?


You can mix C++ with Objective-C if you do it carefully. There are a few caveats but generally speaking they can be mixed. If you want to keep them separate, you can set up a standard C wrapper function that gives the Objective-C object a usable C-style interface from non-Objective-C code (pick better names for your files, I have picked these names for verbosity):

MyObject-C-Interface.h

#ifndef __MYOBJECT_C_INTERFACE_H__#define __MYOBJECT_C_INTERFACE_H__// This is the C "trampoline" function that will be used// to invoke a specific Objective-C method FROM C++int MyObjectDoSomethingWith (void *myObjectInstance, void *parameter);#endif

MyObject.h

#import "MyObject-C-Interface.h"// An Objective-C class that needs to be accessed from C++@interface MyObject : NSObject{    int someVar;}// The Objective-C member function you want to call from C++- (int) doSomethingWith:(void *) aParameter;@end

MyObject.mm

#import "MyObject.h"@implementation MyObject// C "trampoline" function to invoke Objective-C methodint MyObjectDoSomethingWith (void *self, void *aParameter){    // Call the Objective-C method using Objective-C syntax    return [(id) self doSomethingWith:aParameter];}- (int) doSomethingWith:(void *) aParameter{    // The Objective-C function you wanted to call from C++.    // do work here..    return 21 ; // half of 42}@end

MyCPPClass.cpp

#include "MyCPPClass.h"#include "MyObject-C-Interface.h"int MyCPPClass::someMethod (void *objectiveCObject, void *aParameter){    // To invoke an Objective-C method from C++, use    // the C trampoline function    return MyObjectDoSomethingWith (objectiveCObject, aParameter);}

The wrapper function does not need to be in the same .m file as the Objective-C class, but the file that it does exist in needs to be compiled as Objective-C code. The header that declares the wrapper function needs to be included in both CPP and Objective-C code.

(NOTE: if the Objective-C implementation file is given the extension ".m" it will not link under Xcode. The ".mm" extension tells Xcode to expect a combination of Objective-C and C++, i.e., Objective-C++.)


You can implement the above in an Object-Orientented manner by using the PIMPL idiom. The implementation is only slightly different. In short, you place the wrapper functions (declared in "MyObject-C-Interface.h") inside a class with a (private) void pointer to an instance of MyClass.

MyObject-C-Interface.h (PIMPL)

#ifndef __MYOBJECT_C_INTERFACE_H__#define __MYOBJECT_C_INTERFACE_H__class MyClassImpl{public:    MyClassImpl ( void );    ~MyClassImpl( void );    void init( void );    int  doSomethingWith( void * aParameter );    void logMyMessage( char * aCStr );private:    void * self;};#endif

Notice the wrapper methods no longer require the void pointer to an instance of MyClass; it is now a private member of MyClassImpl. The init method is used to instantiate a MyClass instance;

MyObject.h (PIMPL)

#import "MyObject-C-Interface.h"@interface MyObject : NSObject{    int someVar;}- (int)  doSomethingWith:(void *) aParameter;- (void) logMyMessage:(char *) aCStr;@end

MyObject.mm (PIMPL)

#import "MyObject.h"@implementation MyObjectMyClassImpl::MyClassImpl( void )    : self( NULL ){   }MyClassImpl::~MyClassImpl( void ){    [(id)self dealloc];}void MyClassImpl::init( void ){        self = [[MyObject alloc] init];}int MyClassImpl::doSomethingWith( void *aParameter ){    return [(id)self doSomethingWith:aParameter];}void MyClassImpl::logMyMessage( char *aCStr ){    [(id)self doLogMessage:aCStr];}- (int) doSomethingWith:(void *) aParameter{    int result;    // ... some code to calculate the result    return result;}- (void) logMyMessage:(char *) aCStr{    NSLog( aCStr );}@end

Notice that MyClass is instantiated with a call to MyClassImpl::init. You could instantiate MyClass in MyClassImpl's constructor, but that generally isn't a good idea. The MyClass instance is destructed from MyClassImpl's destructor. As with the C-style implementation, the wrapper methods simply defer to the respective methods of MyClass.

MyCPPClass.h (PIMPL)

#ifndef __MYCPP_CLASS_H__#define __MYCPP_CLASS_H__class MyClassImpl;class MyCPPClass{    enum { cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42 };public:    MyCPPClass ( void );    ~MyCPPClass( void );    void init( void );    void doSomethingWithMyClass( void );private:    MyClassImpl * _impl;    int           _myValue;};#endif

MyCPPClass.cpp (PIMPL)

#include "MyCPPClass.h"#include "MyObject-C-Interface.h"MyCPPClass::MyCPPClass( void )    : _impl ( NULL ){   }void MyCPPClass::init( void ){    _impl = new MyClassImpl();}MyCPPClass::~MyCPPClass( void ){    if ( _impl ) { delete _impl; _impl = NULL; }}void MyCPPClass::doSomethingWithMyClass( void ){    int result = _impl->doSomethingWith( _myValue );    if ( result == cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING )    {        _impl->logMyMessage( "Hello, Arthur!" );    }    else    {        _impl->logMyMessage( "Don't worry." );    }}

You now access calls to MyClass through a private implementation of MyClassImpl. This approach can be advantageous if you were developing a portable application; you could simply swap out the implementation of MyClass with one specific to the other platform ... but honestly, whether this is a better implementation is more a matter of taste and needs.


You can compile your code as Objective-C++ - the simplest way is to rename your .cpp as .mm. It will then compile properly if you include EAGLView.h (you were getting so many errors because the C++ compiler didn't understand any of the Objective-C specific keywords), and you can (for the most part) mix Objective-C and C++ however you like.


The easiest solution is to simply tell Xcode to compile everything as Objective C++.

Set your project or target settings for Compile Sources As to Objective C++ and recompile.

Then you can use C++ or Objective C everywhere, for example:

void CPPObject::Function( ObjectiveCObject* context, NSView* view ){   [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)view.layer]}

This has the same affect as renaming all your source files from .cpp or .m to .mm.

There are two minor downsides to this: clang cannot analyse C++ source code; some relatively weird C code does not compile under C++.