2009-06-29 18 views
5

Muszę połączyć Objective-C i C++. Chciałbym ukryć wszystkie rzeczy w C++ wewnątrz jednej klasy i zachować wszystkie inne proste Objective-C. Problem polega na tym, że chcę, aby niektóre klasy C++ były zmiennymi instancji. Oznacza to, że muszą być wymienione w pliku nagłówkowym, który jest dołączany przez inne klasy, a C++ zaczyna rozprzestrzeniać się na całą aplikację. Najlepsze rozwiązanie, jakie udało mi się znaleźć, wygląda tak:Klasy C++ jako zmienne instancji klasy Objective-C

#ifdef __cplusplus 
#import "cppheader.h" 
#endif 

@interface Foo : NSObject 
{ 
    id regularObjectiveCProperty; 
    #ifdef __cplusplus 
    CPPClass cppStuff; 
    #endif 
} 

@end 

To działa. Plik implementacji ma rozszerzenie mm, więc zostanie skompilowany jako Objective-C zmieszany z C++, #ifdef odblokowuje C++ i tam jedziemy. Kiedy inna klasa klasy Objective-C importuje nagłówek, rzeczy C++ są ukryte, a klasa nie widzi nic specjalnego. To wygląda na włamanie, czy jest lepsze rozwiązanie?

+1

to w zasadzie to, co mam wymyślić, gdy miałem ten sam problem. Ale zwróć uwagę na swój ifdef: musisz wstawić dopełnienie dla gałęzi non-cpp. W przeciwnym razie kompilator nie znałby rozmiaru twoich obiektów Foo. Chociaż może to nie zaszkodzić nieusuwalnym wersjom kompilacji var, jest to z pewnością problem dla celów starego stylu. –

+0

Skopiowałem podejście opisane powyżej. Wydawało się całkiem ładne i łatwe, ale potem spowodowało pewne szalone problemy z uszkodzeniem pamięci: http://stackoverflow.com/questions/2458652/objective-c-insanity-simple-assignement-to-a-single-float-variable-results – morgancodes

Odpowiedz

8

Brzmi to jak klasyczne użycie interfejsu/protokołu @. Zdefiniuj protokół cel-c dla interfejsu API, a następnie przedstaw implementację tego protokołu przy użyciu klasy Objective-C++. W ten sposób klienci potrzebują tylko znać protokół, a nie nagłówek implementacji. Tak więc biorąc pod uwagę Oryginalna implementacja wykonana

@interface Foo : NSObject 
{ 
    id regularObjectiveCProperty; 
    CPPClass cppStuff; 

} 

@end 

chciałbym zdefiniować protokół

//Extending the NSObject protocol gives the NSObject 
// protocol methods. If not all implementations are 
// descended from NSObject, skip this. 
@protocol IFoo <NSObject> 

// Foo methods here 
@end 

i modyfikowania oryginalnego oświadczenia Foo do

@interface Foo : NSObject <IFoo> 
{ 
    id regularObjectiveCProperty; 
    CPPClass cppStuff; 
} 

@end 

kod klienta można następnie pracować z typu id<IFoo> i nie potrzebuje kompilowany jako Objective-C++. Oczywiście można przekazać instancję Foo tym klientom.

+0

Jeśli @interface Foo jest w pliku .h, to jest to możliwe, aby zapobiec wpływowi na obj-C++? Jeśli @interface Foo znajduje się w pliku .mm, jak mogę utworzyć jego instancję? – Eonil

+1

Każdy moduł, który importuje Foo.h będzie musiał zostać skompilowany jako Objective-C++, ale kod klienta potrzebuje tylko * importu * Nagłówek IFoo do użycia IFoo i może w związku z tym być tylko Objective-C. Jest to klasyczny wzór zarządzania zależnościami. –

+0

