如何处理来自 C++ 的 Objective-C 委托?

发布于 2024-12-11 14:00:37 字数 1017 浏览 0 评论 0 原文

简短版本:我有一个 Qt/C++,我必须向其中添加有限数量的 Cocoa/Objective-C 代码。我已将 .cpp 文件更改为 .mm 文件,并将 Objective-C 代码/对象添加到该文件中,它可以编译并运行。我现在需要我创建的对象之一的委托 - 准确地说是 NSPopUpButton (或者更确切地说,其菜单) - 但我陷入了困境。如何为该对象添加委托?

细节: 有问题的文件:

reportwindow.h、reportwindow.cpp 重命名为 reportwindow.mm -这些文件包含我的原始 C++ 实现以及一些 Objective-C 代码(打开包含 NSPopUpButton 的 NSSavePanel)。如果有影响的话,reportwindow.h 还包含在 .cpp 文件中。

菜单处理程序.h,菜单处理程序.mm -这些文件包含一个(当前为空的)objective-c 类,我打算将其用作委托

我的第一个想法是我可以简单地将 C++ 类作为委托,但这显然不起作用,因为直接 C++ 不起作用了解委托。然后我想我应该创建一个单独的 Objective-C 类作为 NSMenuDelegate 并将其实例作为成员对象添加到我的 C++ 类中。由于我已经能够添加其他 Objective-C 对象作为成员,我认为这应该可行。然而,一旦我将新的 Objective-C 类的标头包含在 C++ 类头文件中,我就会收到数百个关于“在 '@' 标记之前预期不合格的 id”的错误 - 来自苹果头文件 (NSValue.h) 、 NSObject.h 等)显然这不起作用,至少不能按原样起作用。当我的类头文件中包含任何可可头时,我得到相同的结果。

然后我想我应该尝试对 Objective-C 类进行前向声明(这就是我如何让其他 Objective-C 对象工作的)。但是,这也不起作用 - 如果我将其声明为“class myClassName”,我会收到有关将类重新定义为不同类型符号的错误(大概是 c++ 类与 Objective-c 协议)。如果我尝试将其转发声明为 @protocol myClassName,则会收到有关“‘@’令牌之前预期不合格的 id”的错误。那么我怎样才能做到这一点呢?

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?

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.

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

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.

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

衣神在巴黎 2024-12-18 14:00:37

好的回答你的问题:

reportwindow.h 另外包含在 .cpp 文件中,如果这样的话
有区别。

它确实有所作为。任何涉及 Objective-C 代码的编译单元(在本例中为 cpp 文件)都必须重命名为 .mm 或 .m。包含标头反过来又将 Objective-C 内容包含在 C++ 文件中,将导致 C++ 编译器看到它无法处理的 Objective-C 代码的问题。

将 cpp 文件重命名为 mm 将在编译期间选择 Objective-C 选项(文件名为 cpp 或 c 时不会选择),因此允许使用 Objective-C 标记(在您的情况下主要是“@”)编译内容。

另一种方法是不将 Objective-C 委托类包含到 C++ 类中,而是在 Objective-C 委托中包含指向 C++ 类的指针(即以相反的方式实现它)。通过这种方式,您可以安排一些事情,使 Objective-C 代码不接触 C++ 代码。

编辑:实际上,我更喜欢第二个建议。下面是一个示例:

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

以及 MyCPPClassHandlingStuff.h:

#ifndef __MyCPPClassHandlingStuff_H__
#define __MyCPPClassHandlingStuff_H__

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

#endif /* __MyCPPClassHandlingStuff_H__ */

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

Ok to answer your question:

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

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.

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).

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.

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

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

And well the 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 ;)

终难愈 2024-12-18 14:00:37

创建一个 Objective-C 类来满足委托协议,并将其委托给您的 C++ 类。问题是 AppKit 期望与 Objective-C 对象对话,因此您需要一个垫片来委托给您的 C++ 对象。 (是的,你可以进行一些运行时滥用,在 C++ 类中定义一个 isa 指针,使其与 ObjC 对象在某种程度上兼容(达到可以向 C++ 类发送消息的程度),但不要这样做。这很糟糕。)

因此,制作一个用 C++ 类初始化的垫片,并将其作为 ivar。它应该实现您感兴趣的委托方法,并以它可以理解的方式将这些方法传递给您的 C++ 类。田田,完成了。

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.)

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.

丶视觉 2024-12-18 14:00:37

然后我想我应该尝试对 Objective-C 类进行前向声明(这就是我如何让其他 Objective-C 对象工作的)。但是,这也不起作用 - 如果我将其声明为“class myClassName”,我会收到有关将类重新定义为不同类型符号的错误(大概是 c++ 类与 Objective-c 协议)。

为什么不将其前向声明为@class myClassName

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).

Why not forward-declare it as @class myClassName?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文