如何处理来自c++的objective-c委托?

时间:2022-09-07 08:08:56

Short version: I have a Qt/C++ to which I am having to add a limited amount of Cocoa/Objective-C code. I have changed the .cpp file to a .mm file and added the objective-c code/objects to said file, and it compiles and works. I now need a delegate for one of the objects I created- a NSPopUpButton (or, rather, the menu thereof) to be exact - and I'm stuck. How can I add a delegate for this object?

简短的版本:我有一个Qt/ c++,我需要添加少量Cocoa/Objective-C代码。我已经将.cpp文件更改为.mm文件,并将objective-c代码/对象添加到该文件中,它将编译并工作。我现在需要为我创建的其中一个对象创建一个委托——一个NSPopUpButton(或者,更确切地说,是它的菜单)——我被卡住了。如何为该对象添加委托?

Details: Files in question:

细节:文件的问题:

reportwindow.h, reportwindow.cpp RENAMED TO reportwindow.mm -These are the files containing my original C++ implementation plus some objective-c code (open a NSSavePanel containing a NSPopUpButton). reportwindow.h is additionally included in a .cpp file, if that makes a difference.

reportwindow。h,reportwindow。cpp reportwindow重命名。mm -这些文件包含我最初的c++实现和一些objective-c代码(打开一个包含NSPopUpButton的NSSavePanel)。reportwindow。h被另外包含在.cpp文件中,如果这有什么不同的话。

menuHandler.h, menuHandler.mm -these files contain a (currently empty) objective-c class that I was intending to use as a delegate

menuHandler。h,menuHandler。mm -这些文件包含一个(当前为空的)objective-c类,我打算将其用作委托

My first thought was that I could simply make the C++ class the delegate, but this obviously doesn't work as straight C++ doesn't understand delegation. I then thought I'd make a separate objective-c class as a NSMenuDelegate and add an instance of it as a member object to my C++ class. As I have been able to add other objective-c objects as members, I figured this should work. However, as soon as I included the header for my new objective-c class in the C++ class header file, I got several hundred errors about "expected unqualified-id before '@' token" -from the apple header files (NSValue.h, NSObject.h, etc) So apparently that didn't work, at least not as-is. I get the same result when including ANY cocoa header in my class header file.

我的第一个想法是,我可以简单地将c++类作为委托,但这显然不能作为直接的c++不理解委托。然后我想我应该创建一个单独的objective-c类作为NSMenuDelegate,并将它的实例作为成员对象添加到我的c++类中。由于我能够将其他objective-c对象添加为成员,所以我认为这应该是可行的。但是,当我在c++类的头文件中包含新的objective-c类的头文件时,我从apple头文件(NSValue)中得到了数百个关于“在'@' token之前预期的不限定id”的错误。h,NSObject。很明显,这是行不通的,至少现在不行。当在类头文件中包含任何cocoa头时,我都会得到相同的结果。

I then thought I'd try a forward-declaration of the objective-c class (that is how I got the other objective-c objects working). however, this didn't work either- if I declare it as "class myClassName" I get an error about re-defining the class as a different type of symbol (presumably c++ class vs objective-c protocol). If I try to forward declare it as @protocol myClassName, I get an error about "expected unqualified-id before '@' token". So how can I make this work?

然后我想尝试一个objective-c类的前向声明(这就是我让其他objective-c对象工作的方式)。然而,这也不起作用——如果我将它声明为“myClassName”,我就会得到一个错误,即将类重新定义为不同类型的符号(假设是c++类vs objective-c协议)。如果我试图将其声明为@protocol classmyname,则会得到一个关于“在'@' token之前预期的不限定id”的错误。那么我该怎么做呢?

4 个解决方案

#1


10  

Ok to answer your question:

好回答你的问题:

reportwindow.h is additionally included in a .cpp file, if that makes a difference.

reportwindow。h被另外包含在.cpp文件中,如果这有什么不同的话。

It does make a difference. Any compilation unit (cpp file in this case) that is touching Objective-C code has to be renamed to .mm or .m. Including the header that in turn is including Objective-C stuff in a C++ file will lead to the problem that the C++ compiler sees Objective-C code which it cannot handle.

这是有区别的。任何涉及Objective-C代码的编译单元(本例中为cpp文件)都必须重命名为.mm或.m。在c++文件中包含Objective-C内容的头会导致c++编译器看到它无法处理的Objective-C代码的问题。

