Recommended way to use C++ class into Objective-C class minimizing using of Objective-C++?
Asked Answered
Z

2

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.

Zurkow answered 27/3, 2011 at 10:50 Comment(0)
A
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.

Antiserum answered 27/3, 2011 at 10:56 Comment(1)
I cant wait for remaining 4 min to choose this as an answer!Zurkow
E
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.

Elevated answered 2/10, 2012 at 6:40 Comment(3)
Can you add a link the pmjordan's blog article ?Smaze
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.Elevated
This answer is incorporated into the first answer. I really thank @pmjordan for adopting my suggestion after I posted this answer.Elevated

© 2022 - 2024 — McMap. All rights reserved.