Tôi có thể kết hợp Swift với C ++ không? Giống như các tệp Objective-C .mm


131

Tôi chỉ thay đổi các tập tin .m của tôi thành .mm và sử dụng C ++. Có cách nào để làm điều tương tự với Swift không?

Câu trả lời:


111

Không. Khi bạn chuyển từ .m sang .mm, bạn thực sự đang chuyển từ Objective-C sang một ngôn ngữ khác (có nhiều khác biệt tinh tế) được gọi là Objective-C ++. Vì vậy, bạn không thực sự sử dụng C ++; bạn đang sử dụng Objective-C ++, nơi chấp nhận hầu hết C ++ làm đầu vào (giống như cách mà C ++ chấp nhận hầu hết nhưng không phải tất cả C là đầu vào). Khi tôi nói nó không hoàn toàn là C ++, hãy xem xét một tệp C ++ bao gồm một biến có tên nil(đó là C ++ hợp pháp) và sau đó thử biên dịch nó thành Objective-C ++.

Swift không có cùng mối quan hệ. Nó không phải là siêu dữ liệu của C hoặc C ++ và bạn không thể sử dụng trực tiếp trong một .swifttệp.

"Sử dụng Swift với Ca cao và Mục tiêu-C" cũng cho chúng ta biết:

Bạn không thể nhập mã C ++ trực tiếp vào Swift. Thay vào đó, hãy tạo một trình bao bọc Objective-C hoặc C cho mã C ++.


93
Thực sự khá khó chịu - tất cả chúng ta với các ứng dụng Cacao kết hợp các cơ sở mã C / C ++ giờ phải duy trì các dự án được viết bằng 3 ngôn ngữ ....
Jay

6
Tôi đề nghị rằng Objective-c ++ không phải là một ngôn ngữ khác mà là sự pha trộn giữa sự khác biệt của c ++ và Objective-c là tinh tế nhưng nó vẫn ở đó
amar

1
C ++ "hợp pháp" như thế nào? Không có điều đó (ít nhất là trong tiêu chuẩn c ++) Vui lòng cung cấp một ví dụ khác
tua lại

3
Nhưng với ObjC, bạn có thể truy cập .mmcác tệp của mình và hoàn thành (gần như). Không như vậy với Swift.
chakrit

6
@rewolf, tôi nghĩ rằng anh ta có nghĩa là một biến có tên nil, nhưint nil
Luke

165

Sự nhầm lẫn có thể xuất phát từ giả định rằng chỉ thay đổi một phần mở rộng tệp từ .mthành .mmlà tất cả những gì bạn cần để kết nối các ngôn ngữ, trong khi, trong thực tế, nó không làm gì cả. Nó không phải .mmlà nguyên nhân gây ra ma sát .cpp, đó là .htiêu đề phải tích cực không phải là một C++tiêu đề.


Cùng dự án: Có.

Trong cùng một dự án, bạn có thể vui vẻ trộn C , C ++ , Objective-C , Objective C ++ , Swift và thậm chí là hội .

  1. ...Bridging-Header.h: bạn hiển thị C , Objective-CObjective-C ++ cho Swift bằng cách sử dụng cây cầu này
  2. <ProductModuleName>-Swift.h: Lộ tự động của bạn Swift lớp được đánh dấu bằng @objcđể Objective-C
  3. .h: đây là phần khó khăn, vì chúng được sử dụng một cách mơ hồ cho tất cả các hương vị của C , ++ hay không, Objective hay không. Khi một .hkhông chứa một từ khóa C ++ , như class, nó có thể được thêm vào ...Bridging-Header.hvà sẽ hiển thị bất kỳ chức năng nào tương ứng .c hoặc các .cpp chức năng mà nó tuyên bố. Mặt khác, tiêu đề đó phải được bọc trong API C hoặc Objective-C thuần túy .

Cùng một tệp: Không.

