混合使用Objective-C和C++

44

我正在尝试将Objective-C与C ++混合使用。编译代码时,出现了多个错误。

A.h

#import <Cocoa/Cocoa.h>
#include "B.h"

@interface A : NSView {
    B *b;
}

-(void) setB: (B *) theB;

@end

A.m

#import "A.h"

@implementation A

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
    }
    return self;
}

- (void)drawRect:(NSRect)dirtyRect {
    // Drawing code here.
}

-(void) setB: (B *) theB {
    b = theB;
}

@end

B.h

#include <iostream>

class B {

    B() {
        std::cout << "Hello from C++";
    }

};

以下是错误信息:

/Users/helixed/Desktop/Example/B.h:1:0 /Users/helixed/Desktop/Example/B.h:1:20: error: iostream: No such file or directory
/Users/helixed/Desktop/Example/B.h:3:0 /Users/helixed/Desktop/Example/B.h:3: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'B'
/Users/helixed/Desktop/Example/A.h:5:0 /Users/helixed/Desktop/Example/A.h:5: error: expected specifier-qualifier-list before 'B'
/Users/helixed/Desktop/Example/A.h:8:0 /Users/helixed/Desktop/Example/A.h:8: error: expected ')' before 'B'
/Users/helixed/Desktop/Example/A.m:26:0 /Users/helixed/Desktop/Example/A.m:26: error: expected ')' before 'B'
/Users/helixed/Desktop/Example/A.m:27:0 /Users/helixed/Desktop/Example/A.m:27: error: 'b' undeclared (first use in this function)

2
不要忘记,如果您在头文件中放置C++包含文件,则会强制ObjC类的用户使用ObjC++ - 使用不透明指针来避免这种情况。 - Georg Fritzsche
@gf 那您建议我怎么做呢?我应该只使用一个空指针,还是可以使用id类型? - LandonSchropp
1
为了避免失去类型安全,我个人更喜欢前向声明的结构体(https://dev59.com/73E95IYBdhLWcg3wkegf#2262395),但我也见过使用“私有”ObjC类的情况(例如通过`id`实例变量)。 - Georg Fritzsche
5个回答

80

您需要将.m文件更名为.mm。这样,您就可以使用Objective-C编译C++代码。

因此,根据您的示例,您的AView.m文件应该命名为AView.mm。就是这么简单。它非常有效。我在iPhone项目中使用了许多std容器(如std::vector、std::queue等)和旧的C++代码,没有任何复杂性。


如果我将.m文件重命名为.mm,由于其他类将报告错误,如果我使用.mm扩展名,那么该怎么办?还有其他解决方案吗? - Scar

5

没关系,我感觉很蠢。你只需要将AView.m重命名为AView.mm,这样编译器就知道它是Objective-C++,就可以顺利编译了。


2
我很高兴它如此简单,因为现在我可以将你的代码作为尝试这个东西的模板! - Teekin
1
有另一种方法可以做到这一点——在文件属性窗口中(忘记它的名称了——当在导航器中单击文件时,右侧的窗口),您可以设置文件的类型,而不受其文件扩展名的影响。 - Hot Licks

2

您可以通过C++类的前向声明使界面更加清晰:

#import <AnObjCclass.h>
class DBManager; // This is a C++ class. NOTE: not @class

@interface AppDelegate : UIResponder <UIApplicationDelegate,
                                    CLLocationManagerDelegate,
                                    MFMailComposeViewControllerDelegate>
{
    DBManager* db;
...
}

4
这并没有回答问题,它涉及代码风格,与问题中报告的编译器错误无关。这应该是一条评论。 - Kristopher Johnson

1
我分享了一些我在这个话题上理解的要点。
我们可以使用纯C接口混合.cpp和.m文件。正如我们所知,Clang编译器将支持C ++、Objective C以及Objective C ++,这可能是混合这些语言的更好方法。
混合这些语言时需要注意一件事情就是使用头文件。我们可以通过在类扩展中声明Cpp对象来避免将C++放入Objective C头文件中。
或者,在我们的Objective Cpp(.mm)文件的@implementation块的开头声明cpp对象。
当我们处理Cpp对象时,管理内存将是一个问题。我们可以使用“new”为对象分配内存,并通过调用“delete object”来释放内存。通常,如果我们使用ARC,就不需要关心释放对象的内存。
在使用cpp类时,我们可以通过两种方式声明Cpp对象,即CppWrapper wrapper和CppWrapper *wrapper,其中CppWrapper是一个Cpp类。当我们使用后者时,程序员负责管理内存。
另一个主要的问题是,在调用带参数的Objective C方法时,我们传递的是引用,而在Cpp中,我们需要使用'&'关键字通过引用传递参数,否则对象的副本将被传递。
Objective C对象的释放是在运行时处理的,当对Cpp对象调用'delete'时,它将不再驻留在内存中。
在编写Cpp时,我们有共享指针和弱指针,类似于Objective C中的强指针和弱指针。

http://philjordan.eu/article/mixing-objective-c-c++-and-objective-c++ http://www.raywenderlich.com/62989/introduction-c-ios-developers-part-1


0
在你想要引入一个像 std::cout << 这样的简单 C++ 函数的情况下,Hot Licks 提供了一个很好的替代方案。
将 "Identity and Type" 从 Objective-C source 更改为 Objective-C++ source .mm 扩展名只是标识文件类型;然后你需要寻找的是 Objective-C++ 而不是 Objective-C 类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接