2011-10-25 56 views
5

簡短版本:我有一個Qt/C++,我不得不添加有限數量的Cocoa/Objective-C代碼。我已將.cpp文件更改爲.mm文件,並將該Objective-C代碼/對象添加到所述文件,然後編譯並運行。我現在需要爲我創建的其中一個對象創建一個委託 - 一個NSPopUpButton(或者更準確地說是它的菜單) - 而且我被卡住了。我怎樣才能爲這個對象添加一個委託?如何處理來自C++的objective-c委託?

詳情: 文件中的問題:

reportwindow.h,reportwindow.cpp更名爲reportwindow.mm - 這些是包含我原來的C++實現,加上文件的一些Objective-C代碼(打開包含一個NSSavePanel NSPopUpButton)。 reportwindow.h還包含在.cpp文件中,如果這有所幫助。

menuHandler.h,menuHandler.mm - 這些文件包含(目前爲空)Objective-C類,我是打算作爲一個代表

我首先想到的是,我可以簡單地使C到使用++類代表,但這顯然不起作用,直C++不理解委託。然後,我想我會做一個單獨的Objective-c類作爲NSMenuDelegate,並將它的一個實例作爲成員對象添加到我的C++類中。由於我已經能夠添加其他Objective-C對象作爲成員,我認爲這應該起作用。但是,一旦我在C++類頭文件中包含了我的新Objective-C類的頭文件,我就收到了幾百個有關「在'@'標記之前期待的非限定標識」 - 從蘋果頭文件(NSValue.h ,NSObject.h等)顯然,這沒有奏效,至少不是。在我的類頭文件中包含ANY cocoa頭時,會得到相同的結果。

然後我想我會嘗試一個Objective-c類的前向聲明(這就是我如何獲得其他objective-c對象的工作方式)。然而,這也不起作用 - 如果我將其聲明爲「class myClassName」,則會出現有關將該類重新定義爲不同類型的符號(推測爲C++類vs objective-c協議)的錯誤。如果我嘗試將其聲明爲@protocol myClassName,則會出現有關「@'token'之前的預期非限定標識」的錯誤。那我該如何做這項工作?

+0

已重命名該特定CPP文件毫米設置你的頭,使他們能夠使用的一些有用的信息? –

+0

與問題標題關聯的那個,是的。 – ibrewster

+0

第二種方式是走的路,也許是唯一的一條路。在第一次失敗後,你不應該投降。提供更多的細節,包括什麼,可能會有更多.cpp文件包含'reportwindow.h'。 – hamstergene

回答

10

好回答你的問題:

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的初始化,但你不能初始化任何Objective-C類從那裏的C++代碼。如果您需要在您的C++代碼中使用Objective-C,則必須將其編譯爲Objective-C(即使用.mm文件)。我離開的.cpp細節作爲練習讀者;)

+1

你可以請提供.cpp實現的想法:P你如何初始化MyDelegateObject從CPP。 – Aalok

0

我當時想我會嘗試的Objective-C類的前瞻性聲明(這就是我的工作得到了其他Objective-C對象)。然而,這也不起作用 - 如果我將其聲明爲「class myClassName」,則會出現有關將該類重新定義爲不同類型的符號(推測爲C++類vs objective-c協議)的錯誤。

爲什麼不向前聲明它爲@class myClassName

+0

我試過了,它給出了「在''符號之前預期的不合格id'的錯誤。原來Qt正在生成一個moc_ .cpp文件,它正在拋出一些東西。將其重命名爲.mm可以解決問題。 – ibrewster

0

使一個Objective-C類滿足委託協議,並委託給你的C++類。問題在於AppKit希望與Objective-C對象交談,因此您需要一個墊片來委託給您的C++對象。 (是的,你可以做一些運行時間的濫用,在你的C++類中定義一個isa指針,使它與ObjC對象有一定的兼容性(可以將消息發送到C++類),但不這樣做。

因此,製作一個用你的C++類初始化的墊片,將它作爲一個ivar。它應該實現你感興趣的委託方法,並以可理解的方式將它們傳遞給C++類。田田,完成。

相關問題