Puede mezclar C ++ con Objective-C si lo hace con cuidado. Hay algunas salvedades, pero en general se pueden mezclar. Si desea mantenerlos separados, puede configurar una función de contenedor C estándar que le da al objeto Objective-C una interfaz de estilo C utilizable a partir de código que no sea Objective-C (elija mejores nombres para sus archivos, he elegido estos nombres para verbosidad):
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);
}
No es necesario que la función contenedora esté en el mismo .m
archivo que la clase Objective-C, pero el archivo en el que existe debe compilarse como código Objective-C . El encabezado que declara la función contenedora debe incluirse en el código CPP y Objective-C.
(NOTA: si el archivo de implementación de Objective-C tiene la extensión ".m", no se vinculará bajo Xcode. La extensión ".mm" le dice a Xcode que espere una combinación de Objective-C y C ++, es decir, Objective-C ++. )
Puede implementar lo anterior de una manera orientada a objetos utilizando el lenguaje PIMPL . La implementación es solo ligeramente diferente. En resumen, coloca las funciones contenedoras (declaradas en "MyObject-C-Interface.h") dentro de una clase con un puntero vacío (privado) a una instancia de 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
Observe que los métodos de contenedor ya no requieren el puntero vacío a una instancia de MyClass; ahora es un miembro privado de MyClassImpl. El método init se utiliza para crear una instancia de 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
Observe que MyClass se crea una instancia con una llamada a MyClassImpl :: init. Puede crear una instancia de MyClass en el constructor de MyClassImpl, pero eso generalmente no es una buena idea. La instancia de MyClass se destruye del destructor de MyClassImpl. Al igual que con la implementación de estilo C, los métodos de contenedor simplemente se remiten a los métodos respectivos de 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." );
}
}
Ahora accede a las llamadas a MyClass a través de una implementación privada de MyClassImpl. Este enfoque puede resultar ventajoso si está desarrollando una aplicación portátil; simplemente podría cambiar la implementación de MyClass por una específica para la otra plataforma ... pero honestamente, si esta es una mejor implementación es más una cuestión de gustos y necesidades.
extern "C"
antes delint MyObjectDoSomethingWith
Puede compilar su código como Objective-C ++; la forma más sencilla es cambiar el nombre de su .cpp a .mm. Luego se compilará correctamente si lo incluye
EAGLView.h
(recibía tantos errores porque el compilador de C ++ no entendía ninguna de las palabras clave específicas de Objective-C), y puede (en su mayor parte) mezclar Objective-C y C ++ como quiera me gusta.fuente
La solución más sencilla es simplemente decirle a Xcode que compile todo como Objective C ++.
Establezca la configuración de su proyecto o destino para Compilar fuentes como para Objective C ++ y vuelva a compilar.
Entonces puede usar C ++ u Objective C en todas partes, por ejemplo:
Esto tiene el mismo efecto que cambiar el nombre de todos sus archivos de origen de .cpp o .m a .mm.
Hay dos desventajas menores en esto: clang no puede analizar el código fuente de C ++; algún código C relativamente extraño no se compila en C ++.
fuente
Paso 1
Cree un archivo objetivo c (archivo .m) y su archivo de encabezado correspondiente.
// Archivo de encabezado (lo llamamos "ObjCFunc.h")
// Archivo de objetivo C correspondiente (lo llamamos "ObjCFunc.m")
Paso 2
¡Ahora implementaremos una función c ++ para llamar a la función objetivo c que acabamos de crear! Entonces, para eso, definiremos un archivo .mm y su archivo de encabezado correspondiente (el archivo ". Mm" se usará aquí porque podremos usar codificación Objective C y C ++ en el archivo)
// Archivo de encabezado (lo llamamos "ObjCCall.h")
// Archivo Objective C ++ correspondiente (lo llamamos "ObjCCall.mm")
Paso 3
Llamar a la función c ++ (que en realidad llama al método objetivo c)
// Llamada final
¡Espero que esto funcione!
fuente
Necesita hacer que su archivo C ++ sea tratado como Objective-C ++. Puede hacer esto en xcode cambiando el nombre de foo.cpp a foo.mm (.mm es la extensión obj-c ++). Entonces, como han dicho otros, la sintaxis de mensajería estándar obj-c funcionará.
fuente
A veces, cambiar el nombre de .cpp a .mm no es una buena idea, especialmente cuando el proyecto es multiplataforma. En este caso, para el proyecto xcode, abro el archivo del proyecto xcode a través de TextEdit, encontré una cadena que contiene el archivo de interés, debería ser como:
y luego cambie el tipo de archivo de sourcecode.cpp.cpp a sourcecode.cpp.objcpp
Es equivalente a cambiar el nombre de .cpp a .mm
fuente
Además, puede llamar al tiempo de ejecución de Objective-C para llamar al método.
fuente
La respuesta de @ DawidDrozd anterior es excelente.
Yo agregaría un punto. Las versiones recientes del compilador de Clang se quejan de que se requiere una "transmisión de puente" si se intenta utilizar su código.
Esto parece razonable: usar un trampolín crea un error potencial: dado que las clases de Objective-C cuentan con referencias, si pasamos su dirección como un vacío *, corremos el riesgo de tener un puntero colgante si la clase se recolecta como basura mientras la devolución de llamada aún está activo.
Solución 1) Cocoa proporciona las funciones macro CFBridgingRetain y CFBridgingRelease que presumiblemente suman y restan uno del recuento de referencia del objeto Objective-C. Por lo tanto, debemos tener cuidado con las devoluciones de llamada múltiples, para lanzar la misma cantidad de veces que retenemos.
Solución 2) La alternativa es utilizar el equivalente de una referencia débil (es decir, sin cambios en el recuento de retención), sin ninguna seguridad adicional.
El lenguaje Objective-C proporciona el calificador de conversión __bridge para hacer esto (CFBridgingRetain y CFBridgingRelease parecen ser envoltorios finos de Cocoa sobre las construcciones del lenguaje Objective-C __bridge_retained y release respectivamente, pero Cocoa no parece tener un equivalente para __bridge).
Los cambios requeridos son:
fuente
self
al cierre, que podría quedar desactualizado. El otro punto es que no está claro cómo interactúa esto con el recuento automático de referencias y si el compilador puede averiguar qué está pasando. En la práctica, no logré crear una situación en la que cualquiera de las versiones fallara en un ejemplo de juguete simple de un módulo.Puede mezclar C ++ con Objectiv-C (Objective C ++). Escriba un método C ++ en su clase Objective C ++ que simplemente lo llame
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
y lo llame desde su C ++.No lo he probado antes, pero inténtalo y comparte los resultados con nosotros.
fuente