2010-02-09 7 views
6

Tengo una pequeña aplicación C++ que importé clases Objective-C. Funciona como archivos Objective-C++, .mm, pero cualquier archivo C++ que incluya un encabezado que pueda incluir un encabezado Objective-C debe renombrarse a una extensión .mm para los controladores GCC adecuados.¿Puedo separar la función principal de C++ y las clases de las rutinas Objective-C y/o C en compilación y enlace?

¿Hay alguna manera de escribir un contenedor puramente C++ para clases Objective-C o puedo separar los objetos Objective-C de alguna manera y simplemente vincularlos por separado? Quizás incluso si las clases de Objective-C se convirtieran en una pequeña biblioteca, podría volver a enlazar estáticamente en tiempo de compilación.

El problema es que este código es multiplataforma y es más difícil de compilar en sistemas que normalmente no usan Objective-C (es decir, no Mac). Aunque los comandos del preprocesador restringen cualquier implementación del código Objective-C en Windows o Linux, el código original aún tiene extensiones .mm y GCC aún trata el código como Objective-C++.

Respuesta

3

Por lo general, simplemente ajusta sus clases de Objective-C con las clases de C++, p. Ej. usando opaque pointers y reenviando llamadas a métodos C++ a métodos Objective-C.

De esta forma, sus fuentes portátiles de C++ nunca deben ver ningún Objective-C, y lo ideal es que solo tengan que intercambiar los archivos de implementación de los contenedores en diferentes plataformas.

Ejemplo:

// c++ header: 
class Wrapper { 
    struct Opaque; 
    Opaque* opaque; 
    // ... 
public: 
    void f(); 
}; 

// Objective-C++ source on Mac: 
struct Wrapper::Opaque { 
    id contained; 
    // ... 
}; 

void Wrapper::f() { 
    [opaque->contained f]; 
} 

// ... 
+0

entonces ¿struct Wrapper :: Opaque incluiría 'OBJCClass * name = [[OBJCClass alloc] init]' y Wrapper :: f() llamaría a [name f] si estuviera tan vinculado? –

+0

Sí, podría asignar e inicializar la clase Objective-C contenida en el constructor 'Wrapper' o' Opaque', lo que más le convenga, y los métodos de la clase C++ reenviarían las llamadas a su clase Objective-C. –

2

Sí, eso es posible sin más, en ambos sentidos, si usted sabe algunos trucos:

1) El tipo de "id" es en realidad se define en una cabecera de C llana. Así que usted puede hacer lo siguiente:

En su cabecera:

#include <objc/objc.h> 

class MyWindow 
{ 
public: 
    MyWindow(); 
    ~MyWindow(); 
protected: 
    id  mCocoaWindow; 
}; 

En su aplicación (.mm):

#include "MyWindow.h" 
#include <Cocoa/Cocoa.h> 

MyWindow::MyWindow() 
{ 
    mCocoaWindow = [[NSWindow alloc] init]; 
} 

MyWindow::~MyWindow() 
{ 
    [mCocoaWindow release]; 
    mCocoaWindow = nil; 
} 

2) Hay dos constantes del preprocesador que puede utilizar para excluir C++ código/ObjC específico cuando un archivo de origen que incluye ese es uno de los dos, pero no ObjC++:

#if __OBJC__ 
// ObjC code goes here. 
#endif /* __OBJC__*/ 

#if __cplusplus 
// C++ code goes here. 
#endif 

Solo tenga cuidado, no puede simplemente agregar/eliminar ivars o métodos virtuales con un #ifdef, que creará dos clases con diferentes diseños de memoria y hará que su aplicación falle de maneras muy extrañas.

3) Se puede utilizar un puntero a una estructura sin declarar su contenido:

En su cabecera:

@interface MyCppObjectWrapper : NSObject 
{ 
    struct MyCppObjectWrapperIVars *ivars; // This is straight ObjC, no ++. 
} 

@end 

En el archivo de aplicación (.mm):

struct MyCppObjectWrapperIVars 
{ 
    std::string myCppString1; 
    std::string myCppString2; 
    std::string myCppString3; 
}; 

@implementation MyCppObjectWrapper 

-(id) init 
{ 
    if((self = [super init])) 
    { 
     ivars = new MyCppObjectWrapperIVars; 
    } 

    return self; 
} 

-(void) dealloc 
{ 
    delete ivars; 
    ivars = NULL; 

    [super dealloc]; 
} 

@end 

Esto hará que su encabezado sea simple C u ObjC, mientras que su archivo de implementación obtiene constructores/destructores de todos los ivars llamados sin que tenga que crear/eliminar cada uno como un objeto en el ap.

Esto es solo el lado Mac de las cosas, pero esto significaría que podría mantener las cosas ObjC fuera de sus encabezados, o al menos compilarlo cuando se utiliza desde archivos de cliente multiplataforma de la implementación Mac de su Capa de portabilidad C++.

Cuestiones relacionadas