Skip to content

Instantly share code, notes, and snippets.

@nevyn
Created April 8, 2010 21:58
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nevyn/360606 to your computer and use it in GitHub Desktop.
Save nevyn/360606 to your computer and use it in GitHub Desktop.
Transparent ObjC<>C++ bridge
/*
Say you have a largeish C++ class. You want to use it from ObjC. ObjC++ is painful;
C++ is painful. .mm files are bad. How about if we could just treat that C++
object as an ObjC object whenever it exits C++ land?
Apple already solved this problem once with toll free bridging. The tricky part is
vtables -- with a vtable, isa isn't at offset 0 of the memory layout of the object.
The code below is a work in progress to work around this.
*/
#import <Foundation/Foundation.h>
/////// ObjcObject.h ///////////
#include <objc/runtime.h>
class ObjcObject {
Class isa;
mutable size_t isa_offset;
public:
template<typename CPP> static size_t objcHeaderOffset(CPP* cpp) {
return (size_t)((char *)&((CPP*)cpp)->isa - (char*)cpp);
}
template<typename CPP, typename OBJC> static OBJC *objc(CPP *cpp) {
if(!cpp) return nil;
if(cpp->isa_offset == -1)
cpp->isa_offset = objcHeaderOffset<CPP>(cpp);
OBJC* o = (OBJC*)((char*)cpp + cpp->isa_offset);
return (OBJC*)o;
}
template<typename CPP, typename OBJC> static CPP *cpp(OBJC *objc) {
if(!objc) return NULL;
size_t offset = *(size_t*)((char*)objc + sizeof(Class));
return (CPP*)((char*)objc - offset);
}
protected:
ObjcObject(const char *objcname) : isa_offset(-1) {
isa = (Class)objc_getClass(objcname);
}
};
/////// Base ///////////
class Base {
public:
virtual int getB() = 0;
virtual void setB(int _) = 0;
};
/////// Foo ///////////
class Foo : public ObjcObject, public Base {
int a;
int b;
public:
Foo() : a(0), b(0), ObjcObject("ObjcFoo") {}
int getA() { return a; }
void setA(int _) { a = _; }
virtual int getB() { return b; }
virtual void setB(int _) { b = _; }
};
/////// ObjcFoo ///////////
@interface ObjcFoo : NSObject
@property (readonly) Foo *foo;
@end
@implementation ObjcFoo
-(Foo*)foo; { return ObjcObject::cpp<Foo, ObjcFoo>(self); }
-(int)a;
{
return self.foo->getA();
}
-(void)setA:(int)_;
{
self.foo->setA(_);
}
-(int)b;
{
return self.foo->getB();
}
-(void)setB:(int)_;
{
self.foo->setB(_);
}
@end
/////// main.mm ///////////
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Foo *foo = new Foo();
foo->setA(3);
foo->setB(6);
ObjcFoo *ofoo = ObjcObject::objc<Foo, ObjcFoo>(foo);
// insert code here...
NSLog(@"Hello, World! %d %d", [ofoo a], [ofoo b]);
[pool drain];
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment