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

时间:2011-10-25 16:18:50

标签: c++ objective-c objective-c++

简短版本:我有一个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”的错误。那么我怎样才能做到这一点呢?

4 个答案:

答案 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 ++