7

I'm mixing Objective-C and C++. However I want to minimize using of Objective-C++. Because it has some kind of limits in both of Objective-C and C++.

Currently, I'm using it like this.

// A.h, Objective-C
#import "B.h"
@interface A
{
    B* b;
}
@end

// B.h, Objective-C++
@interface B
{
    void* c;
}

// C.h, C++
class C
{
};

I want to include C.h in B.h, but if I did it, B.h cannot be imported into A.h. So I have to leave variable c as void* type. This is not a big problem because I can use members of C in B.m file freely. But I always have to cast it. This feels something unclear. So I want to use better way if it is.

eonil
  • 83,476
  • 81
  • 317
  • 516

2 Answers2

15

There are a couple of ways of doing this, but in my opinion the best method is to use the 'PIMPL' idiom, which is fairly common in C++. Make the headers pure Objective-C and pure C++, with pointers to a forward-declared struct containing the actual implementation. This is defined in the .mm file, and can then use Objective-C++.

In your example, you would do something like this:

// B.h, pure Objective-C:
struct BImpl;
@interface B
{
    struct BImpl* impl;
}
// ...


// B.mm, mixed:
#include "C.h"
struct BImpl // since this is C++, it can actually have constructors/destructors
{
    C* my_c;
    BImpl() : my_c(new C) {}
    ~BImpl() { delete my_c; my_c = NULL; }
};
// make sure to alloc/initialise impl (using new) in B's init* methods,
// and free it (using delete) in the dealloc method.

I've actually written an article on solving exactly this problem, you might find it useful: http://philjordan.eu/article/strategies-for-using-c++-in-objective-c-projects - it also shows some other ways of doing it, including your original void* approach.

pmdj
  • 22,018
  • 3
  • 52
  • 103
4

As pmjordan wrote in his blog article, BImpl within @interface declaration needs 'struct' keyword as follows.

struct BImpl;
@interface B
{
    struct BImpl* impl;
}

I think he inadvertently left this out. In case you need to include this header when you have a lot of *.m files, this makes a huge difference. The added 'struct' keyword causes Objective-C compiler to understand this header as pure C for other .m files which import this header. Otherwise other *.m files which import this header won't be compiled. This small solution saves you from changing the *.m files to .mm files. Sometimes, changing original .m files to .mm causes a lot of compile errors.

DuncanSungWKim
  • 3,774
  • 1
  • 14
  • 11
  • Can you add a link the pmjordan's blog article ? – Stephan Oct 02 '12 at 08:00
  • Yes, I did. In fact, pmjordan is the author of the first answer to this question. I got the link from the original answer. You can also use the original link in his answer. – DuncanSungWKim Oct 02 '12 at 08:20
  • 1
    This answer is incorporated into the first answer. I really thank @pmjordan for adopting my suggestion after I posted this answer. – DuncanSungWKim Oct 03 '12 at 05:24