Czy mogę łączyć Swift z C ++? Podobnie jak pliki .mm Objective-C


131

Właśnie zmieniłem moje pliki .m na .mm i używam C ++. Czy jest sposób, aby zrobić to samo w Swift?

Odpowiedzi:


111

Nie. Kiedy przełączasz się z .m na .mm, tak naprawdę przełączasz się z Objective-C na inny język (który ma wiele subtelnych różnic) zwany Objective-C ++. Więc tak naprawdę nie używasz C ++; używasz Objective-C ++, który akceptuje większość C ++ jako dane wejściowe (w taki sam sposób, w jaki C ++ akceptuje większość, ale nie całe C jako dane wejściowe). Kiedy mówię, że nie jest to całkiem C ++, rozważ plik C ++, który zawiera zmienną o nazwie nil(która jest poprawną wersją C ++), a następnie spróbuj skompilować ją jako Objective-C ++.

Swift nie ma takiego samego związku. Nie jest to nadzbiór języków C ani C ++ i nie można ich bezpośrednio użyć w .swiftpliku.

„Używanie Swift z Cocoa i Objective-C” mówi nam również:

Nie można importować kodu C ++ bezpośrednio do Swift. Zamiast tego utwórz otokę Objective-C lub C dla kodu C ++.


94
Właściwie to dość denerwujące - wszyscy z aplikacjami Cocoa zawierającymi podstawy kodu C / C ++ musimy teraz obsługiwać projekty napisane w 3 językach ...
Jay

6
Sugeruję, że Objective-c ++ nie jest innym językiem, ale połączenie różnicy między c ++ i Objective-c jest subtelne, ale nadal istnieje
amar

1
W jaki sposób „zero” jest legalnym C ++? Nie ma czegoś takiego (przynajmniej w standardowym c ++) Proszę podać inny przykład
rewolf

4
Ale dzięki ObjC możesz po prostu przejść do .mmswoich plików i (prawie) skończyć. Nie tak z Szybkim.
chakrit

6
@rewolf, myślę, że ma na myśli zmienną o nazwie nil, na przykładint nil
Luke

168

Zamieszanie może wynikać z założenia, że ​​wystarczy zmienić rozszerzenie pliku z .mna .mm, aby połączyć języki, podczas gdy w rzeczywistości nic takiego nie robi. To nie jest to, .mmco powoduje tarcie .cpp, to .hnagłówek, który zdecydowanie nie może być C++nagłówkiem.


Ten sam projekt: tak.

W tym samym projekcie możesz szczęśliwie mieszać C , C ++ , Objective-C , Objective C ++ , Swift , a nawet Assembly .

  1. ...Bridging-Header.h: udostępniasz C , Objective-C i Objective-C ++ w Swift za pomocą tego mostu
  2. <ProductModuleName>-Swift.h: Naraża automatycznie swoje Swift klas oznaczonych @objcdo Objective-C
  3. .h: to jest trudna część, ponieważ są one niejednoznacznie używane dla wszystkich smaków C , ++ lub nie, Cel lub nie. Gdy .hnie zawiera pojedynczy C ++ słów kluczowych, jak classto może być dodane do ...Bridging-Header.hi narazi niezależnie funkcjonować odpowiednie .c lub .cpp funkcjonalności deklaruje. W przeciwnym razie ten nagłówek musi być opakowany w czysty interfejs API C lub Objective-C .

Ten sam plik: Nie.

W tym samym pliku nie można mieszać wszystkich 5. W tym samym pliku źródłowym :

  1. .swift: nie możesz mieszać Swifta z niczym
  2. .m: Można mieszać Objective-C z C . ( @Vinzzz )
  3. .mm: możesz mieszać Objective-C z C ++ . Ten most to Objective-C ++ . ( @Vinzzz ).
  4. .c: czysty C
  5. .cpp: możesz mieszać C ++ i Assembly ( @Vality )
  6. .h: wszechobecny i niejednoznaczny C , C ++ , Objective-C lub Objective-C ++ , więc odpowiedź brzmi: to zależy.

Bibliografia


1
Korekta: W tym samym pliku źródłowym .m , Objective-C będącym ścisłą supersetem C, MOŻESZ łączyć Objective-C i C ...
Vinzzz

1
Żaden problem, nie dbam nawet o kredyt, o ile odpowiedź jest prawidłowa;) BTW, .mm jest do mieszania Objective-C i C ++ (C i C ++ to dwie różne rzeczy, pomimo nazwy )
Vinzzz,

1
Chciałbym wspomnieć, że w przeciwieństwie do obiektywnego C, C ++ nie jest nadzbiorem C, więc nie można mieszać C i C ++ w pliku .cpp. Tylko C ++ i montaż.
Vality,

