4

目前我正在做一个 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 类。

4

3 回答 3

2

一种简单的解决方案是重命名Game.mGame.mm.

于 2011-11-18T10:42:46.500 回答
1

有几种方法。如果您可以依赖使用 Objective-C 2.2 运行时的功能,您可以在类(类别)扩展中添加 ivars。这意味着您可以在类的 .mm 文件中添加 ivars,并保持 .h 文件中没有任何 C++ 内容。

如果您需要支持旧版本的运行时,有几种方法比#ifdefing 更好。在我看来,最好的方法是使用 C++ 中常见的 'pimpl' 习惯用法——你在头文件中声明一个实现结构,并添加一个指向这种结构的指针的 ivar。在您的类的实现 (.mm) 中,您实际上定义了该结构及其所有 C++ 成员。然后,您只需要在您的init...方法中分配该实现对象,newdeletedealloc.

我已经编写了 pimpl 成语,因为它适用于在本文中干净地混合 Objective-C 和 C++ - 它还显示了您可以考虑的一些其他潜在解决方案。

于 2011-11-18T11:21:44.377 回答
0

使用 Xcode 5,您不必在头文件中声明实例变量,只需在实现文件中声明它们即可。因此,您的 BasicNode 头文件不会被 C++“污染”。

您可以在 C++ 中使用“struct”而不是“class”。唯一的区别是,在一个类中,所有成员默认都是私有的,而在结构中,它们默认是公共的。但是你可以用一个结构来做任何你可以用一个类来做的事情。这样你就可以写例如

struct b2Body;
struct b2Fixture; 

在您的界面之外,以及

{ ...
    struct b2Body* _body;
  ...
}

在您的界面中。

于 2014-02-19T22:03:27.807 回答