Trong cùng một tệp, bạn không thể trộn tất cả 5. Trong cùng một tệp nguồn :

  1. .swift: bạn không thể trộn Swift với bất cứ thứ gì
  2. .m: Bạn có thể trộn Objective-C với C . ( @Vinzzz )
  3. .mm: bạn có thể trộn Objective-C với C ++ . Cây cầu này là Objective-C ++ . ( @Vinzzz ).
  4. .c: C nguyên chất
  5. .cpp: bạn có thể kết hợp C ++hội ( @Vality )
  6. .h: có mặt khắp nơi và mơ hồ C , C ++ , Objective-C hoặc Objective-C ++ , vì vậy câu trả lời là tùy thuộc.

Người giới thiệu


1
Sửa lỗi: Trong cùng một tệp nguồn .m , Objective-C là một superset C nghiêm ngặt, bạn CÓ THỂ trộn Objective-CC ...
Vinzzz

1
Không có vấn đề gì, tôi thậm chí không quan tâm đến tín dụng, miễn là câu trả lời là đúng;) BTW, .mm là để trộn Objective-C và C ++ (C và C ++ là hai thứ khác nhau, bất chấp tên )
Vinzzz

1
Tôi sẽ đề cập rằng không giống như mục tiêu C, C ++ không phải là siêu bộ C nên bạn không thể trộn cả C và C ++ trong tệp .cpp. Chỉ có C ++ và lắp ráp.
Vality

1
Trong trường hợp bất cứ ai cũng thấy rằng câu trả lời chi tiết tốt này không giúp ích gì nhiều khi cố gắng hiển thị các tệp Swift vào tệp Objective-C / C ++ của họ (Xcode đang phàn nàn rằng không tìm thấy tệp tiêu đề Swift). Tôi thấy rằng tôi phải nhập "ProductName / ProductModuleName-Swift.h" trong tệp nguồn Objective-C / C ++ của tôi. Tôi thấy điều này hơi bị chôn vùi tại: developer.apple.com/l
Library / ios / document / Swift / Conceptionual / Kẻ

Điểm tốt. Đối với một dự án làm việc pha trộn các ngôn ngữ này, hãy xem stackoverflow.com/a/32546879/218152 .
SwiftArchitect

72

Tôi đã viết một dự án Xcode 6 đơn giản chỉ ra cách trộn mã C ++, Objective C và Swift:

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

Cụ thể, ví dụ này gọi hàm Objective C và hàm C ++ từ Swift.

Chìa khóa là tạo một tiêu đề chung Project-Bridging-Header.h và đặt các tiêu đề Objective C ở đó.

Vui lòng tải về dự án như một ví dụ hoàn chỉnh.


Cảm ơn vì Gian này!
Jason Elwood

Cảm ơn bạn về ví dụ này, nhưng nếu tôi muốn chuyển #import "CPlusPlus.h" từ tệp ObjCtoCPlusPlus.mm sang tệp ObjCtoCPlusPlus.h, trình biên dịch trả về lỗi này: <unknown>: 0: lỗi: không thể nhập tiêu đề bắc cầu ' /Users/Ale/Doads/spl-master/C-ObjC-Swift/Performance_Console/Performance_Console/Performance_Console-Bridging-Header.h 'bạn có thể chuyển bản nhập này vào tệp tiêu đề không?
Alessandro Pirovano

