Рекомендуемый способ использования класса C ++ в классе Objective-C, минимизирующий использование Objective-C ++? - PullRequest
7 голосов
/ 27 марта 2011

Я смешиваю Objective-C и C ++. Однако я хочу свести к минимуму использование Objective-C ++. Потому что у него есть какие-то ограничения как в Objective-C, так и в C ++.

В настоящее время я использую это так.

// A.h, Objective-C
#import "B.h"
@interface A
{
    B* b;
}
@end

// B.h, Objective-C++
@interface B
{
    void* c;
}

// C.h, C++
class C
{
};

Я хочу включить C.h в B.h, но если я это сделал, B.h не может быть импортирован в A.h. Поэтому я должен оставить переменную c в качестве void* типа. Это не большая проблема, потому что я могу свободно использовать элементы C в B.m файле. Но я всегда должен бросать это. Это чувствует что-то неясное. Поэтому я хочу использовать лучший способ, если это так.

Ответы [ 2 ]

15 голосов
/ 27 марта 2011

Есть несколько способов сделать это, но, на мой взгляд, лучший способ - использовать идиому 'PIMPL' , которая довольно распространена в C ++.Сделайте заголовки чистыми Objective-C и чистым C ++, с указателями на заранее объявленную структуру, содержащую фактическую реализацию.Это определено в файле .mm, и затем можно использовать Objective-C ++.

В вашем примере вы бы сделали что-то вроде этого:

// B.h, pure Objective-C:
struct BImpl;
@interface B
{
    struct BImpl* impl;
}
// ...


// B.mm, mixed:
#include "C.h"
struct BImpl // since this is C++, it can actually have constructors/destructors
{
    C* my_c;
    BImpl() : my_c(new C) {}
    ~BImpl() { delete my_c; my_c = NULL; }
};
// make sure to alloc/initialise impl (using new) in B's init* methods,
// and free it (using delete) in the dealloc method.

Я действительно написал статьюпри решении именно этой проблемы вы можете найти ее полезной: http://philjordan.eu/article/strategies-for-using-c++-in-objective-c-projects - здесь также показаны некоторые другие способы сделать это, включая ваш оригинальный подход void*.

4 голосов
/ 02 октября 2012

Как написал pmjordan в своей статье в блоге , для BImpl в объявлении @interface необходимо ключевое слово struct, как показано ниже.

struct BImpl;
@interface B
{
    struct BImpl* impl;
}

Я думаю, что он случайно пропустил это. Если вам нужно включить этот заголовок, когда у вас много файлов * .m, это имеет огромное значение. Добавленное ключевое слово struct заставляет компилятор Objective-C понимать этот заголовок как чистый C для других файлов .m, которые импортируют этот заголовок. В противном случае другие * .m файлы, которые импортируют этот заголовок, не будут скомпилированы. Это небольшое решение избавляет вас от изменения файлов * .m на файлы .mm. Иногда изменение исходных файлов .m на .mm вызывает много ошибок компиляции.

...