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++.