2009-06-29 15 views
5

Necesito mezclar Objective-C y C++. Me gustaría esconder todo el material de C++ dentro de una clase y mantener todos los demás simples Objective-C. El problema es que quiero tener algunas clases de C++ como variables de instancia. Esto significa que deben mencionarse en el archivo de encabezado, que se incluye en otras clases y C++ comienza a extenderse a toda la aplicación. La mejor solución que he podido encontrar hasta ahora se parece a esto:Clases de C++ como variables de instancia de una clase Objective-C

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

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

@end 

Esto funciona. El archivo de implementación tiene una extensión mm, por lo que se compila como Objective-C mezclado con C++, el #ifdef desbloquea las cosas de C++ y ahí vamos. Cuando alguna otra clase puramente Objective-C importa el encabezado, las cosas de C++ están ocultas y la clase no ve nada especial. Esto parece un truco, ¿hay una mejor solución?

+1

Es básicamente lo que he llegado con cuando tuve el mismo problema. Pero preste atención a su ifdef: tiene que insertar relleno para la rama que no sea de cpp. De lo contrario, el compilador no sabría el tamaño de sus objetos Foo. Si bien esto podría no afectar a las compilaciones de var de instancia no frágiles, definitivamente es un problema para los objetivos de estilo antiguo. –

+0

Copié el enfoque que describió anteriormente. Parecía bastante agradable y fácil, pero luego causó algunos problemas de corrupción de memoria loca: http://stackoverflow.com/questions/2458652/objective-c-insanity-simple-assignement-to-a-single-float-variable-results – morgancodes

Respuesta

8

Parece un uso clásico para una interfaz/protocolo @. Defina un protocolo objetivo-c para la API y luego proporcione una implementación de ese protocolo usando su clase Objective-C++. De esta forma, los clientes solo necesitan conocer el protocolo y no el encabezado de la implementación. Por lo tanto, dada la implementación original

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

} 

@end 

Yo definiría un protocolo

//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 

y modificar la declaración original de Foo a

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

@end 

código de cliente puede trabajar con el tipo id<IFoo> y no necesita para ser compilado como Objective-C++. Obviamente, puede pasar una instancia de Foo a estos clientes.

+0

Si la @interface Foo está en el archivo .h, ¿es posible prevenir la influencia de obj-C++? Si la @interface Foo está en un archivo .mm, ¿cómo puedo crear una instancia de ella? – Eonil

+1

Cualquier módulo que importe Foo.h tendrá que compilarse como Objective-C++, pero el código del cliente solo debe importar * solo * El encabezado IFoo para usar IFoo y, por lo tanto, solo puede ser Objective-C. Este es un patrón clásico de gestión de dependencia. –

+0

en su ejemplo, ¿cómo crearía una instancia de un nuevo Foo sin importar el encabezado? Lo primero que viene a la mente es una clase de fábrica Objective C++ que no importa y material C++ en su encabezado. Todo parece muy complicado. También existe este enfoque: http://stackoverflow.com/questions/2262011/adding-c-object-to-objective-c-class/2262395 pero no lo he hecho funcionar (ver http://stackoverflow.com/questions/2463970/trouble-using-opaque-pointers-in-objective-c) – morgancodes

1

¿Hay alguna razón particular por la que no puedes usar Objective C++ para todo? Simplemente cambie el compilador a Compilar fuentes como: Objetivo C++ (o cambie el nombre de todos sus archivos fuente de .cpp o .m a .mm). A continuación, puede entremezclar libremente su C++ y Objective C.

C++ empieza a propagarse a todo el aplicación

¿Qué problema es que hay con eso? Si su código de Objective C está haciendo solo código C/Objective C en general, entonces casi con certeza no se verá afectado por ser compilado como C++. No hay problemas apreciables de tamaño o velocidad de rendimiento.

Las dos únicas desventajas que he encontrado son: no puede (todavía) usar el analizador estático clang para analizarse en C++; Cierto código C (relativamente extraño) no funcionará en C++, lo que a veces es un problema cuando se usa código C de terceros.

+0

El único problema es que no me siento cómodo con C++ y tenía miedo de que haya algunas diferencias sutiles que podría conducir a errores. Me gusta la idea de que C++ esté encapsulado solo en la clase que realmente lo necesita. Pero gracias, esta ciertamente es una solución. – zoul

0

Es posible que tenga problemas para hacer esto: por lo que recuerdo de ObjectiveC++, es posible que el constructor y el destructor de su objeto C++ adjunto no sean invocados.

3

También me encontré con este problema recientemente. En mi caso, un protocolo fue excesivo. Solo necesitaba mantener un puntero a un objeto de acceso a datos que resultó ser un objeto C++.

Lo que hice fue declarar la clase con una variable de instancia void * y emitirla cuando la uso en los métodos de instancia.

Esto es un poco hack-y, pero conceptualmente, es muy similar a lo que es el tipo Objective-C id.

0

no hace esto

Si ifdef a cabo una variable de instancia, que dará a los dos diseños variables instancia independiente para esta clase. Obtendrá smashers de memoria aleatoria por todas partes porque la memoria asignada para el objeto en la mitad de los casos será demasiado corta. En lugar de ifdefing a cabo la variable de instancia, con visión de declarar su tipo como

struct CPPClass; 

y tener un puntero a él en el Ivar, a continuación, en sus init/dealloc métodos llaman nuevos/borrar para crear el objeto. Si tiene varios objetos, puede crear una estructura para contener todos los ivars de C++ directamente y luego simplemente crear/eliminar esa estructura.

ver este hilo para más detalle y más enlaces a la información, incluyendo un podcast que habla largo y tendido sobre ObjC++: Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link?

+0

En C, un tipo de estructura debería denominarse 'struct CPPClass', no' CPPClass', por lo que tendrían que cambiar eso también. – newacct

+0

En la declaración de ivar, sí, buena captura. Para C++ struct Foo y Foo son los mismos, por lo que solo es necesario en el encabezado. Usualmente escribo struct delante del nombre de la clase donde sea que lo use, no necesitas una declaración de estructura separada como mencioné aquí por sí misma. – uliwitness

Cuestiones relacionadas