我可以将Swift与C ++混合使用吗?类似于Objective-C .mm文件


131

我只是将.m文件更改为.mm并使用C ++。有没有办法用Swift做同样的事情?

Answers:


111

不。当您从.m切换到.mm时,您实际上是在从Objective-C切换到另一种称为Objective-C ++的语言。因此,您并不是真正在使用C ++。您使用的是Objective-C ++,它接受大多数C ++作为输入(与C ++接受大多数但不是全部C作为输入的方式相同)。当我说它不是完全C ++时,请考虑一个C ++文件,其中包含一个名为nil(合法C ++),然后尝试将其编译为Objective-C ++。

Swift没有相同的关系。它不是C或C ++的超集,并且您不能在.swift文件中直接使用它。

“将Swift与Cocoa和Objective-C结合使用”还告诉我们:

您不能将C ++代码直接导入Swift。而是为C ++代码创建一个Objective-C或C包装器。


93
烦实际-我们所有的人与Cocoa程序结合C / C ++代码库,现在要保持写在项目3种语言....
周杰伦

6
我建议Objective-c ++不是另一种语言,但是c ++和Objective-c的差异虽然很细微,但是仍然存在
2014年

1
“ nil”合法的C ++如何?没有这样的东西(至少在标准c ++中),请提供另一个示例
撤销2014年

3
但是,使用ObjC,您可以处理.mm文件并(几乎)完成。Swift并非如此。
chakrit

6
@rewolf,我认为他的意思是一个名为的变量nil,例如int nil
Luke

165

这种混乱可能来自于假设,即只改变从文件扩展名.m.mm是所有你需要弥合语言的时候,在现实中,它什么也不做那种。这不是.mm引起摩擦.cpp,这是.h必须积极地不是一个报头C++报头。


同一项目:是的。

同一项目中,您可以愉快地混合使用CC ++Objective-CObjective C ++Swift甚至Assembly

  1. ...Bridging-Header.h:使用此桥向Swift公开CObjective-CObjective-C ++
  2. <ProductModuleName>-Swift.h自动将标记为Objective-C的Swift类公开@objc
  3. .h:这是棘手的部分,因为它们是不明确地用于所有风味Ç++与否,目的或没有。当.h不包含单C ++关键字,如class,它可以被添加到...Bridging-Header.h,并且将暴露的任何起作用的对应.c .cpp它声明功能。否则,该标头必须包装在纯CObjective-C API中。

同一文件:否。

同一个文件中,您不能混合所有5个文件。在同一个源文件中

  1. .swift:您不能Swift与任何东西混合使用
  2. .m:您可以将Objective-CC混合使用。(@Vinzzz
  3. .mm:您可以将Objective-CC ++混合使用。该桥是Objective-C ++。(@Vinzzz)。
  4. .c:纯C
  5. .cpp:您可以混合使用C ++汇编语言@Vality
  6. .h:无处不在的CC ++Objective-CObjective-C ++,所以答案取决于它。

参考资料


1
更正:在相同的.m源文件,Objective-C的是一个严格C超集,可以混合使用的Objective-CC ^ ...
Vinzzz

1
没问题,只要答案是正确的,我什至不在乎;)BTW,.mm用于混合Objective-C和C ++(尽管名称如此,C和C ++是两个不同的东西) )
Vinzzz

1
我要提到的是,与目标C不同,C ++不是C的超集,因此您不能在.cpp文件中混合使用C和C ++。只有C ++和汇编语言。

1
万一有人发现尝试将Swift文件公开到他们的Objective-C / C ++文件中时,这个详尽的答案没有太大帮助(Xcode抱怨找不到Swift头文件)。我发现我必须在我的Objective-C / C ++源文件中导入“ ProductName / ProductModuleName-Swift.h”。我发现这个有点埋葬在:developer.apple.com/library/ios/documentation/Swift/Conceptual/...
AeroBuffalo

好点子。对于使用这些语言的工作项目,请查看stackoverflow.com/a/32546879/218152
SwiftArchitect

72

我写了一个简单的Xcode 6项目,展示了如何混合使用C ++,Objective C和Swift代码:

https://github.com/romitagl/shared/tree/master/C-ObjC-Swift/Performance_Console

特别是该示例从Swift调用了Objective C和C ++函数。

关键是创建一个共享头Project-Bridging-Header.h,然后在其中放置Objective C头。

请下载该项目作为完整示例。


感谢这个吉安!
杰森·艾尔伍德

谢谢您提供此示例,但如果我要将#import“ CPlusPlus.h”从ObjCtoCPlusPlus.mm移到ObjCtoCPlusPlus.h文件,则编译器将返回以下错误:<未知>:0:错误:无法导入桥接头' /Users/Ale/Downloads/shared-master/C-ObjC-Swift/Performance_Console/Performance_Console/Performance_Console-Bridging-Header.h',有可能将此导入移动到头文件中吗?
亚历山德罗·皮罗瓦诺

