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 .marchivo 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.