简短版本:我有一个Qt / C ++,我不得不添加有限数量的Cocoa / Objective-C代码。我已将.cpp文件更改为.mm文件,并将objective-c代码/对象添加到所述文件中,并进行编译和工作。我现在需要为我创建的一个对象 - 一个NSPopUpButton(或者更确切地说,它的菜单)代表一个委托 - 而且我被卡住了。如何为此对象添加委托?
详细说明: 有问题的文件:
reportwindow.h,reportwindow.cpp重新命名为reportwindow.mm - 这些是包含我原始C ++实现的文件加上一些Objective-c代码(打开包含NSPopUpButton的NSSavePanel)。 reportwindow.h还包含在.cpp文件中,如果这有所不同。
menuHandler.h,menuHandler.mm 这些文件包含一个(当前为空)objective-c类,我打算将其用作委托
我的第一个想法是,我可以简单地将C ++类作为委托,但这显然不起作用,因为直接的C ++不理解委托。然后我想我将一个单独的objective-c类作为NSMenuDelegate,并将它的一个实例添加为我的C ++类的成员对象。由于我已经能够添加其他objective-c对象作为成员,我认为这应该工作。但是,只要我在C ++类头文件中包含了我的新objective-c类的头文件,就会从apple头文件(NSValue.h)中获得几百个关于“'''令牌之前的未定义id'的错误”。 ,NSObject.h等)显然这不起作用,至少不是原样。在我的类头文件中包含任何cocoa头时,我得到相同的结果。
然后我想我会尝试使用objective-c类的前向声明(这就是我让其他Objective-c对象工作的方式)。但是,这也没有用 - 如果我将其声明为“class myClassName”,我会收到一个关于将类重新定义为不同类型符号的错误(可能是c ++类vs objective-c协议)。如果我尝试将其声明为@protocol myClassName,我会收到关于“'''令牌之前的预期unqualified-id”的错误。那么我怎样才能做到这一点呢?
答案 0 :(得分:11)
好的回答你的问题:
reportwindow.h还包含在.cpp文件中,如果这样做的话 差异。
确实有所作为。触摸Objective-C代码的任何编译单元(在本例中为cpp文件)都必须重命名为.mm或.m。包括反过来包含C ++文件中的Objective-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的详细信息留作读者的练习;)
答案 1 :(得分:1)
创建一个Objective-C类来满足委托协议,并让它委托给您的C ++类。问题是AppKit期望与Objective-C对象交谈,因此您需要一个垫片来委托您的C ++对象。 (是的,你可以做一些运行时滥用,在你的C ++类中定义一个isa指针,使它与ObjC对象有点兼容(到你可以向C ++类发送消息的那一点),但不要这样做。这很讨厌。)
所以制作一个用你的C ++类初始化的垫片,把它作为一个ivar。它应该实现您感兴趣的委托方法,并以它能够理解的方式将它们传递给您的C ++类。田田,完成了。
答案 2 :(得分:0)
然后我想我会尝试使用objective-c类的前向声明(这就是我让其他Objective-c对象工作的方式)。但是,这也没有用 - 如果我将其声明为“class myClassName”,我会收到一个关于将类重新定义为不同类型符号的错误(可能是c ++类vs objective-c协议)。
为什么不将其声明为@class myClassName
?
答案 3 :(得分:0)
有一些关于如何设置标题的有用信息,以便可以在Can I separate C++ main function and classes from Objective-C and/or C routines at compile and link?中使用ObjC和C ++