@API: Không, bạn đang thiếu điểm. ObjCtoCPlusPlus.h/ `` .mm` tồn tại cho mục đích duy nhất là cung cấp giao diện Ob-C cho mã C ++. Đây là cầu nối, là thành phần cần thiết ở đây. Để lại bao gồm vị trí của chúng và thêm một phương thức trong các ObjCtoCPlusPlus.…tệp cho mỗi phương thức C ++ mà bạn cần truy cập. Bạn sẽ làm tốt để đọc qua sourcemaking.com/design_potypes/ad CHƯƠNG
Slipp D. Thompson

Tôi đã tải xuống ví dụ của bạn và thật tuyệt vời cho hàm STATIC mà lớp cung cấp làm ví dụ, nhưng tôi không thể quản lý để điều chỉnh ví dụ cho một hàm không tĩnh bổ sung được sử dụng từ bên ngoài ... Điều đó cũng có thể chứ? (Tôi đã làm bài tập về C ++ của mình cách đây nhiều thập kỷ ... Tôi không phải là cây bút chì sắc nhất của chiếc hộp ngay bây giờ)
Isaac

31

Bạn cũng có thể bỏ qua tệp Objective-C ở giữa. Chỉ cần thêm tệp tiêu đề C với tệp nguồn .cpp. Chỉ có khai báo C trong tệp tiêu đề và bao gồm bất kỳ mã C ++ nào trong tệp nguồn. Sau đó, bao gồm tệp tiêu đề C trong ** - Bridging-Header.h.

Ví dụ sau đây trả về một con trỏ tới một đối tượng C ++ (struct Foo) để Swift có thể lưu trữ trong COpaquePulum thay vì có struct Foo được xác định trong không gian toàn cầu.

Tệp Foo.h (được xem bởi Swift - được bao gồm trong tệp bắc cầu)

#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

Tệp nguồn bên trong Foo.cpp (không thấy bởi 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
Câu trả lời này xứng đáng cách hơn upvotes. Thực sự hữu ích.
rsp1984

Đây là lần đầu tiên tôi thấy extern "C"bọc tiêu đề ở vị trí được bao gồm thay vì #ifdef'ed trong chính tệp tiêu đề. Xuất sắc!
dcow

27

Tôi vừa thực hiện một dự án ví dụ nhỏ bằng Swift, Objective-C và C ++. Đây là bản demo về cách sử dụng khâu OpenCV trong iOS. API OpenCV là C ++ vì vậy chúng tôi không thể nói chuyện trực tiếp với nó từ Swift. Tôi sử dụng một lớp bao bọc nhỏ, tệp thực thi là Objective-C ++. Tệp Header sạch Objective-C, vì vậy Swift có thể nói chuyện trực tiếp với điều này. Bạn phải cẩn thận không nhập gián tiếp bất kỳ tệp C ++ - ish nào vào các tiêu đề mà Swift tương tác.

Dự án ở đây: https://github.com/foundry/OpenCVSwiftStitch


Tôi nghĩ rằng điều này trả lời một vấn đề tôi gặp phải hôm nay khi cố gắng sử dụng thư viện bên thứ 3 KudanCV với Swift. Tiêu đề bắc cầu của tôi nhập tệp .h của chúng chứa nhập vào <memory> <chuỗi> và <vectơ> mà tôi đoán là từ các thư viện hoặc tệp C ++, do đó, mã Swift của tôi sẽ không biên dịch. Tôi sẽ biết ơn nếu ai đó có thể cho tôi biết nếu có cách nào khác ... hoặc nếu tôi phải viết lại tất cả mã của mình trong Objective-C
Rocket Garden

1
@RocketGarden - Tệp tiêu đề KudanCV là C ++. Bạn có thể viết một trình bao bọc hoạt động giống như lớp trình bao bọc ví dụ của tôi. HOẶC bạn viết lại những phần trong ứng dụng của bạn cần nói chuyện với KudanCV trong object-C ++ (với tiêu đề Objective-C). Bạn sẽ không cần phải viết lại những phần trong dự án của bạn mà không liên quan đến KudanCV.
xưởng đúc

Cảm ơn vì điều đó, tôi nhận ra nó khoảng 5 phút sau, nhưng nó hữu ích để ghi lại cho người khác.
Rocket Garden

13

Đây là nỗ lực của tôi tại một công cụ clang để tự động hóa giao tiếp C ++ / swift. Bạn có thể kích hoạt các lớp C ++ từ swift, kế thừa từ lớp C ++ và thậm chí ghi đè các phương thức ảo trong swift.
Nó sẽ phân tích lớp C ++ mà bạn muốn xuất để nhanh chóng và tự động tạo cầu Objective-C / Objective-C ++.

https://github.com/sandym/swiftpp


8

Swift không tương thích trực tiếp với C ++. Bạn có thể giải quyết vấn đề bằng cách gói mã C ++ của mình bằng Objective-C và sử dụng trình bao bọc Objective C trong Swift.


Đây là những gì tôi đã làm. Tôi đã viết một bài viết về cách tích hợp c ++ với một dự án nhanh chóng: learningswift.brightdigit.com/integrating-c-plus-plus-swift
leogdion


4

Không, không phải trong một tập tin duy nhất.

Tuy nhiên, bạn có thể sử dụng C ++ trong Dự án Swift mà không cần thư viện tĩnh hoặc khung. Giống như những người khác đã nói, mấu chốt là tạo một tiêu đề bắc cầu Objective-C bao gồm các tiêu đề C ++ tương thích C được đánh dấu là C tương thích với thủ thuật "C" {} bên ngoài .

Video hướng dẫn: https://www.youtube.com/watch?v=0x6JbiphNS4


2

Các câu trả lời khác hơi không chính xác. Bạn thực sự có thể trộn cả Swift và [Objective-] C [++] trong cùng một tệp, mặc dù không hoàn toàn theo cách bạn mong đợi.

Tệp này (c.swift) biên dịch thành tệp thực thi hợp lệ với cả 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;
}
// */

Mã mẫu của bạn là C không phải C ++. Tốt hơn nên đi với một ví dụ <iostream> IMHO.
kakyo

2

Một mẹo (của nhiều người) là

Bạn cần một tiêu đề riêng cho tệp obj-c ++ bắc cầu của bạn ...

Bạn không thể chỉ ném @interface và @im THỰCation trong cùng một tệp .mm như thường làm.

Vì vậy, trong tệp tiêu đề bắc cầu của bạn, bạn có

#import "Linkage.hpp"

Linkage.hpp có @interface cho Liên kết và Liên kết.mm có @im THỰCation cho .mm

Và sau đó

... bạn thực sự không #inc loại "yourCpp.hpp" trong Linkage.hpp.

Bạn chỉ đặt #include "yourCpp.hpp"tệp Linkage.mm, không phải trong tệp Linkage.hpp.

Trong nhiều ví dụ / hướng dẫn trực tuyến, người viết chỉ cần đặt @interface và @im THỰCation trong cùng một tệp .mm, như người ta thường làm.

Điều đó sẽ làm việc trong các ví dụ bắc cầu cpp rất đơn giản, nhưng,

Vấn đề là:

nếu yourCpp.hpp của bạn có bất kỳ tính năng c ++ nào mà nó chắc chắn sẽ (như dòng đầu tiên #include <something>), thì quá trình sẽ thất bại.

Nhưng nếu bạn không có tệp tiêu đề#include "yourCpp.hpp" Liên kết (tốt nhất là có tệp đó trong tệp .mm, rõ ràng bạn sẽ cần) - nó hoạt động.

Một lần nữa, điều này không may chỉ là một mẹo trong toàn bộ quá trình.


1

Trong trường hợp điều này hữu ích với bất kỳ ai, tôi cũng có một hướng dẫn ngắn gọn về cách gọi thư viện tĩnh C ++ đơn giản từ tiện ích dòng lệnh Swift tầm thường. Đây là một bằng chứng thực sự trần trụi của đoạn mã khái niệm.

Không có Objective-C liên quan, chỉ có Swift và C ++. Mã trong thư viện C ++ được gọi bởi trình bao bọc C ++, thực hiện một chức năng với liên kết "C" bên ngoài. Hàm đó sau đó được tham chiếu trong tiêu đề bắc cầu và được gọi từ Swift.

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


1

Tôi đang cung cấp một liên kết đến SE-0038 trong tài nguyên chính thức, được mô tả là Điều này duy trì các đề xuất cho các thay đổi và cải tiến hiển thị của người dùng đối với Ngôn ngữ lập trình Swift.

Tình trạng như ngày nay là đây là yêu cầu tính năng đã được chấp nhận nhưng chưa được lên lịch.

Liên kết này nhằm điều khiển bất cứ ai tìm kiếm tính năng này theo đúng hướng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.