【问题标题】:Can I mix Swift with C++? Like the Objective-C .mm files我可以将 Swift 与 C++ 混合使用吗?像 Objective-C 的 .mm 文件
【发布时间】:2014-07-25 10:02:35
【问题描述】:

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

【问题讨论】:

    标签: c++ objective-c swift


    【解决方案1】:

    一个(许多)技巧是

    你需要一个 separate 头文件来为你的桥接 obj-c++ 文件...

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

    所以在你的桥接头文件中有

    #import "Linkage.hpp"
    

    Linkage.hpp 具有 Linkage 的 @interface,Linkage.mm 具有 .mm 的 @implementation

    然后

    ...你实际上 #include "yourCpp.hpp" in Linkage.hpp。

    您只将#include "yourCpp.hpp" 放在 Linkage.mm 文件中,没有放在 Linkage.hpp 文件中。

    在许多在线示例/教程中,作者只是将@interface 和@implementation 放在同一个.mm 文件中,就像人们经常做的那样。

    这适用于非常简单的 cpp 桥接示例,但是,

    问题是:

    如果你的 yourCpp.hpp 有任何它肯定会的 c++ 特性(比如第一行 #include <something>),那么这个过程将会失败。

    但如果您只是没有在 Linkage header 文件中有 #include "yourCpp.hpp"(它是可以将它放在 .mm 文件中,显然你需要这样做)——它可以工作。

    不幸的是,这只是整个过程中的一个提示。

    【讨论】:

      【解决方案2】:

      其他答案略有不准确。实际上,您可以在同一个文件中混合使用 Swift 和 [Objective-]C[++],尽管这与您期望的不太一样。

      此文件 (c.swift) 编译为具有 swiftc c.swiftclang -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++。最好使用 示例恕我直言。
      【解决方案3】:

      混淆可能来自这样的假设,即只需将文件扩展名从 .m 更改为 .mm 即可桥接这些语言,而实际上,它并没有做任何此类事情。与.cpp 产生摩擦的不是.mm,而是.h 标头绝对不能是C++ 标头。


      同一个项目:是的。

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

      1. ...Bridging-Header.h:你使用这个桥将 CObjective-CObjective-C++ 暴露给 Swift李>
      2. &lt;ProductModuleName&gt;-Swift.h自动Objective-C 公开标有 @objcSwift
      3. .h:这是棘手的部分,因为它们被模糊地用于所有风格的 C++ 与否、Objective 与否.当.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++Assembly (@Vality)
      6. .h:无处不在且模棱两可的CC++Objective-CObjective-C++,所以答案这取决于。

      参考文献

      【讨论】:

      • 更正:在同一个 .m 源文件中,Objective-C 是严格的 C 超集,您可以混合使用 Objective-CC ...
      • 没问题,我什至不在乎功劳,只要答案是正确的;)顺便说一句,.mm 用于混合 Objective-C 和C++(C 和 C++ 是两个不同的东西,尽管名称不同)
      • 我要提一下,与目标 C 不同,C++ 不是 C 超集,因此您不能在 .cpp 文件中混合使用 C 和 C++。只有 C++ 和程序集。
      • 如果有人发现这个非常详细的答案在尝试将 Swift 文件公开到他们的 Objective-C/C++ 文件时并没有多大帮助(Xcode 抱怨找不到 Swift 头文件)。我发现我必须在我的 Objective-C/C++ 源文件中import "ProductName/ProductModuleName-Swift.h"。我发现这有点埋在:developer.apple.com/library/ios/documentation/Swift/Conceptual/…
      • 好点。对于混合这些语言的工作项目,请查看stackoverflow.com/a/32546879/218152
      【解决方案4】:

      我在官方资源中提供了指向SE-0038 的链接,描述为 这维护了对 Swift 编程语言的更改和用户可见增强的建议。

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

      此链接旨在引导任何寻找此功能的人朝着正确的方向前进

      【讨论】:

        【解决方案5】:

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

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

        "Using Swift with Cocoa and Objective-C" 也告诉我们:

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

        【讨论】:

        • 实际上很烦人 - 我们所有使用包含 C/C++ 代码库的 Cocoa 应用程序的人现在都必须维护用 3 种语言编写的项目......
        • 我认为 Objective-c++ 不是一门不同的语言,而是 c++ 和 Objective-c 的混合差异是微妙的,但它仍然存在
        • “nil”如何合法 C++ ?没有这样的东西(至少在标准c++中)请提供另一个例子
        • 但是使用 ObjC,您只需转到 .mm 您的文件并(几乎)完成。 Swift 并非如此。
        • @rewolf,我想他的意思是一个名为nil的变量,比如int nil
        【解决方案6】:

        如果这对任何人都有帮助,我还有一个简短的教程,关于从一个简单的 Swift 命令行实用程序调用一个简单的 C++ 静态库。这是一段非常简单的概念验证代码。

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

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

        【讨论】:

          【解决方案7】:

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

          以下示例返回一个指向 C++ 对象 (struct Foo) 的指针,因此 Swift 可以存储在 COpaquePointer 中,而不是在全局空间中定义 struct 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;
          }
          

          【讨论】:

          • 这个答案值得 方式 更多的支持。真的很有用。
          • 这是我第一次看到 extern "C" 将标头包装在包含的位置,而不是 #ifdef'ed 在标头文件本身中。太棒了!
          • 互联网上的每个人:“你必须为 c++ 类编写objective-c 包装器”。不,你不必。这是一个简单的技巧,可以在您的代码库中减少一种语言。
          【解决方案8】:

          不,不在单个文件中。

          但是,您可以在 Swift 项目中使用 C++,而无需静态库或框架。就像其他人所说的那样,关键是制作一个 Objective-C 桥接头标头,其中 #includes C 兼容的 C++ 标头标记为与 extern "C" {} 技巧兼容的 C。

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

          【讨论】:

            【解决方案9】:

            我还有一个快速结合opencv的演示程序。

            您可以从https://github.com/russj/swift_opencv3_demo下载。

            有关演示的更多信息http://flopalm.com/opencv-with-swift/

            【讨论】:

              【解决方案10】:

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

              https://github.com/sandym/swiftpp

              【讨论】:

                【解决方案11】:

                我编写了一个简单的 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头文件放在那里。

                请下载项目作为一个完整的例子。

                【讨论】:

                • 感谢这个吉安!
                • 感谢您提供此示例,但如果我想将 ObjCtoCPlusPlus.mm 中的 #import "CPlusPlus.h" 移动到 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 接口——它是桥梁,这是这里的必要组件。将包含保留在它们所在的位置,并在 ObjCtoCPlusPlus.… 文件中为您需要访问的每个 C++ 方法添加一个方法。你最好仔细阅读sourcemaking.com/design_patterns/adapter
                • 我下载了您的示例,该类提供的 STATIC 函数作为示例非常棒,但我无法调整示例以从外部使用额外的非静态函数。 . 也有可能吗? (几十年前我做过 C++ 作业……我现在不是盒子里最锋利的铅笔)
                【解决方案12】:

                我刚刚使用 Swift、Objective-C 和 C++ 制作了一个小示例项目。这是一个如何在 iOS 中使用 OpenCV 拼接的演示。 OpenCV API 是 C++,所以我们不能直接从 Swift 与它对话。我使用一个小的包装类,它的实现文件是 Objective-C++。 Header 文件是干净的 Objective-C 文件,因此 Swift 可以直接与之对话。您必须注意不要将任何 C++ 文件间接导入 Swift 与之交互的标头中。

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

                【讨论】:

                • 我认为这解决了我今天尝试在 Swift 中使用 3rd 方库 KudanCV 时遇到的问题。我的桥接头导入了他们的 .h 文件,其中包含对 的导入,我猜它们来自 C++ 库或文件,因此我的 Swift 代码将无法编译。如果有人能告诉我是否有办法解决这个问题,我将不胜感激......或者我是否必须在 Objective-C 中重写我的所有代码
                • @RocketGarden - KudanCV 头文件是 C++。您可以编写一个与我的示例包装器类工作方式相同的包装器。或者您重写应用程序中需要在 Objective-C++ 中与 KudanCV 对话的部分(带有 Objective-C 标头)。您无需重写项目中与 KudanCV 无关的部分。
                • 谢谢您,大约 5 分钟后我意识到了这一点,但将其记录在案给其他人很有用。
                【解决方案13】:

                Swift 与 C++ 不直接兼容。您可以通过使用 Objective-C 包装 C++ 代码并在 Swift 中使用 Objective C 包装器来解决此问题。

                【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多