Renaming the cpp file to mm will select the Objective-C option during compilation (which isn't when the file is named cpp or c) and hence allow to compile stuff with the Objective-C tokens (mainly "@" in your case).

将cpp文件重命名为mm将在编译过程中选择Objective-C选项(当文件命名为cpp或c时不是),因此允许使用Objective-C令牌(主要是“@”)编译内容。

An alternative would be not to include the Objective-C delegate class to your C++ class but rather include a pointer to your C++ class within the Objective-C delegate (i.e. implement it the other way around). This way you could arrange things such that the Objective-C code isn't touching the C++ code.

另一种方法是不将Objective-C的delegate类包含到c++类中,而是在Objective-C委托中包含一个指向c++类的指针(也就是说,将它反过来执行)。通过这种方式,您可以安排一些事情,使Objective-C代码不会触及c++代码。

Edit: Actually, I'd prefer the second suggestion. Here is an example:

编辑:事实上,我更喜欢第二个建议。这是一个例子:

DelegateClass.h:

DelegateClass.h:

class MyCPPClassHandlingStuff;

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

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

- (void) theDelegateProtocolMethod;

@end

DelegateClass.mm

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

And well the MyCPPClassHandlingStuff.h:

和MyCPPClassHandlingStuff.h:

#ifndef __MyCPPClassHandlingStuff_H__
#define __MyCPPClassHandlingStuff_H__

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

#endif /* __MyCPPClassHandlingStuff_H__ */

MyCPPClassHandlingStuff can be initialized from Objective-C but you cannot initialise any Objective-C class from C++ code there. If you need to use Objective-C in your C++ code, you would have to compile it as Objective-C (i.e. use an .mm file). I leave the .cpp details as an exercise for the reader ;)

可以从Objective-C初始化mycppclasshandstuff,但是不能从c++代码初始化任何Objective-C类。如果您需要在c++代码中使用Objective-C,那么必须将其编译为Objective-C(即使用.mm文件)。我把。cpp细节留给读者作为练习;)

#2


0  

I then thought I'd try a forward-declaration of the objective-c class (that is how I got the other objective-c objects working). however, this didn't work either- if I declare it as "class myClassName" I get an error about re-defining the class as a different type of symbol (presumably c++ class vs objective-c protocol).

然后我想尝试一个objective-c类的前向声明(这就是我让其他objective-c对象工作的方式)。然而,这也不起作用——如果我将它声明为“myClassName”,我就会得到一个错误,即将类重新定义为不同类型的符号(假设是c++类vs objective-c协议)。

Why not forward-declare it as @class myClassName?

为什么不把它声明为@ myClassName呢?

#3


0  

Make an Objective-C class to satisfy the delegate protocol, and have it delegate to your C++ class. The problem is that the AppKit expects to talk to Objective-C objects, so you need a shim to delegate to your C++ objects. (Yes you can do some runtime abuse, defining an isa pointer in your C++ class to make it somewhat compatible with ObjC objects (to the point where you can send messages to C++ classes), but don't do that. It's nasty.)

创建一个Objective-C类来满足委托协议,并将其委托给c++类。问题是AppKit期望与Objective-C对象对话,所以需要一个shim来委托给c++对象。(是的,您可以做一些运行时滥用,在您的c++类中定义一个isa指针,以使它与ObjC对象有一定的兼容性(可以向c++类发送消息),但是不要这样做。这是令人讨厌的。)

So make a shim which is initialized with your C++ class, has that as an ivar. It should implement the delegate methods you're interested in, and pass those along to your C++ class in a manner that it can understand. Tada, done.

因此,用c++类初始化一个shim,它是一个ivar。它应该实现您感兴趣的委托方法,并以它能够理解的方式将这些方法传递给您的c++类。恩,做的。

#4


0  

There is some useful information on how to set up your headers so they can be used both from ObjC and C++ in Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link?

有一些关于如何设置头文件的有用信息,可以在ObjC和c++中使用,我可以在编译和链接中将c++主函数和类从Objective-C和/或C例程中分离出来吗?

#1


10  

Ok to answer your question:

好回答你的问题:

reportwindow.h is additionally included in a .cpp file, if that makes a difference.

reportwindow。h被另外包含在.cpp文件中,如果这有什么不同的话。

It does make a difference. Any compilation unit (cpp file in this case) that is touching Objective-C code has to be renamed to .mm or .m. Including the header that in turn is including Objective-C stuff in a C++ file will lead to the problem that the C++ compiler sees Objective-C code which it cannot handle.

