2011-11-18 58 views
4

目前我正在研究cocos2d + Box2D项目,因此我已经处理了一些Objective-C++代码。声明包含C++类型ivar的obj-c类接口

而且我现在面临这样的局面:

#import "cocos2d.h" 
#import "Box2D.h" 

@interface BasicNode : CCNode { 
@private 
    ccColor3B _color; 
    b2Body *_body; 
    b2Fixture *_shape; 
} 

b2Body和b2Fixture是C,在Box2D.h

它的工作原理,如果BasicNode实施名为BasicNode.mm定义++类。

但是,如果我有一个使用BasicNode和进口BasicNode.h名为Game.m另一个文件,它不会编译,因为.m文件为对象 - 文件,不知道C++代码。

所以我决定搬到#进口“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++类类型作为对象 - 类特别是我使用ARC一个伟大的想法。

是否有更好的方法来处理它?我真的不希望做这样的事情

@interface BasicNode : CCNode { 
@private 
    ccColor3B _color; 
#ifdef __cplusplus 
    b2Body *_body; 
    b2Fixture *_shape; 
#else 
    void *_body; 
    void *_shape; 
#endif 
} 

编辑:也请告诉我,我会TWEAK方式引入任何问题?通过使C++类ivar看起来像其他纯粹Obj-C代码的Obj-C类。

回答

1

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

如果您需要支持旧版本的运行时,有几个方法可以做到这一点它比#ifdef ING更好。在我看来,最好的方法是使用C++中常见的'pimpl'成语 - 你在头部声明一个实现结构,并添加一个指向这样的结构的指针。在你的类的实现(.mm)中,你实际上是用它的所有C++成员定义了这个结构体。然后,您只需在方法中使用newdelete分配该实现对象,然后在dealloc中分配该实现对象。

我已经写了pimpl成语,因为它适用于干净地混合Objective-C和C++在this article - 它也显示了一些其他可能的解决方案,你可以考虑。

+0

看起来不错,除了C++类型成员没有更多合成属性。如果不引入新问题,我仍然更喜欢我的调整方式。 –

+0

您仍然可以合成PIMPL类型的属性。将指向C++对象的指针作为指向Obj-C类的指针看起来是个不错的主意,但只要您不使用ARC,您可能就没问题。 – pmdj

2

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

+0

是的,它会。我只需要记住将每个.m文件改为.mm文件。 –

+0

确切地说,一旦使用C++头文件,它可能会“传播”到其他类中,所以最好将.mm作为所有ObjC类的默认扩展名。 – LearnCocos2D

+1

请注意,包含C++头文件“无处不在”可能会减慢编译速度。取决于项目的规模,头文件的复杂性(STL,boost和类似的最差)以及计算机的速度。 – pmdj

0

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

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

struct b2Body; 
struct b2Fixture; 

你的界面之外编写,并

{ ... 
    struct b2Body* _body; 
    ... 
} 
在你的界面