Home > cocoa > Wrapping C++ in ObjC

Wrapping C++ in ObjC

April 14th, 2009 Leave a comment Go to comments

See Take 2 for an updated approach to this problem.

When faced with mixing C++ and ObjC code, there are two main approaches. One is to just work in Objective-C++ through the entire project. I don’t like this approach. I find the mixing of ObjC and C++ classes very confusing, since they cannot be used interchangeably and require completely different memory management. The mix of class hierarchies and naming conventions lead to a lot of confusion when we introduce people to code that does this kind of mixing.

My opinion is that ObjC and C++ have very different patterns, so it is important to pick one to be in charge and wrap the other. So if you basically have an C++ program than needs a little ObjC to talk to the UI, then wrap the ObjC in C++ objects. If you basically have an ObjC program that needs a C++ middleware, then wrap the C++ objects.

Here’s how I usually wrap a C++ object (CFoo) into a ObjC object (Foo):

Foo.h

typedef void* CFooRef;
@interface Foo : NSObject {
   CFooRef _fooRef;
}

Foo+CPP.h

#import "Foo.h"
@interface Foo (CPP)
@property (readwrite, assign) CFoo* foo;
@end

Foo.mm

#import "Foo+CPP.h"
@interface Foo () {
@property (readwrite, assign) CFooRef fooRef;
@end
 
class CFoo { ... }; // Define the C++ object here, or in a separate file.
 
@implementation Foo
@synthesize fooRef=_fooRef;
 
- (CFoo*)foo {
   return static_cast<cfoo*>([self fooRef]);
}
 
- (void)setFoo:(CFoo*)aFoo {
   [self setFooRef:aFoo];
}
@end

The goal of this is to provide a pure-ObjC interface (Foo.h) that has no C++ in it. The CFooRef type allows ObjC to treat the C++ object as an opaque type. Other C++ wrapper objects can access the underlying C++ object using the Foo+CPP.h interface, but I only provide this if there are other objects that really need it.

In general, I then provide ObjC methods to all the relevant C++ methods. This way, higher level classes (generally UI classes) can be pure ObjC. This makes it much easier to tie these C++ objects into Cocoa. I can use the wrapper to make the C++ bindings compliant, put them into NSArrays, etc. And when we hire ObjC developers, they can focus on ObjC without learning the intricacies of C++. Similarly, the C++ stays pure C++, making it much easier for C++ developers to work on, and keeps it portable. Only the guys who work on the wrappers (guys like me) have to really keep their head in both languages and both sets of patterns. And we keep the wrappers as thin as possible to minimize the work done there. Ideally, the wrappers can do simple language translation and nothing else.

After years of evolving this approach in multiple projects, this has been the most successful for our large mixed-language projects.

EDIT: After doing this for a long time, I’ve learned that using “#ifdef __cplusplus” in your header file around the C++ code can be much easier than maintaining a separate “+CPP” header.

Categories: cocoa Tags: , ,
  1. gf
    February 16th, 2010 at 19:11 | #1