w twoim przykładzie, w jaki sposób można utworzyć instancję nowego Foo bez importowania nagłówka? Pierwszą rzeczą, która przychodzi na myśl, jest klasa fabularna klasy Objective C++, która nie importuje rzeczy z C++ do nagłówka. Wszystko wydaje się bardzo skomplikowane. Istnieje również takie podejście: http://stackoverflow.com/questions/2262011/adding-c-object-to-objective-c-class/2262395, ale nie dostałem go do pracy (zobacz http://stackoverflow.com/questions/2463970/trouble-using-opaque-pointers-in-objective-c) – morgancodes

1

Czy istnieje jakiś szczególny powód, dla którego nie można po prostu użyć programu Objective C++? Po prostu przełącz kompilator na Compile Sources As: Objective C++ (lub zmień wszystkie swoje pliki źródłowe z .cpp lub .m na .mm). Następnie można swobodnie wymieszać swoją C++ i Objective C

C++ zacznie się rozprzestrzeniać na cały aplikacji

Jaki problem ma z tym? Jeśli twój kod Celive C wykonuje ogólnie tylko kod C/Objective C, to prawie na pewno nie zostanie w ogóle zmieniony przez kompilację jako C++. Nie ma problemów z wielkością lub szybkością działania.

Jedynymi wadami, które znalazłem są: nie można (jeszcze) użyć statycznego analizatora klang do analizy C++; jakiś (względnie dziwny) kod C nie będzie działał w C++, co jest sporadycznie problemem przy korzystaniu z kodu C strony trzeciej.

+0

Jedynym problemem jest to, że nie czuję się dobrze z C++ i bałam się, że pojawią się pewne subtelne różnice może prowadzić do błędów. Podoba mi się idea, że ​​C++ jest enkapsulowany tylko w klasie, która naprawdę tego potrzebuje. Ale dziękuję, to na pewno jest rozwiązanie. – zoul

0

Może się okazać, że masz problemy z robieniem tego - z tego co pamiętam z ObjectiveC++ może się okazać, że konstruktor i destruktor dla twojego zamkniętego obiektu w C++ nie zostaną wywołani.

3

Niedawno również spotkałem się z tym problemem. W moim przypadku protokół był przesadny. Potrzebowałem tylko wskaźnika do obiektu dostępu do danych, który był obiektem C++.

Co zrobiłem, zadeklarowano klasę ze zmienną instancji void * i rzutowałem ją, gdy używam jej w metodach instancji.

To jest trochę hack-y, ale koncepcyjnie, jest bardzo podobny do tego, jaki jest typ Objective-C id.

0

nie ten

Jeśli ifdef się zmienną instancji, które dadzą dwa oddzielne układy zmiennych instancji tej klasy. Otrzymasz przypadkowe rozbijacze pamięci w każdym miejscu, ponieważ pamięć przydzielona dla obiektu w połowie przypadków będzie zbyt krótka. Zamiast ifdefing się zmienną instancji, do przodu-zadeklarować jej typ jak

struct CPPClass; 

i posiada wskaźnik do niej w ivar, potem w twoim init/dealloc metody nazywają new/delete, aby utworzyć obiekt. Jeśli masz kilka obiektów, możesz utworzyć strukturę do przechowywania wszystkich ivars iv bezpośrednio, a następnie po prostu nowa/usunąć tę strukturę.

Zobacz ten wątek, aby uzyskać więcej szczegółów i dalsze linki do informacji, w tym podcast, że rozmowy na długości około ObjC++: Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link?

+0

W języku C typ struktury musiałby być nazywany 'struct CPPClass', a nie' CPPClass', więc musiałby to również zmienić. – newacct

+0

W deklaracji ivar, tak, dobry połów. Dla C++ struct Foo i Foo są takie same, więc są potrzebne tylko w nagłówku. Zwykle po prostu piszę struct przed nazwą klasy wszędzie, gdzie go używam, nie potrzebujesz osobnej deklaracji struktury, tak jak tu wspomniałem. – uliwitness

Powiązane problemy