2011-10-25 7 views
5

Versión corta: Tengo un Qt/C++ al que tengo que agregar una cantidad limitada de código Cocoa/Objective-C. Cambié el archivo .cpp a un archivo .mm y agregué el código/objetos objetivo-c a dicho archivo, y se compila y funciona. Ahora necesito un delegado para uno de los objetos que creé, un NSPopUpButton (o, más bien, el menú del mismo) para ser exactos, y estoy atascado. ¿Cómo puedo agregar un delegado para este objeto?¿Cómo manejar la delegación de Object-c de C++?

Detalles: archivos en cuestión:

reportwindow.h, reportwindow.cpp renombrado a reportwindow.mm -Estos son los archivos que contienen mi original C++ aplicación, además de algo de código Objective-C (abrir una NSSavePanel que contiene una NSPopUpButton). reportwindow.h también se incluye en un archivo .cpp, si eso hace la diferencia.

menuHandler.h, menuHandler.mm archivos contienen una -estos (VACIO) Clase de Objective-C que tenía la intención de utilizar como delegado

Mi primer pensamiento fue que yo podría simplemente hacer que la clase de C++ el delegado, pero obviamente esto no funciona, ya que C++ no comprende la delegación. Luego pensé en crear una clase object-c separada como NSMenuDelegate y agregar una instancia de ella como objeto miembro a mi clase C++. Como pude agregar otros objetos Object-C como miembros, pensé que esto debería funcionar. Sin embargo, tan pronto como incluí el encabezado para mi nueva clase object-c en el archivo de encabezado de clase C++, recibí varios cientos de errores sobre "id-esperado no esperado antes de '@' token" -de los archivos de encabezado de apple (NSValue.h , NSObject.h, etc.) Entonces, aparentemente, eso no funcionó, al menos no como está. Obtengo el mismo resultado al incluir CUALQUIER cabecera de cacao en el archivo de encabezado de mi clase.

Entonces pensé en intentar una declaración directa de la clase objetivo-c (así es como obtuve el funcionamiento de los otros objetos object-c). sin embargo, esto tampoco funcionó: si lo declaro como "clase myClassName", aparece un error sobre la redefinición de la clase como un tipo diferente de símbolo (presumiblemente clase c + + vs protocolo objetivo-c). Si intento reenviarlo, lo declaro como @protocol myClassName, me sale un error sobre "esperado ID no calificado antes de '@' token". Entonces, ¿cómo puedo hacer que esto funcione?

+0

¿Ha cambiado el nombre de ese archivo CPP específico para mm? –

+0

El asociado con el encabezado en cuestión, sí. – ibrewster

+0

La segunda forma es el camino a seguir, y probablemente el único. No deberías rendirte después del primer intento fallido. Proporcione más detalles, lo que incluye qué, puede haber solo más archivos .cpp que incluyen 'reportwindow.h'. – hamstergene

Respuesta

10

Ok Para responder a su pregunta:

reportwindow.h se incluye, además, en un archivo .cpp, si eso tiene una diferencia.

Hace la diferencia. Cualquier unidad de compilación (archivo cpp en este caso) que esté tocando código Objective-C debe cambiarse a .mm o .m. Incluir el encabezado que a su vez incluye las cosas de Objective-C en un archivo C++ dará lugar al problema de que el compilador C++ vea el código Objective-C que no puede manejar.

Cambiar el nombre del archivo cpp a mm seleccionará la opción Objective-C durante la compilación (que no es cuando el archivo se llama cpp o c) y permitirá compilar cosas con los tokens Objective-C (principalmente "@" en tu caso).

Una alternativa sería no incluir la clase de delegado Objective-C en su clase C++, sino incluir un puntero a su clase C++ dentro del delegado Objective-C (es decir, implementarlo al revés). De esta forma, podría organizar cosas tales que el código Objective-C no esté tocando el código C++.

Editar: En realidad, preferiría la segunda sugerencia. Aquí hay un ejemplo:

DelegateClass.h:

class MyCPPClassHandlingStuff; 

@interface MyDelegateObject : NSObject <SomeDelegateProtocol> { 
    MyCPPClassHandlingStuff *m_handlerInstance; 
} 

- (id) initWithCPPInstance:(MyCPPClassHandlingStuff*)cppInstance; 

- (void) theDelegateProtocolMethod; 

@end 

DelegateClass.mm

#include "MyCPPClassHandlingStuff.h" 

@implementation MyDelegateObject 

- (id) initWithCPPInstance:(MyCPPClassHandlingStuff*)cppInstance 
{ 
    self = [super init]; 
    if (self) { 
    m_handlerInstance = cppInstance; 
    } 
    return self; 
} 

- (void) theDelegateProtocolMethod 
{ 
    if (m_handlerInstance) 
    m_handlerInstance->handleDelegateMethod(); 
} 

@end 

Y así la MyCPPClassHandlingStuff.h:

#ifndef __MyCPPClassHandlingStuff_H__ 
#define __MyCPPClassHandlingStuff_H__ 

class MyCPPClassHandlingStuff 
{ 
public: 
    MyCPPClassHandlingStuff(); 
    void handleDelegateMethod(); 
}; 

#endif /* __MyCPPClassHandlingStuff_H__ */ 

MyCPPClassHandlingStuff se puede inicializar de Objective-C pero no se puede inicializar cualquier clase de Objective-C desde el código C++ allí. Si necesita usar Objective-C en su código C++, debería compilarlo como Objective-C (es decir, usar un archivo .mm). Dejo los detalles .cpp como un ejercicio para el lector;)

+1

¿Podría darnos una idea de la implementación de .cpp también? P ¿Cómo inicializará MyDelegateObject? cpp. – Aalok

0

Luego pensé en intentar una declaración directa de la clase objetivo-c (así es como obtuve los otros objetivos-objetos c trabajando) sin embargo, esto tampoco funcionó: si lo declaro como "clase myClassName", aparece un error sobre la redefinición de la clase como un tipo diferente de símbolo (presumiblemente clase c + + vs protocolo objetivo-c).

¿Por qué no reenviar-declararlo como @class myClassName?

+0

Lo intenté, me dio errores sobre "id esperado no calificado antes del símbolo '@'". Resulta que Qt estaba generando un archivo .cpp moc_ que estaba tirando cosas. Renombrar eso a .mm solucionó el problema. – ibrewster

0

Haz una clase Objective-C para satisfacer el protocolo de delegado y haz que delegue en tu clase de C++. El problema es que AppKit espera hablar con objetos Objective-C, por lo que necesita un ajuste para delegar en sus objetos C++. (Sí, puedes abusar del tiempo de ejecución, definir un puntero isa en tu clase C++ para que sea algo compatible con objetos ObjC (hasta el punto en que puedes enviar mensajes a clases C++), pero no lo hagas. Es desagradable.)

Así que haga un calce que se inicializa con su clase C++, tiene eso como un ivar. Debe implementar los métodos de delegado que le interesan y pasarlos a su clase de C++ de una manera que pueda entender. Tada, hecho.

Cuestiones relacionadas