Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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):</p> <h3>MyObject-C-Interface.h</h3> <pre><code>#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 </code></pre> <h3>MyObject.h</h3> <pre><code>#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 </code></pre> <h3>MyObject.mm</h3> <pre><code>#import "MyObject.h" @implementation MyObject // C "trampoline" function to invoke Objective-C method int 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 </code></pre> <h3>MyCPPClass.cpp</h3> <pre><code>#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); } </code></pre> <p>The wrapper function <strong><em>does not need</em></strong> to be in the same <code>.m</code> file as the Objective-C class, but the file that it does exist in <strong><em>needs to be compiled as Objective-C code</em></strong>. The header that declares the wrapper function needs to be included in both CPP and Objective-C code.</p> <p>(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++.)</p> <hr> <p>You can implement the above in an Object-Orientented manner by using the <a href="http://c2.com/cgi/wiki?PimplIdiom" rel="noreferrer">PIMPL idiom</a>. 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.</p> <h3>MyObject-C-Interface.h <em>(PIMPL)</em></h3> <pre><code>#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 </code></pre> <p>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;</p> <h3>MyObject.h <em>(PIMPL)</em></h3> <pre><code>#import "MyObject-C-Interface.h" @interface MyObject : NSObject { int someVar; } - (int) doSomethingWith:(void *) aParameter; - (void) logMyMessage:(char *) aCStr; @end </code></pre> <h3>MyObject.mm <em>(PIMPL)</em></h3> <pre><code>#import "MyObject.h" @implementation MyObject MyClassImpl::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 </code></pre> <p>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.</p> <h3>MyCPPClass.h <em>(PIMPL)</em></h3> <pre><code>#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 </code></pre> <h3>MyCPPClass.cpp <em>(PIMPL)</em></h3> <pre><code>#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-&gt;doSomethingWith( _myValue ); if ( result == cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING ) { _impl-&gt;logMyMessage( "Hello, Arthur!" ); } else { _impl-&gt;logMyMessage( "Don't worry." ); } } </code></pre> <p>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.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload