2

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

他们的 DecklinkAPI.h 文件包含丰富的 C++ 代码,所以当我尝试将这个头文件原样包含在一个 Objective-C 类中时,编译器在 API 深处窒息包括:未知类型名称“类”;您指的是 'Class' 吗?

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

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

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

对此的任何帮助将不胜感激。

首先,这是我当前的 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;
}
4

5 回答 5

1

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

- -编辑 - -

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

于 2014-07-11T17:45:59.760 回答
1

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

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

以下等效于您发布的代码,但将所有 C++ 声明移至单独的标头:

同步控制器.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  ...
{
    ...
}

同步控制器.mm

#import "SyncController_CPP.h"

@implementation SyncController
...
@end

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

// etc..

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

于 2014-07-11T21:40:17.620 回答
1

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

未知类型名称“类”;您指的是 'Class' 吗?

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

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

  • 不要把 C++ 头文件是预编译的头文件。
  • 尝试只在 Objective-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++ 中实现的)。

于 2014-07-11T15:01:37.847 回答
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 *正确的类型转换。

此外 usingvoid *意味着不再需要标头中的 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;
于 2014-07-11T21:07:20.107 回答
1

初始化

syncController.playerDelegate = new PlaybackDelegate();

// use the pointer
PlaybackDelegate *playbackDelegate = (PlaybackDelegate *)syncController.playerDelegate
于 2017-03-22T15:27:47.267 回答