这是有区别的。任何涉及Objective-C代码的编译单元(本例中为cpp文件)都必须重命名为.mm或.m。在c++文件中包含Objective-C内容的头会导致c++编译器看到它无法处理的Objective-C代码的问题。

Renaming the cpp file to mm will select the Objective-C option during compilation (which isn't when the file is named cpp or c) and hence allow to compile stuff with the Objective-C tokens (mainly "@" in your case).

将cpp文件重命名为mm将在编译过程中选择Objective-C选项(当文件命名为cpp或c时不是),因此允许使用Objective-C令牌(主要是“@”)编译内容。

An alternative would be not to include the Objective-C delegate class to your C++ class but rather include a pointer to your C++ class within the Objective-C delegate (i.e. implement it the other way around). This way you could arrange things such that the Objective-C code isn't touching the C++ code.

另一种方法是不将Objective-C的delegate类包含到c++类中,而是在Objective-C委托中包含一个指向c++类的指针(也就是说,将它反过来执行)。通过这种方式,您可以安排一些事情,使Objective-C代码不会触及c++代码。

Edit: Actually, I'd prefer the second suggestion. Here is an example:

编辑:事实上,我更喜欢第二个建议。这是一个例子:

DelegateClass.h:

DelegateClass.h:

class MyCPPClassHandlingStuff;

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

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

- (void) theDelegateProtocolMethod;

@end

DelegateClass.mm

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

And well the MyCPPClassHandlingStuff.h:

和MyCPPClassHandlingStuff.h:

#ifndef __MyCPPClassHandlingStuff_H__
#define __MyCPPClassHandlingStuff_H__

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

#endif /* __MyCPPClassHandlingStuff_H__ */

MyCPPClassHandlingStuff can be initialized from Objective-C but you cannot initialise any Objective-C class from C++ code there. If you need to use Objective-C in your C++ code, you would have to compile it as Objective-C (i.e. use an .mm file). I leave the .cpp details as an exercise for the reader ;)

可以从Objective-C初始化mycppclasshandstuff,但是不能从c++代码初始化任何Objective-C类。如果您需要在c++代码中使用Objective-C,那么必须将其编译为Objective-C(即使用.mm文件)。我把。cpp细节留给读者作为练习;)

#2


0  

I then thought I'd try a forward-declaration of the objective-c class (that is how I got the other objective-c objects working). however, this didn't work either- if I declare it as "class myClassName" I get an error about re-defining the class as a different type of symbol (presumably c++ class vs objective-c protocol).

然后我想尝试一个objective-c类的前向声明(这就是我让其他objective-c对象工作的方式)。然而,这也不起作用——如果我将它声明为“myClassName”,我就会得到一个错误,即将类重新定义为不同类型的符号(假设是c++类vs objective-c协议)。

Why not forward-declare it as @class myClassName?

为什么不把它声明为@ myClassName呢?

#3


0  

Make an Objective-C class to satisfy the delegate protocol, and have it delegate to your C++ class. The problem is that the AppKit expects to talk to Objective-C objects, so you need a shim to delegate to your C++ objects. (Yes you can do some runtime abuse, defining an isa pointer in your C++ class to make it somewhat compatible with ObjC objects (to the point where you can send messages to C++ classes), but don't do that. It's nasty.)

创建一个Objective-C类来满足委托协议,并将其委托给c++类。问题是AppKit期望与Objective-C对象对话,所以需要一个shim来委托给c++对象。(是的,您可以做一些运行时滥用,在您的c++类中定义一个isa指针,以使它与ObjC对象有一定的兼容性(可以向c++类发送消息),但是不要这样做。这是令人讨厌的。)

So make a shim which is initialized with your C++ class, has that as an ivar. It should implement the delegate methods you're interested in, and pass those along to your C++ class in a manner that it can understand. Tada, done.

因此,用c++类初始化一个shim,它是一个ivar。它应该实现您感兴趣的委托方法,并以它能够理解的方式将这些方法传递给您的c++类。恩,做的。

#4


0  

There is some useful information on how to set up your headers so they can be used both from ObjC and C++ in Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link?

有一些关于如何设置头文件的有用信息,可以在ObjC和c++中使用,我可以在编译和链接中将c++主函数和类从Objective-C和/或C例程中分离出来吗?