1
W przypadku, gdy ktoś stwierdzi, że ta szczegółowa odpowiedź nie do końca pomaga, gdy próbuje ujawnić pliki Swift w ich pliku Objective-C / C ++ (Xcode narzeka, że ​​nie znaleziono pliku nagłówkowego Swift). Okazało się, że muszę zaimportować „ProductName / ProductModuleName-Swift.h” w moim pliku źródłowym Objective-C / C ++. Znalazłem to trochę zakopane pod adresem: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
AeroBuffalo

Słuszna uwaga. Aby uzyskać działający projekt łączący te języki, zajrzyj na stackoverflow.com/a/32546879/218152 .
SwiftArchitect

72

Napisałem prosty projekt Xcode 6, który pokazuje, jak łączyć kod C ++, Objective C i Swift:

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

W szczególności przykład wywołuje funkcję Objective C i C ++ z języka Swift.

Kluczem jest utworzenie współdzielonego nagłówka Project-Bridging-Header.h i umieszczenie tam nagłówków Objective C.

Pobierz projekt jako kompletny przykład.


Dzięki za tego Giana!
Jason Elwood,

Dziękuję za ten przykład, ale jeśli chcę przenieść #import „CPlusPlus.h” z ObjCtoCPlusPlus.mm do pliku ObjCtoCPlusPlus.h, kompilator zwrócił ten błąd: <unknown>: 0: error: nie udało się zaimportować nagłówka mostkowania ' /Users/Ale/Downloads/shared-master/C-ObjC-Swift/Performance_Console/Performance_Console/Performance_Console-Bridging-Header.h 'czy można przenieść ten import do pliku nagłówkowego?
Alessandro Pirovano

@API: Nie, nie rozumiesz. ObjCtoCPlusPlus.h/ `.mm` istnieje wyłącznie w celu zapewnienia interfejsu Ob-C do kodu C ++ - jest to mostek, który jest tutaj niezbędnym komponentem. Pozostaw dołączenia tam, gdzie się znajdują, i dodaj metodę w ObjCtoCPlusPlus.…plikach dla każdej metody C ++, do której potrzebujesz dostępu. Dobrze by było, gdybyś przeczytał sourcemaking.com/design_patterns/adapter
D. Thompson,

Pobrałem Twój przykład i jest fantastyczny dla funkcji STATIC, którą klasa oferuje jako przykład, ale nie mogę dostosować przykładu do dodatkowej funkcji niestatycznej do użycia z zewnątrz ... Czy to również możliwe? (Zrobiłem zadanie domowe z C ++ dziesiątki lat temu ... Nie jestem teraz najostrzejszym ołówkiem w pudełku)
Isaac

32

Możesz także pominąć plik Objective-C pomiędzy. Po prostu dodaj plik nagłówkowy C z plikiem źródłowym .cpp. Miej tylko deklaracje C w pliku nagłówkowym i dołącz dowolny kod C ++ do pliku źródłowego. Następnie dołącz plik nagłówkowy C do ** - Bridging-Header.h.

Poniższy przykład zwraca wskaźnik do obiektu C ++ (struct Foo), dzięki czemu Swift może przechowywać w COpaquePointer zamiast definiowania struktury Foo w przestrzeni globalnej.

Plik Foo.h (widziany przez Swift - zawarty w pliku pomostowym)

#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

Wewnątrz pliku źródłowego Foo.cpp (niewidoczny dla 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;
}

2
Ta odpowiedź zasługuje sposób więcej upvotes. Naprawdę użyteczne.
rsp1984

To pierwszy raz, kiedy widziałem extern "C"zawijanie nagłówka w miejscu, w którym jest zawarty, a nie #ifdefw samym pliku nagłówkowym. Znakomity!
dcow

Wszyscy w internecie: „musisz napisać opakowanie z celem-c dla klas C ++”. Nie, nie musisz. Oto prosta sztuczka, aby mieć jeden język mniej w bazie kodu.
Siergiej

27

Właśnie wykonałem mały przykładowy projekt przy użyciu Swift, Objective-C i C ++. To demonstracja, jak używać zszywania OpenCV w iOS. OpenCV API to C ++, więc nie możemy rozmawiać z nim bezpośrednio z Swift. Używam małej klasy opakowania, której plik implementacji to Objective-C ++. Plik nagłówkowy jest czysty Objective-C, więc Swift może rozmawiać z tym bezpośrednio. Musisz uważać, aby nie importować pośrednio żadnych plików C ++ - ish do nagłówków, z którymi współdziała Swift.

Projekt jest tutaj: https://github.com/foundry/OpenCVSwiftStitch