@API:不,您没有抓住重点。 ObjCtoCPlusPlus.h/''。mm`的唯一目的是为C ++代码提供Ob-C接口-它是桥梁,在这里是必不可少的组件。将include保留在原处,并在ObjCtoCPlusPlus.…文件中为您需要访问的每个C ++方法添加一个方法。您最好阅读sourcemaking.com/design_patterns/adapter
Slipp D. Thompson

我下载了您的示例,该类提供的STATIC函数作为示例非常棒,但是我无法设法将示例改编为可以从外部使用的其他非静态函数...也可以吗?(几十年前我做了C ++作业……我现在还不是盒子里最敏锐的铅笔)
Isaac

31

您也可以在两者之间跳过Objective-C文件。只需添加带有.cpp源文件的C头文件即可。头文件中仅包含C声明,并且源文件中包含任何C ++代码。然后,将C头文件包含在**-Bridging-Header.h中。

下面的示例返回一个指向C ++对象(结构Foo)的指针,因此Swift可以存储在COpaquePointer中,而不是在全局空间中定义结构Foo。

Foo.h文件(由Swift看到-包含在桥接文件中)

#ifndef FOO_H
#define FOO_H

// Strictly C code here.
// 'struct Foo' is opaque (the compiler has no info about it except that 
// it's a struct we store addresses (pointers) to it.
struct Foo* foo_create();
void foo_destroy(struct Foo* foo);

#endif

内部源文件Foo.cpp(Swift无法看到):

extern "C"
{
#include "Foo.h"
}
#include <vector>

using namespace std;

// C++ code is fine here. Can add methods, constructors, destructors, C++ data members, etc.
struct Foo
{
   vector<int> data;
};

struct Foo* foo_create()
{
   return new Foo;
}

void foo_destroy(struct Foo* foo)
{
    delete foo;
}

1
这个答案值得方式更多upvotes。真的很有用。
rsp1984 '16

这是我第一次看到extern "C"将标头包装在包含标头的位置,而不是#ifdef在标头文件本身中编辑。辉煌!
dcow

27

我刚刚使用Swift,Objective-C和C ++制作了一个小示例项目。这是有关如何在iOS中使用OpenCV缝合的演示。OpenCV API是C ++,因此我们无法直接通过Swift与之交谈。我使用一个小型包装器类,该包装器的实现文件是Objective-C ++。该文件是干净的Objective-C,所以雨燕进行直接通话这一点。您必须注意不要将任何C ++格式的文件间接导入到Swift与之交互的标头中。

该项目在这里:https : //github.com/foundry/OpenCVSwiftStitch


我认为这可以解决我今天尝试在Swift中使用第三方库KudanCV时遇到的问题。我的桥接标头导入了它们的.h文件,其中包含对<memory> <strings>和<vectors>的导入,我猜这些导入来自C ++库或文件,因此我的Swift代码无法编译。如果有人可以告诉我是否有解决方法,或者如果我必须重写Objective-C中的所有代码,我将不胜感激
Rocket Garden

1
@RocketGarden-KudanCV头文件是C ++。您可以编写一个与我的示例包装器类相同的包装器。或者,您可以用Objective-C ++(带有Objective-C标头)重写需要与KudanCV对话的应用程序部分。您无需重写项目中与KudanCV不相关的部分。
铸造厂

谢谢您,大约5分钟后我意识到了这一点,但将其记录下来对其他人很有用。
火箭花园

13

这是我尝试使用自动C ++ / swift通信的clang工具的尝试。您可以从swift实例化C ++类,从C ++类继承,甚至可以在swift中重写虚拟方法。
它将解析要导出的C ++类以快速生成自动生成的Objective-C / Objective-C ++桥。

https://github.com/sandym/swiftpp




4

不,不在单个文件中。

但是,您可以在Swift项目中使用C ++,而无需静态库或框架。就像其他人所说的那样,关键是要创建一个Objective-C桥接标头,该标头包含#个与C兼容的C ++标头,这些标头被标记为与外部“ C” {}技巧兼容的C ++标头。

视频教程:https//www.youtube.com/watch?v = 0x6JbiphNS4


2

其他答案略有错误。实际上,您可以将Swift和[Objective-] C [++]混合在同一个文件中,尽管并不是您期望的那样。

此文件(c.swift)编译为带有swiftc c.swift和的有效可执行文件clang -x objective-c c.swift

/* /* */
#if 0
// */
import Foundation
print("Hello from Swift!")
/* /* */
#endif
#include <stdio.h>
int main()
{
    puts("Hello from C!");
    return 0;
}
// */

您的示例代码是C而不是C ++。最好使用<iostream>示例恕我直言。
kakyo

2

(很多)诀窍是

您需要一个单独的标头来连接obj-c ++文件...

您不能像通常那样将@interface和@implementation放在同一.mm文件中。

因此,在桥接头文件中,

#import "Linkage.hpp"

Linkage.hpp具有@interface用于链接,而Linkage.mm具有@implementation用于.mm

然后

...您实际上并未在Linkage.hpp中#include“ yourCpp.hpp”。

您只放入#include "yourCpp.hpp"Linkage.mm文件,而不放在Linkage.hpp文件中。

在许多在线示例/教程中,作者经常像通常那样将@interface和@implementation放在同一.mm文件中。

这将在非常简单的cpp桥接示例中起作用,但是,

问题是:

如果yourCpp.hpp确实具有任何c ++功能(例如第一行#include <something>),则该过程将失败。

但如果你只是具备#include "yourCpp.hpp"的联动文件(它的优良有它在.mm文件,很明显你需要) -它的工作原理。

再次不幸的是,这只是整个过程中的一个技巧。


1

如果这对任何人都有帮助,我还将提供一个简短的教程,介绍如何从琐碎的Swift命令行实用程序调用简单的C ++静态库。这是概念代码的真正准系统证明。

不涉及Objective-C,仅涉及Swift和C ++。C ++包装器调用C ++库中的代码,该包装器实现具有外部“ C”链接的功能。然后,该函数在桥接头文件中引用,并从Swift调用。

参见http://www.swiftprogrammer.info/swift_call_cpp.html


1

我在官方资源中提供了指向SE-0038的链接,其描述为: 文档保留了有关Swift编程语言的更改和用户可见的增强的建议。

截至今天的状态是,这是已接受但尚未安排的功能请求。

该链接旨在引导任何人在正确的方向上寻找该功能

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.