5

I need to mix Objective-C and C++. I would like to hide all the C++ stuff inside one class and keep all the others plain Objective-C. The problem is that I want to have some C++ classes as instance variables. This means they have to be mentioned in the header file, which gets included by other classes and C++ starts spreading to the whole application. The best solution I was able to come with so far looks like this:

#ifdef __cplusplus
#import "cppheader.h"
#endif

@interface Foo : NSObject
{
    id regularObjectiveCProperty;
    #ifdef __cplusplus
    CPPClass cppStuff;
    #endif
}

@end

This works. The implementation file has an mm extension, so that it gets compiled as Objective-C mixed with C++, the #ifdef unlocks the C++ stuff and there we go. When some other, purely Objective-C class imports the header, the C++ stuff is hidden and the class does not see anything special. This looks like a hack, is there a better solution?

2
  • 1
    It's basically what I have come up with when I had the same problem. But pay attention to your ifdef: you have to insert padding for the non-cpp branch. Otherwise the compiler wouldn't know the size of your Foo objects. While this might not break on non-fragile instance var builds, it's definitely a problem for old style targets. Commented Jun 29, 2009 at 8:15
  • I copied the approach you outlined above. Seemed pretty nice and easy, but then it caused some crazy memory corruption problems: stackoverflow.com/questions/2458652/… Commented Mar 18, 2010 at 20:57

5 Answers 5

8

This sounds like a classic use for an interface/@protocol. Define an objective-c protocol for the API and then provide an implementation of that protocol using your Objective-C++ class. This way clients need only know about the protocol and not the header of the implementation. So given the original implementation

@interface Foo : NSObject
{
    id regularObjectiveCProperty;
    CPPClass cppStuff;

}

@end

I would define a protocol

//Extending the NSObject protocol gives the NSObject
// protocol methods. If not all implementations are
// descended from NSObject, skip this.
@protocol IFoo <NSObject>

// Foo methods here
@end

and modify the original Foo declaration to

@interface Foo : NSObject <IFoo>
{
    id regularObjectiveCProperty;
    CPPClass cppStuff;
}

@end

Client code can then work with type id<IFoo> and does not need to be compiled as Objective-C++. Obviously you can pass an instance of Foo to these clients.

Sign up to request clarification or add additional context in comments.

4 Comments

If the @interface Foo is in .h file, it that possible to preventing influencing of obj-c++? If the @interface Foo is in .mm file, how can I make an instance of it?
Any module that imports Foo.h will have to be compiled as Objective-C++, but client code need import only IFoo's header to use IFoo and can thus be Objective-C only. This is a classic dependency management pattern.
in your example, how would one instantiate a new Foo without importing the header? The first thing that comes to mind is an Objective C++ factory class that doesn't import and C++ stuff into its header. It all seems very complicated. There's also this approach: stackoverflow.com/questions/2262011/… but I haven't gotten it to work (see stackoverflow.com/questions/2463970/…)
@mrogancodes A factory class that imports only the IFoo header would be the obvious choice as you state. There's nothing stopping you from using the PIMPL pattern in your Objective-C++ class, making the header C++-free...
3

I also ran into this issue recently. In my case a protocol was overkill. I just needed to keep a pointer to a data access object that happened to be a C++ object.

What I did was declare the class with a void * instance variable and cast it when I use it in the instance methods.

This is a little bit hack-y, but conceptually, it's very similar to what the Objective-C id type is.

Comments

1

Is there some particular reason you cannot just use Objective C++ for everything? Simply switch the compiler to Compile Sources As: Objective C++ (or rename all your source files from .cpp or .m to .mm). Then you can freely intermix your C++ and Objective C.

C++ starts spreading to the whole application

What problem is there with that? If your Objective C code is doing only C/Objective C code in general, then it will almost certainly not be affected at all by being compiled as C++. There is no appreciable size or speed performance issues.

The only two downsides I've found are: you cannot (yet) use clang static analyser to analyseC++; some (relatively weird) C code wont work in C++, which is occasionally an issue when using third party C code.

1 Comment

The only problem is that I am not comfortable with C++ and I was afraid there are going to be some subtle differences that could lead to bugs. I like the idea of C++ being encapsulated only in the class that really needs it. But thank you, this certainly is a solution.
0

You might find that you have problems doing this -- from what I remember of ObjectiveC++ you may find that the constructor and the destructor for your enclosed C++ object won't get called.

Comments

0

DO NOT DO THIS

If you ifdef out an instance variable, that will give two separate instance variable layouts for this class. You will get random memory smashers all over the place because memory allocated for the object in half the cases will be too short. Instead of ifdefing out the instance variable, forward-declare its type like

struct CPPClass;

and have a pointer to it in the ivar, then in your init/dealloc methods call new/delete to create the object. If you have several objects, you can create a struct to hold all C++ ivars directly and then just new/delete that struct.

See this thread for more detail and further links to information, including a podcast that talks at length about ObjC++: Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link?

2 Comments

In C, a struct type would have to be referred to as struct CPPClass, not CPPClass, so they would have to change that too.
In the ivar declaration, yeah, good catch. To C++ struct Foo and Foo are the same though, so it's only needed in the header. Usually I just write struct in front of the class name everywhere I use it, you don't need a separate struct declaration like I mentioned here on its own.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.