目前我正在开发一个cocos2d + Box2D项目,所以我处理了一些Objective-C ++代码。
我正面临这样的情况:
#import "cocos2d.h"
#import "Box2D.h"
@interface BasicNode : CCNode {
@private
ccColor3B _color;
b2Body *_body;
b2Fixture *_shape;
}
b2Body和b2Fixture是在Box2D.h中定义的C ++类
如果BasicNode的实现名为BasicNode.mm。
但是如果我有另一个名为Game.m的文件正在使用BasicNode并导入BasicNode.h,它将无法编译,因为.m文件是Obj-C文件,并且不知道C ++代码。
所以我决定将#import“Box2D.h”移动到实现文件中,并且只在头文件中保留类型声明(这正是头文件应包含的内容)。
但是我该怎么做?它们是C ++类类型,但它们实际上只是一个指针,所以我写了一些帮助宏
#ifdef __cplusplus
#define CLS_DEF(clsname) class clsname
#else
#define CLS_DEF(clsname) struct clsname; typedef struct clsname clsname
#endif
CLS_DEF(b2Body);
CLS_DEF(b2Fixture);
仅当CLS_DEF(b2Body)仅出现一次时才有效。否则编译器会找到同一个名称的多个类型声明,即使它们是相同的。比我必须改为
#ifdef __cplusplus
#define CLS_DEF(clsname) class clsname
#else
#define CLS_DEF(clsname) @class clsname
#endif
它现在正在运作。
但是我认为将C ++类类型声明为Obj-C类并不是一个好主意,尤其是我使用ARC。
有没有更好的方法来处理它?我真的不想做这样的事情
@interface BasicNode : CCNode {
@private
ccColor3B _color;
#ifdef __cplusplus
b2Body *_body;
b2Fixture *_shape;
#else
void *_body;
void *_shape;
#endif
}
编辑:还请告诉我,我的调整方式会引入任何问题吗?通过使C ++类ivar看起来像其他纯Obj-C代码的Obj-C类。
答案 0 :(得分:2)
一个简单的解决方案是将Game.m
重命名为Game.mm
。
答案 1 :(得分:1)
有两种方法。如果您可以依赖于使用Objective-C 2.2运行时的功能,则可以在类(类别)扩展中添加ivars。这意味着您可以在类的.mm文件中添加ivars,并保持.h文件清除任何C ++内容。
如果您需要支持旧版本的运行时,有几种方法可以比#ifdef
更好。在我看来,最好的方法是使用C ++中常见的'pimpl'习语 - 你在头文件中声明一个实现结构,并添加一个指向这种结构的指针的ivar。在类的实现(.mm)中,实际上是用它的所有C ++成员定义该结构。然后,您只需要在init...
方法中使用new
和delete
dealloc
分配该实施对象。
我已经编写了pimpl习惯用法,因为它适用于this article中干净地混合Objective-C和C ++ - 它还展示了一些其他可以考虑的潜在解决方案。
答案 2 :(得分:0)
使用Xcode 5,您不必在头文件中声明实例变量,只需在实现文件中声明它们即可。因此,您的BasicNode头文件不会被C ++“污染”。
您可以在C ++中使用“struct”而不是“class”。唯一的区别是,在类中,默认情况下所有成员都是私有的,而在结构中,默认情况下它们是公共的。但是你可以用一个可以用类做的结构来做任何事情。这样你可以写例如
struct b2Body;
struct b2Fixture;
在您的界面之外,
{ ...
struct b2Body* _body;
...
}
在您的界面中。