简短版本:我有一个 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?
发布评论
评论(4)
好的回答你的问题:
它确实有所作为。任何涉及 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:
DelegateClass.mm
以及 MyCPPClassHandlingStuff.h:
MyCPPClassHandlingStuff 可以从 Objective-C 初始化,但不能从那里的 C++ 代码初始化任何 Objective-C 类。如果您需要在 C++ 代码中使用 Objective-C,则必须将其编译为 Objective-C(即使用 .mm 文件)。我将 .cpp 详细信息留给读者作为练习;)
Ok to answer your question:
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:
DelegateClass.mm
And well the 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 类来满足委托协议,并将其委托给您的 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.
为什么不将其前向声明为
@class myClassName
?Why not forward-declare it as
@class myClassName
?我可以在编译和链接时将 C++ 主函数和类与 Objective-C 和/或 C 例程分开吗?
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?