Вы можете смешивать C ++ с Objective-C, если будете делать это осторожно. Есть несколько предостережений, но в целом их можно смешивать. Если вы хотите сохранить их отдельно, вы можете настроить стандартную функцию-оболочку C, которая дает объекту Objective-C удобный интерфейс в стиле C из кода, отличного от Objective-C (выберите более удачные имена для ваших файлов, я выбрал эти имена за многословие):
MyObject-C-Interface.h
#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__
// This is the C "trampoline" function that will be used
// to invoke a specific Objective-C method FROM C++
int MyObjectDoSomethingWith (void *myObjectInstance, void *parameter);
#endif
MyObject.h
#import "MyObject-C-Interface.h"
// An Objective-C class that needs to be accessed from C++
@interface MyObject : NSObject
{
int someVar;
}
// The Objective-C member function you want to call from C++
- (int) doSomethingWith:(void *) aParameter;
@end
MyObject.mm
#import "MyObject.h"
@implementation MyObject
// C "trampoline" function to invoke Objective-C method
int MyObjectDoSomethingWith (void *self, void *aParameter)
{
// Call the Objective-C method using Objective-C syntax
return [(id) self doSomethingWith:aParameter];
}
- (int) doSomethingWith:(void *) aParameter
{
// The Objective-C function you wanted to call from C++.
// do work here..
return 21 ; // half of 42
}
@end
MyCPPClass.cpp
#include "MyCPPClass.h"
#include "MyObject-C-Interface.h"
int MyCPPClass::someMethod (void *objectiveCObject, void *aParameter)
{
// To invoke an Objective-C method from C++, use
// the C trampoline function
return MyObjectDoSomethingWith (objectiveCObject, aParameter);
}
Функция-оболочка не обязательно должна находиться в том же .m
файле, что и класс Objective-C, но файл, в котором она существует, должен быть скомпилирован как код Objective-C. . Заголовок, объявляющий функцию-оболочку, должен быть включен как в код CPP, так и в код Objective-C.
(ПРИМЕЧАНИЕ: если файлу реализации Objective-C присвоено расширение «.m», он не будет связываться под Xcode. Расширение «.mm» указывает Xcode ожидать комбинации Objective-C и C ++, т. Е. Objective-C ++. )
Вы можете реализовать описанное выше объектно-ориентированным образом, используя идиому PIMPL . Реализация немного отличается. Короче говоря, вы помещаете функции-оболочки (объявленные в «MyObject-C-Interface.h») внутри класса с (частным) указателем void на экземпляр MyClass.
MyObject-C-Interface.h (PIMPL)
#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__
class MyClassImpl
{
public:
MyClassImpl ( void );
~MyClassImpl( void );
void init( void );
int doSomethingWith( void * aParameter );
void logMyMessage( char * aCStr );
private:
void * self;
};
#endif
Обратите внимание, что методам-оболочкам больше не требуется указатель void на экземпляр MyClass; теперь он является частным членом MyClassImpl. Метод init используется для создания экземпляра MyClass;
MyObject.h (PIMPL)
#import "MyObject-C-Interface.h"
@interface MyObject : NSObject
{
int someVar;
}
- (int) doSomethingWith:(void *) aParameter;
- (void) logMyMessage:(char *) aCStr;
@end
MyObject.mm (PIMPL)
#import "MyObject.h"
@implementation MyObject
MyClassImpl::MyClassImpl( void )
: self( NULL )
{ }
MyClassImpl::~MyClassImpl( void )
{
[(id)self dealloc];
}
void MyClassImpl::init( void )
{
self = [[MyObject alloc] init];
}
int MyClassImpl::doSomethingWith( void *aParameter )
{
return [(id)self doSomethingWith:aParameter];
}
void MyClassImpl::logMyMessage( char *aCStr )
{
[(id)self doLogMessage:aCStr];
}
- (int) doSomethingWith:(void *) aParameter
{
int result;
// ... some code to calculate the result
return result;
}
- (void) logMyMessage:(char *) aCStr
{
NSLog( aCStr );
}
@end
Обратите внимание, что MyClass создается с помощью вызова MyClassImpl :: init. Вы можете создать экземпляр MyClass в конструкторе MyClassImpl, но обычно это не очень хорошая идея. Экземпляр MyClass уничтожен деструктором MyClassImpl. Как и в случае реализации в стиле C, методы оболочки просто подчиняются соответствующим методам MyClass.
MyCPPClass.h (PIMPL)
#ifndef __MYCPP_CLASS_H__
#define __MYCPP_CLASS_H__
class MyClassImpl;
class MyCPPClass
{
enum { cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42 };
public:
MyCPPClass ( void );
~MyCPPClass( void );
void init( void );
void doSomethingWithMyClass( void );
private:
MyClassImpl * _impl;
int _myValue;
};
#endif
MyCPPClass.cpp (PIMPL)
#include "MyCPPClass.h"
#include "MyObject-C-Interface.h"
MyCPPClass::MyCPPClass( void )
: _impl ( NULL )
{ }
void MyCPPClass::init( void )
{
_impl = new MyClassImpl();
}
MyCPPClass::~MyCPPClass( void )
{
if ( _impl ) { delete _impl; _impl = NULL; }
}
void MyCPPClass::doSomethingWithMyClass( void )
{
int result = _impl->doSomethingWith( _myValue );
if ( result == cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING )
{
_impl->logMyMessage( "Hello, Arthur!" );
}
else
{
_impl->logMyMessage( "Don't worry." );
}
}
Теперь вы получаете доступ к вызовам MyClass через частную реализацию MyClassImpl. Этот подход может быть выгоден, если вы разрабатываете переносимое приложение; вы можете просто поменять реализацию MyClass на одну, специфичную для другой платформы ... но, честно говоря, лучшая ли эта реализация - это скорее вопрос вкуса и потребностей.
extern "C"
доint MyObjectDoSomethingWith
Вы можете скомпилировать свой код как Objective-C ++ - самый простой способ - переименовать ваш .cpp как .mm. Затем он будет правильно скомпилирован, если вы включите
EAGLView.h
(вы получали так много ошибок, потому что компилятор C ++ не понимал ни одного из ключевых слов Objective-C), и вы можете (по большей части) смешивать Objective-C и C ++, но вы лайк.источник
Самое простое решение - просто указать Xcode скомпилировать все как Objective C ++.
Задайте для вашего проекта или цели параметры компиляции исходных файлов как Objective C ++ и перекомпилируйте.
Тогда вы можете везде использовать C ++ или Objective C, например:
Это имеет тот же эффект, что и переименование всех ваших исходных файлов из .cpp или .m в .mm.
У этого есть два незначительных недостатка: clang не может анализировать исходный код C ++; какой-то относительно странный код C не компилируется под C ++.
источник
Шаг 1
Создайте целевой файл c (файл .m) и соответствующий ему файл заголовка.
// Заголовочный файл (мы называем его ObjCFunc.h)
// Соответствующий файл Objective C (мы называем его ObjCFunc.m)
Шаг 2
Теперь мы реализуем функцию c ++ для вызова только что созданной целевой функции c! Поэтому для этого мы определим файл .mm и соответствующий ему файл заголовка (здесь должен использоваться файл «. Mm», потому что мы сможем использовать в файле кодировку как Objective C, так и C ++)
// Заголовочный файл (мы называем его ObjCCall.h)
// Соответствующий файл Objective C ++ (мы называем его ObjCCall.mm)
Шаг 3
Вызов функции c ++ (которая фактически вызывает метод target c)
//Последний вызов
Надеюсь, это сработает!
источник
Вам нужно, чтобы ваш файл C ++ обрабатывался как Objective-C ++. Вы можете сделать это в xcode, переименовав foo.cpp в foo.mm (.mm - это расширение obj-c ++). Тогда, как говорили другие, стандартный синтаксис обмена сообщениями obj-c будет работать.
источник
Иногда переименование .cpp в .mm не является хорошей идеей, особенно если проект является кроссплатформенным. В этом случае для проекта xcode я открываю файл проекта xcode через TextEdit, обнаруживаю строку, которая содержит интересующий файл, она должна быть такой:
а затем измените тип файла с sourcecode.cpp.cpp на sourcecode.cpp.objcpp
Это эквивалентно переименованию .cpp в .mm
источник
Кроме того, вы можете вызвать среду выполнения Objective-C для вызова метода.
источник
Ответ @ DawidDrozd выше отличный.
Я бы добавил одно очко. Последние версии компилятора Clang жалуются на то, что при попытке использовать его код требуется «мостовое приведение».
Это кажется разумным: использование трамплина создает потенциальную ошибку: поскольку классы Objective-C подсчитываются по ссылкам, если мы передадим их адрес как void *, мы рискуем получить висящий указатель, если класс собирает мусор, пока обратный вызов все еще активный.
Решение 1) Какао предоставляет макрофункции CFBridgingRetain и CFBridgingRelease, которые предположительно добавляют и вычитают единицу из счетчика ссылок объекта Objective-C. Поэтому мы должны быть осторожны с несколькими обратными вызовами, чтобы выпускать столько же раз, сколько мы сохраняем.
Решение 2) Альтернативой является использование эквивалента слабой ссылки (т. Е. Без изменения счетчика удержания) без какой-либо дополнительной безопасности.
Язык Objective-C предоставляет для этого квалификатор приведения __bridge (CFBridgingRetain и CFBridgingRelease кажутся тонкими оболочками Cocoa над конструкциями языка Objective-C __bridge_rehibited и release соответственно, но какао, похоже, не имеет эквивалента для __bridge).
Необходимые изменения:
источник
self
в закрытие копию , которая может устареть. Другой момент заключается в том, что неясно, как это взаимодействует с автоматическим подсчетом ссылок и может ли компилятор выяснить, что происходит. На практике мне не удалось создать ситуацию, когда ни одна из версий не сработала в простом примере с одной модульной игрушкой.Вы можете смешивать C ++ с Objectiv-C (Objective C ++). Напишите метод C ++ в своем классе Objective C ++, который просто вызывает
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
и вызывает его из вашего C ++.Я не пробовал это раньше, но попробую и поделитесь с нами результатами.
источник