2010-11-17 9 views
8

Estoy tratando de hacer un contenedor en Objective-C, así que no tengo que escribir C++ fuera de las clases de la biblioteca.Hacer un contenedor Objective-C para una biblioteca en C++

El archivo principal de la biblioteca es LLAHProcessor.h .cpp

Mi envoltura es LLAHProcessorWrapper.h .mm

Se compila bien, pero cuando agrego LLAHProcessorWrapper a otra clase, (Digamos que un UIView) como una variable miembro de recibo cientos de errores , como:

#include <map> : Map no such a file or directory 

y en cada clase de C++/struct:

Expected specifier-qualifier list before ClassName 

Es como el compilador no reconoce el código de C++.

Me pregunto qué es lo que echo de menos aquí. Tiene que ser algo con el hecho de que agregué esto a Propiedades de Xcode Target:?

Other Link Flags : -lstdc++ -lz 

O tal vez necesito agregar nuevas banderas aquí?

Gracias de antemano

+1

Es fundamental que 'LLAHProcessorWrapper.h' no contenga ningún código C++ en absoluto. 'LLAHProcessor.h' debe importarse en su' .mm'. archivo, no en el archivo '.h'. ¿Hiciste eso? –

+0

También tiene archivos .m en el proyecto? –

+0

@Chris Tengo muchos archivos .m. Este es un programa bastante grande. – nacho4d

Respuesta

6

Su problema es que los archivos .m se compilan como C en lugar de C++. Por lo tanto, cuando el compilador se encuentre con cualquier C++ incluso en un archivo de encabezado mientras compila un archivo .m, se eliminará.

Sin duda tiene que poner C++ en su archivo de encabezado porque su objeto Objective C envuelve un objeto C++, pero hay formas de evitar esto. Una forma sería usar un puntero al objeto C++ y usar el útil preprocesador definir __cplusplus que se define para C++ (y Objective-C++) pero no para C (u Objective-C), p.

// LLAHProcessorWrapper.h 

#if defined __cplusplus 
class MyCPPClass; // forward class declaration 
#else 
typedef struct MyCPPClass MyCPPClass; // forward struct declaration 
#endif 

@interface MyOCClass : NSObject 
{ 
@private 
    MyCPPClass* cppObject; 
} 

// methods and properties 

@end 

Dado que nunca eliminar la referencia de los miembros de la cppObject fuera del archivo .mm no importa que nunca se proporciona una definición completa de la estructura.

Usted new y delete el puntero en -init y -dealloc respectivamente. Debería incluir la declaración de clase C++ completa en LLAHProcessorWrapper.mm.

+1

En caso de que esto sea de utilidad para cualquier persona: quedé atrapado al tener todavía '#include" MyCPPClass.h "' en el 'LLAHProcessorWrapper.h'. Debería estar en el 'LLAHProcessorWrapper.mm' en su lugar. – Ross

+0

Supongo que ahora podemos usar extensiones de clase también? tal vez un mejor enfoque? – Ahmed

4

Todo lo que necesita hacer es crear un .mm como lo han hecho, y el compilador debe tener cuidado de todo.

La advertencia es que no es seguro tener algo relacionado con C++ en los archivos .h, ya que pueden/serán importados por otros archivos Objective-C solamente, y luego todo se rompe. El principal problema aquí es que no puede definir tipos de C++ directamente como variables de instancia para su clase de contenedor Objective-C, a menos que cada archivo .m se renombre como un archivo Objective-C++ .mm.

La solución es definir las variables de instancia como void* en el archivo de encabezado y acceder a ellas con el tipo de conversión del archivo de implementación. La solución más fácil para esto sería acceder a la variable de instancia utilizando una propiedad privada que a la conversión de tipo para usted.

Ejemplo código suponiendo Foo es una clase de C++ se define en Foo.h:

// FooWrapper.h 
#import <Foundation/Foundation.h> 

@interface FooWrapper : NSObject { 
@private 
    void* foo; 
} 
// Actual wrapper API for Foo… 
@end 


// FooWrapper.mm 
#import "FooWrapper.h" 
#include <map> 
#include "Foo.h" 

@interface FooWrapper() 
@property(nonatomic, assign) Foo* foo; 
@end 

@implementation FooWrapper 
-(Foo*)foo { 
    return (Foo*)foo; 
} 
-(void)setFoo:(Foo*)aFoo { 
    foo = (void*)aFoo; 
} 
// Implementation of actual API for Foo… 
@end 
0

En cualquier archivo de cabecera (.h) en el que desea para referirse a LLAHProcessorWrapper, de uso hacia adelante definiciones de clase en lugar de importaciones, así:

@class LLAHProcessorWrapper; 
@interface SomeView : UIView { 
    LLAHProcessorWrapper *wrapper; 
} 

y asegúrese de que el archivo de aplicación correspondiente tiene #include LLAHProcessorWrapper.h o #import LLAHProcessorWrapper.h.

Cualquier archivo de implementación en el que #include o #import su cabecera debe tener .mm como su sufijo si LLAHProcessorWrapper.ho cualquier otra cosa en todo el árbol incluye tiene ninguna sintaxis de C++ en absoluto. De esta manera, tener un archivo .mm tiene la tendencia a significar que grandes porciones de una base de código deben tener sus archivos renombrados a .mm.

Cuestiones relacionadas