【问题标题】:I need help mixing C++ code and Objective-C code我需要帮助混合 C++ 代码和 Objective-C 代码
【发布时间】:2014-07-11 14:09:56
【问题描述】:

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

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

我曾尝试将 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;
}

【问题讨论】:

  • 错误信息是什么?
  • 如帖子中所述,我遇到了“未知类型名称‘类’;您的意思是‘类’吗?”的问题
  • 您使用的是旧版本的 Xcode 或 gcc,还是针对 32 位 OS X?这将影响您使用类扩展的方式。
  • Darren,我的目标是使用 Xcode 5.1.1 和 OSX10.9.4 的 OSX 64 位。
  • @zzyzy 那么使用类扩展应该是相当简单的。您只需将 CPP 标头、CPP 实例变量和 CPP 类声明移动到您的 .mm 文件中。您在使用类扩展时遇到了什么问题?

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


【解决方案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”

【讨论】:

    【解决方案2】:

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

    未知类型名称“类”;你是说“班级”吗?

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

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

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

      #import <vector>
      @implementation MyObjCppClass {
          std::vector<int> _stuff;
      }
      
      - (id)init {
          ...
      }
      
      @end
      
    • 1234563 )。

    【讨论】:

    • 感谢您的建议。我知道我需要将 SyncController.h 文件中的接口声明之后的所有内容移动到 .mm 文件中。实际上,这将阻止 C++ 头文件出现在 Obj-C 实现文件中。我想我很清楚通过实例变量隐藏 C++ —— 但是,鉴于 API 中有一个 Playback 委托,我不确定如何使用 Obj-C 包装器实现这一点。
    • 此外,我在上面的代码中提供的内容是否足以在 Obj-C 包装器对象中重写它?我希望如此。同样,我不精通C++。干杯。再次感谢您的建议。
    【解决方案3】:

    将您的 .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 包装器中。

    【讨论】:

    • 感谢您的建议。到目前为止,我正在开发一个 Obj-C 项目,其中包含大约 130 个 .m 文件,此时只有一个 .mm 文件需要处理。我试图避免走那条路。
    【解决方案4】:

    使用#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;
    

    【讨论】:

    • 嗯...这是使用类扩展的一个有吸引力的替代解决方案。
    【解决方案5】:

    初始化

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-10
      • 2013-12-22
      相关资源
      最近更新 更多