I'm mixing Objective-C (*.m) and Objective-C++ (*.mm) source files in an iOS project. When I import a C++ header file in a *.m file how can I exclude the C++-specific code 开发者_如何学编程in the header file? I want to use a compiler macro, something like:
// SomeClass.h - a file I want to import in C++ and Objectice-C classes
#if CPLUSPLUS
#import "CPlusPlusLibrary.h"
#endif
@interface SomeClass : BaseClass
{
#if CPLUSPLUS
CPlusPlusClass* variable;
#endif
}
@end
That would fail badly because an instance of SomeClass would have a different size and layout depending on whether it's compiled from a .m or a .mm file.
Here's what I would do (with added code to make it includable from .c and .cp as well):
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif
#ifdef __cplusplus
#include "CPlusPlusLibrary.h"
#endif
#ifdef __cplusplus
class CPlusPlusClass;
#else
typedef struct CPlusPlusClass CPlusPlusClass;
#endif
#ifdef __OBJC__
@class AnotherObjCClass;
@interface SomeObjCClass : NSObject
{
CPlusPlusClass* _variableCPP;
AnotherObjCClass* _variableObjC;
}
#else
typedef struct ObjC_AnotherObjCClass AnotherObjCClass;
typedef struct ObjC_SomeClass SomeObjCClass;
#endif
#ifdef __cplusplus
extern "C" { // Callable from C
#endif
void CFunctionTakingCPlusPlusClass(CPlusPlusClass* foo);
void CFunctionTakingSomeObjCClass(SomeObjCClass* foo);
#ifdef __cplusplus
}
#endif
Note that when compiling a .mm file, both __OBJC__ and __cplusplus are defined. #include and #import are roughly equivalent in Objective-C (a superset of C-99), but you must use #include for anything visible to C/C++.
Remember that in C, a struct foo*
with foo never defined (pointer to anonymous structure) is a perfectly valid type, so what this does is typedef "other language classes" as anonymous structs which you can pass around by pointer w/o looking at the contents.
I'll leave as an exercise how this interacts with ARC for ObjC instance variables. (There might be dragons and/or you may need __unsafe_unretained)
IIRC, if you use the same name for the struct as the C++ class, the debugger will show the right information if it has it available. I'm not sure if that's safe for Obj-C so I used a different name.
Also, try to avoid including the C++ header (just #include it in your .mm implementation file) unless you need it for types other than the anonymous class. Alternatively, you might create a wrapper header for it that looks like the top of this file.
HTH, -Steve
Objective-C++ is a viral thing that you can't really stop. Your current example gives different parts of your code (C and C++) a different view of the layout of your class, and while I do think it would still work, I'm pretty sure this isn't a very good thing.
When working on ObjC projects interacting with C++, I usually try to avoid having C++ references in my header files. This makes the header file valid for both Objective-C and Objective-C++. If I can't avoid it, then I don't try to fight it (it's a lost cause); but I try to not include that ObjC++ header file in otherwise 'sane' ObjC headers, and I use the @class
directive (@class SomeObjCPPClass;
instead of an #import "SomeObjCPPClass.h"
directive) instead if I need to reference the class. Then, I include the header from the implementation file, which has to be ObjC++, but at least it won't propagate from there.
EDIT Recent-ish (2012 and later) versions of Clang allow you to declare fields in the @implementation
side of things. This can effectively free your header of any references to C++ and make Objective-C++ much more manageable (and less viral). To retain OP's example, you would now have:
// SomeClass.h - a file I want to import in C++ and Objectice-C classes
@interface SomeClass : BaseClass
// (no fields)
// (methods)
@end
// SomeClass.mm
#import "CPlusPlusLibrary.h"
@implementation SomeClass
{
CPlusPlusClass* variable;
}
// (method implementations)
@end
This makes the SomeClass.h header safe to include in pure Objective-C files and Objective-C++ files as well.
There is a predefined macro that's defined when compiling as c++: __cplusplus
I'd guess the same is true for objective c++.
精彩评论