我需要帮助混合C ++代码和Objective-C代码

时间:2014-07-11 14:09:57

标签: c++ objective-c xcode class-extensions

我正在为XCode中的Blackmagic Design AV设备编写设备驱动程序,我在将BMD的SyncController类从其缩写示例代码(下面)中包含到我纯粹的Objective-C项目中时遇到了麻烦。

他们的DecklinkAPI.h文件包含丰富的C ++代码,因此当我尝试在Objective-C类中按原样包含此头文件时,API中的编译器包括:未知类型名称'类“;你的意思是'上课'吗?

我试图将C ++位捆绑成一个Obj-C类扩展,如here所述,但没有太大成功。我从来没有做过任何C ++编程(并且从未使用过Obj-C类扩展),所以这对我来说是个新领域。

我不确定是否需要为我的SyncController对象创建一个额外的包装类,或者我是否可以在这个上执行类扩展并将C ++位拖放到.mm文件中。

我希望能够在没有编译器阻塞的情况下在Objective-C类中执行#include "SyncController.h"(或其包装器)。

非常感谢您提供的任何帮助。

首先,这是我当前的SyncController.h文件:

#import <Cocoa/Cocoa.h>
#import "DeckLinkAPI.h"  // this is rich in C++ code

class PlaybackDelegate;

@interface SyncController : NSObject {
    PlaybackDelegate*           playerDelegate;

    IDeckLink*                  deckLink;
    IDeckLinkOutput*            deckLinkOutput;
}

- (void)scheduleNextFrame:(BOOL)prerolling;
- (void)writeNextAudioSamples;

@end

class PlaybackDelegate : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback
{
    SyncController*             mController;
    IDeckLinkOutput*            mDeckLinkOutput;

public:
    PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput);

    // IUnknown needs only a dummy implementation
    virtual HRESULT     QueryInterface (REFIID iid, LPVOID *ppv)    {return E_NOINTERFACE;}
    virtual ULONG       AddRef ()                                   {return 1;}
    virtual ULONG       Release ()                                  {return 1;}

    virtual HRESULT     ScheduledFrameCompleted (IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result);
    virtual HRESULT     ScheduledPlaybackHasStopped ();
    virtual HRESULT     RenderAudioSamples (bool preroll);
};

void    ScheduleNextVideoFrame (void);

接下来,这是我的(简化的)SyncController.mm文件:

#import <CoreFoundation/CFString.h>
#import "SyncController.h"

@implementation SyncController

- (instancetype)init
{
    self = [super init];
    return self;
}

- (void)dealloc
{
}

- (void)scheduleNextFrame:(BOOL)prerolling
{
}

- (void)writeNextAudioSamples
{
}

@end

PlaybackDelegate::PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput)
{
    mController = owner;
    mDeckLinkOutput = deckLinkOutput;
}

HRESULT PlaybackDelegate::ScheduledFrameCompleted (IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result)
{
    [mController scheduleNextFrame:NO];
    return S_OK;
}

HRESULT     PlaybackDelegate::ScheduledPlaybackHasStopped ()
{
    return S_OK;
}

HRESULT     PlaybackDelegate::RenderAudioSamples (bool preroll)
{
    [mController writeNextAudioSamples];
    if (preroll)
        mDeckLinkOutput->StartScheduledPlayback(0, 100, 1.0);

    return S_OK;
}

5 个答案:

答案 0 :(得分:1)

不是一个完整的答案,但错误如:

未知类型名称'class';你的意思是'上课'吗?

Objective-C ++是一个经典问题,其中 Objective-C实现文件正在查看C ++头文件

我只能提供关于如何避免它的建议,因为你没有发布完整的构建输出。

  • 不要把C ++标题放在预编译的标题中。
  • 尝试仅在Objective-C ++实现文件中包含C ++标头,而不是在其对应的头文件中包含C ++标头文件,而该文件可能反过来包含在Objective-C文件中。
  • 隐藏任何头文件中C ++的使用,例如使用私有实例变量:

    #import <vector>
    @implementation MyObjCppClass {
        std::vector<int> _stuff;
    }
    
    - (id)init {
        ...
    }
    
    @end
    
  • 如果您正在混合使用Objective-C和Objective-C ++,那么您可能会发现需要为C ++类提供Objective-C包装器(从外部看起来是Objective-C但实际上是在Objective-C ++中实现的) )。

答案 1 :(得分:1)

将.m文件(objective-c)重命名为.mm(objective-c ++)。这应该允许您通过包含c ++标头和引用来自objc的c ++代码来混合objc和c ++。

--- --- EDIT

您在objective-c中包含的任何头文件都必须只包含objective-c。从包装器类的头中删除任何c ++,以获取要构建的其他objc类。在现代objc中,您可以在.h和.m文件之间拆分ivars;将所有方法保存在.h中以供其他objc类使用,并在.mm中声明你的c ++ ivars。将你的c ++委托类放在它自己的.h中,它只包含在.mm包装器中。

答案 2 :(得分:1)

使用#if __cplusplus

例如,

#import <Cocoa/Cocoa.h>

#if __cplusplus
#import "DeckLinkAPI.h"  // this is rich in C++ code
#endif // __cplusplus

@interface SyncController : NSObject {
    void* playerDelegate; // should be cast as C++ PlaybackDelegate class.
    ...
}
@end

#if __cplusplus
class PlaybackDelegate : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback
{
    ...
};
#endif // __cplusplus

头文件可以与Objective-C和Objective-C ++一起使用。但是你不能在头部的SyncController Objective-C类声明中使用C ++类签名。使用void *代替PlaybackDelegate *进行正确的类型转换。

同样使用void *意味着不再需要标题中的C ++内容。

#import <Cocoa/Cocoa.h>

@interface SyncController : NSObject {
    void* playerDelegate; // should be cast as C++ PlaybackDelegate class.
    ...
}
@end

在Objective-C ++代码中,

// initialize
syncController.playerDelegate = new PlaybackDelegate();

// use the pointer
PlaybackDelegate *playbackDelegate = (PlaybackDelegate *)syncController.playerDelegate;

答案 3 :(得分:1)

  

我试图将C ++位捆绑成一个Obj-C类扩展,如此处所述,但没有太大成功。

如果你的目标是64位,那么类扩展方法应该相当简单。

以下内容相当于您发布的代码,但将所有C ++声明移到单独的标题中:

SyncController.h:

#import <Cocoa/Cocoa.h>

@interface SyncController : NSObject
- (void)scheduleNextFrame:(BOOL)prerolling;
- (void)writeNextAudioSamples;
@end

SyncController_CPP.h

#import "SyncController.h"
#include "DeckLinkAPI.h"

class PlaybackDelegate;

@interface SyncController() {
    PlaybackDelegate* playerDelegate;
    IDeckLink* deckLink;
    IDeckLinkOutput* deckLinkOutput;
}
@end

class PlaybackDelegate  ...
{
    ...
}

SyncController.mm

#import "SyncController_CPP.h"

@implementation SyncController
...
@end

PlaybackDelegate::PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput)
{
    mController = owner;
    mDeckLinkOutput = deckLinkOutput;
}

// etc..

需要访问SyncController的任何其他ObjC类都将导入“SyncController.h”。任何其他ObjC ++类都可以导入“SyncController.h”或“SyncController_CPP.h”

答案 4 :(得分:1)

初​​始化

syncController.playerDelegate = new PlaybackDelegate();

// use the pointer
PlaybackDelegate *playbackDelegate = (PlaybackDelegate *)syncController.playerDelegate