    I’m curious, do you have any specific practical reason for not using opaque pointers? (as e.g. given here: http://stackoverflow.com/questions/2262011/adding-c-object-to-objective-c-class/2262395#2262395) I personally currently prefer that as it avoids casting and preserves type safety.

  2. February 17th, 2010 at 11:24 | #2

    I’m still investigating this style for use in my current project since we use this style extensively in our C wrappers around C++ objects. I haven’t been able to really show a strong benefit of it over the above (as long as you always use accessors, as I require in all my projects). In my C wrappers, it is often necessary to return a pointer to the opaque C++ object, so this is particularly useful. But in all the ObjC code I’ve dealt with so far, the C++ object never needs to be exposed. The above code has a single place the typecasting is done (in the accessor), so outside of that single place it is type-safe. Memory managing an indirect pointer doesn’t seem to give much benefit. And playing games like typecasting the C++ pointer to the struct pointer (which will work, since the offset of “cppobject” is 0) seems more hackish than the typecast. Have you seen a more extensive code example that shows the memory management of the struct pointer? I’m in the midst of revising this article with more details learned over the last year or two of doing this.

  3. gf
    February 20th, 2010 at 15:35 | #3

    I personally argue for the opaque pointer that it doesn’t require casts or function calls – you just use use e.g. “opaque->cppobj” directly. You just can’t do anything wrong there without the compiler shouting at you – any casts introduce a possibility of hard-to-trace bugs. The memory management doesn’t really differ except that now “opaque” is constructed and deleted and might need to get a constructor. The only down-side i can think of is the pointer-indirection in high-performance code – but that can get possibly optimized if there is a proven hot-spot there. Well, my 2 cents – i don’t assume i’ve found the holy grail there.

  4. gf
    February 20th, 2010 at 15:39 | #4
    gf :The only down-side i can think of is the pointer-indirection in high-performance code – but that can get possibly optimized if there is a proven hot-spot there

    Hm, but then the “void*”-pointer approach has also one indirection and it has another advantage – you can just put more members in the struct, without any visible change to the clients. So the only overhead i can possibly see is maybe padding of the struct.

  5. February 22nd, 2010 at 10:34 | #5

    You should never call “opaque->cppobj” directly. That access an ivar (opaque) outside of an accessor, which should be avoided whenever possible. There is no single rule that will avoid more heartache then sticking to accessors, and the caller shouldn’t need a special “oh, I use the ivar directly when it’s a C++ wrapper” rule. Special rules are the bane of code review. So in any case it’ll be “self.opaque->cppobj” which is no better than “self.cppobj,” while adding an additional malloc/free for the struct.

    To the point of putting other things in the struct, this is only significant if you ever hand back pointers to the struct to a caller, and you almost certainly shouldn’t be doing that anyway in ObjC. This makes sense in a C wrapper around C++ (like Core Foundation, and I use this pattern elsewhere), but I still don’t see a benefit in ObjC.

    Do you have any example code that shows how to do this well without bypassing accessors on the ivars? I think the resulting code is less space efficient, more complicated and gives no greater type safety.

  6. gf
    February 23rd, 2010 at 04:10 | #6

    @Rob Napier Thanks for the heartache point, that might be a good one (i’ve currently mainly done rather flat Obj-C bridging). But there is no additional malloc/free/new/delete – its still one as you don’t need to hold a pointer to the object in the opaque struct.

    I think we have a misunderstanding though, i didn’t intend to hand the opaque pointer aound, its just for Pimpl.

    Putting other things in there is not only relevant if you pass the pointer – what if you need to additional (helper/secondary) C++ objects to deal with the main object?

  7. February 23rd, 2010 at 13:44 | #7

    I’m not clear how you’re allocating the object for the struct if it has a non-trival constructor (i.e. you need to pass parameters). Can you show an example of this model? As far as helper C++ objects, I have them all the time (mostly listeners), but I don’t see what that has to do with a struct. They don’t need to be passed around as some kind of bundle; I just have multiple pointers in my ObjC class. Again, maybe this would be clearer with some example code of using the opaque pointer.

  8. gf
    May 7th, 2010 at 12:00 | #8

    I somehow forgot about this discussion, sorry about that. Snippet here: http://pastebin.org/207012

    For me it has the major advantage that through the wrapping opaque struct i’m in a clean C++-world again regarding object storage.

  9. May 8th, 2010 at 12:56 | #9

    OK, now I’m seeing it. The key is the use of C++’s ambiguity between structs and classes. By adding a “constructor” to your struct, you got the benefits of a C++ object while allowing it to be defined in the header. No casting at all, and fewer raw pointers to C++ objects. I should be able to wrap shared_ptr<> in there easily as well (which is coming up more often in my code, and has been a bit of a pain). I like this. I’ve got a dozen or so ObjC/C++ wrapper classes to write this month, so I’ll give this a try and see if it’s as handy as it looks. Thanks.

  10. Jacob
    June 8th, 2010 at 05:01 | #10

    Hi,

    Any chance of reposting “http://pastebin.org/207012″? or providing an equivalent example of the non-trivial constructor here?

    Thanks

  11. June 9th, 2010 at 02:44 | #11

    @Jacob, see my update. I’ve posted a simple example of this. I’ll post a more complex example (including smart pointers, and more) shortly.

  1. January 28th, 2010 at 14:13 | #1
  2. June 9th, 2010 at 02:43 | #2
  3. January 14th, 2011 at 15:38 | #3