Wrapping C++ in Obj-C
So, guess it’s time for a short programming essay. I came across a C++ library these days, Crypto++, a very well-built library for cryptographic purposes. I needed a specific algorithm not implemented in Obj-C, so I wrote a quick wrap. Did some research and here’s what I have discovered.
Basically, you could choose to implement all the thing using Obj-C++, but that’s very messy and error-prone. Obj-C++ is very problematic and you should really stay away from it. The idea behind my wrapping technique is to keep the Obj-C and C++ files separated, and link them with an Obj-C++ file. Keeping the files separated and gluing them together with a third implementation works really well and keeps everything ordered.
We are also going to use opaque structs, since classes are basically structs in C++, so we can create an handy C++ object in Obj-C to handle all the calls, then release it when we are done. Ok, let’s get started.
Firstly, we need a CPP source files pair (header and implementation), in this example we are going to implement the AutoSeededRandomPool
from Crypto++.
CPPRandomPoolHeader.h
class RandomPool_CPP { public: int _generateRandomByte() { CryptoPP::AutoSeededRandomPool rng; return rng.GenerateByte(); } };
So far so good right? This only implements a method from the class, but it’s an example, however. I also packed all the code inside an header file, for brevity purposes. You should organize the code between an header and an implementation, that’s more readable and clean.
Now, we are going to write the actual Obj-C++ header and implementation, this will handle the C++ code and will be used by the Objective-C code.
OBJCPPRandomHeader.h
struct FRandomPool; @interface RandomPool : NSObject { struct FRandomPool *_randomPool; } /*! * Generates a random byte. * \returns The newly generated random byte. */ -(int) generateRandomByte; // generates a random byte @end
You can actually see that we are declaring the opaque struct here. The definition is there, but the implementation will be in the .mm file. We also declare a new ivar with the opaque struct. This will be the C++ handling object. Now, the Obj-C++ implementation:
OBJCPPRandomImplementation.mm
struct FRandomPool { RandomPool_CPP m1; }; @implementation RandomPool -(id) init { self = [super init]; if(self) { _randomPool = new FRandomPool; } return self; } -(int) generateRandomByte { return _randomPool->m1._generateRandomByte(); } @end
There you can see the actual struct body. It contains a RandomPool_CPP
pointer. So, to access low-level C++ functions we can simply use the ->
operator on the _randomPool
object and call the methods, as you can see in generateRandomByte
method. This is very handy, because all the memory management can be accomplished by handling that object.
Now, we can simply #import
this Obj-C++ header into any other Obj-C file and use it. There:
int main(int argc, const char * argv[]) { @autoreleasepool { RandomPool *rng = [[RandomPool alloc] init]; NSLog(@"0x%x", [rng generateRandomByte]); } return 0; }
And there you have it. C++ wrapped into Obj-C without messy source files. Last thing: if you are not using ARC, you can manually call dealloc
, to release the Obj-C++ instance. With ARC enabled the method is called automatically. The dealloc
should be also overrided to make it delete
the _randomPool
object and free the memory.
-(void) dealloc { delete _randomPool; }
Thanks for the time, hope I helped you out. Feel free to leave a comment if you have any doubt/suggestion/report.