Myślę, że to rozwiązuje problem, który napotkałem dzisiaj, próbując użyć biblioteki KudanCV innej firmy w Swift. Mój nagłówek mostkujący importuje ich plik .h, który zawiera import do <memory> <strings> i <vectors>, które, jak sądzę, pochodzą z bibliotek lub plików C ++, w wyniku czego mój kod Swift nie zostanie skompilowany. Byłbym wdzięczny, gdyby ktoś mógł mi powiedzieć, czy jest na to sposób ... lub jeśli muszę przepisać cały mój kod w Objective-C
Rocket Garden

1
@RocketGarden - Plik nagłówkowy KudanCV to C ++. Możesz napisać opakowanie, które działa w taki sam sposób, jak moja przykładowa klasa opakowania. LUB przepisujesz te części aplikacji, które muszą komunikować się z KudanCV w Objective-C ++ (z nagłówkami Objective-C). Nie musiałbyś przepisywać tych części projektu, które nie dotyczą KudanCV.
odlewnia

Dzięki za to, zdałem sobie z tego sprawę jakieś 5 minut później, ale warto mieć to na koncie dla innych.
Rocket Garden

13

Oto moja próba użycia narzędzia Clang do automatyzacji C ++ / szybkiej komunikacji. Możesz tworzyć klasy C ++ ze swift, dziedziczyć z klasy C ++, a nawet przesłonić metody wirtualne w swift.
Spanalizuje klasę C ++, którą chcesz wyeksportować, aby szybko i automatycznie wygenerować mostek Objective-C / Objective-C ++.

https://github.com/sandym/swiftpp




4

Nie, nie w jednym pliku.

Możesz jednak używać języka C ++ w projektach Swift bez konieczności posiadania biblioteki statycznej lub struktury. Jak powiedzieli inni, kluczem jest utworzenie nagłówka mostkującego Objective-C, który # zawiera nagłówki C ++ zgodne z C, które są oznaczone jako zgodne z C za pomocą zewnętrznej sztuczki „C” {} .

Samouczek wideo: https://www.youtube.com/watch?v=0x6JbiphNS4


2

Inne odpowiedzi są nieco niedokładne. W rzeczywistości możesz mieszać zarówno Swift, jak i [Objective-] C [++] w tym samym pliku, chociaż nie do końca tak, jak byś się spodziewał.

Ten plik (c.swift) kompiluje się do prawidłowego pliku wykonywalnego z zarówno swiftc c.swifticlang -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;
}
// */

Twój przykładowy kod jest w C, a nie C ++. Lepiej skorzystaj z przykładowego IMHO <iostream>.
kakyo

2

Jedna (z wielu) sztuczek jest taka

Potrzebujesz osobnego nagłówka dla swojego mostkującego pliku obj-c ++ ...

Nie możesz po prostu wrzucić @interface i @implementation do tego samego pliku .mm, jak to się często robi.

Więc w swoim pliku nagłówkowym mostkowania masz

#import "Linkage.hpp"

Linkage.hpp ma @interface dla Linkage, a Linkage.mm ma @implementation dla .mm

I wtedy

... w rzeczywistości nie # uwzględniasz „yourCpp.hpp” w Linkage.hpp.

Umieszczasz tylko #include "yourCpp.hpp"plik Linkage.mm, a nie plik Linkage.hpp.

W wielu internetowych przykładach / samouczkach autor po prostu umieszcza @interface i @implementation w tym samym pliku .mm, jak to się często robi.

To zadziała w bardzo prostych przykładach mostkowania cpp, ale

Problemem jest:

jeśli twój Cpp.hpp ma jakiekolwiek cechy C ++, które z pewnością będą (jak pierwsza linia #include <something>), to proces się nie powiedzie.

Ale jeśli po prostu nie masz #include "yourCpp.hpp"w pliku nagłówkowym Linkage (dobrze jest mieć go w pliku .mm, oczywiście będziesz musiał) - działa.

Niestety, jest to tylko jedna wskazówka w całym procesie.


1

Na wypadek, gdyby było to pomocne dla każdego, mam również krótki samouczek dotyczący wywoływania prostej biblioteki statycznej C ++ z prostego narzędzia wiersza poleceń Swift. To jest prawdziwy dowód koncepcji kodu.

Bez Objective-C, tylko Swift i C ++. Kod w bibliotece C ++ jest wywoływany przez opakowanie C ++, które implementuje funkcję z zewnętrznym połączeniem „C”. Ta funkcja jest następnie przywoływana w nagłówku mostkowania i wywoływana z języka Swift.

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


1

Podaję link do SE-0038 w oficjalnym zasobie, opisanym jako To utrzymuje propozycje zmian i widocznych dla użytkownika ulepszeń w Swift Programming Language.

Stan na dzień dzisiejszy jest taki, że jest to propozycja funkcji, która została zaakceptowana, ale nie została jeszcze zaplanowana.

Ten link ma na celu skierowanie każdego, kto szuka tej funkcji, we właściwym kierunku

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.