【问题标题】:Making a Objective-C Wrapper for a C++ Library为 C++ 库制作 Objective-C 包装器
【发布时间】:2011-05-11 09:27:07
【问题描述】:

我正在尝试在 Objective-C 中制作一个包装器,因此我不必在库类之外编写 c++。

库主文件为LLAHProcessor.h .cpp

我的包装器是LLAHProcessorWrapper.h .mm

它编译得很好,但是当我将 LLAHProcessorWrapper 添加到其他类时,(比如说 UIView)作为成员变量,我得到了数百个错误,例如:

#include <map> : Map no such a file or directory

在每个 c++ 类/结构中:

Expected specifier-qualifier list before ClassName

就像编译器无法识别 c++ 代码一样。

我想知道我在这里缺少什么。 是否必须与我将其添加到 Xcode 目标属性的事实有关:?

Other Link Flags : -lstdc++ -lz

或者我可能需要在这里添加新标志?

提前致谢

【问题讨论】:

  • LLAHProcessorWrapper.h 不包含任何 C++ 代码至关重要。 LLAHProcessor.h 应该导入到您的 .mm 中。文件,而不是在 .h 文件中。你这样做了吗?
  • 项目中还有.m文件?
  • @Chris 我有很多 .m 文件。这是一个相当大的程序。
  • @Ole,好的,我明白你的意思,但如果我这样做,我应该如何拥有成员变量?我应该将它们添加到 LLAHProcessorWrapper.mm 文件中的方法实现之外吗?
  • 对实例变量使用void * 指针。请参阅 Peylow 的回答。

标签: iphone c++ objective-c xcode stl


【解决方案1】:

您的问题是 .m 文件被编译为 C 而不是 C++。因此,当编译器在编译 .m 文件时遇到任何 C++(甚至是在头文件中)时,它都会出错。

毫无疑问,您必须在头文件中放入一些 C++,因为您的 Objective C 对象包装了一个 C++ 对象,但是有一些方法可以解决这个问题。一种方法是使用指向 C++ 对象的指针并使用方便的预处理器定义 __cplusplus,它是为 C++(和 Objective-C++)定义的,但不是为 C(或 Objective-C)定义的,例如

// LLAHProcessorWrapper.h

#if defined __cplusplus
class MyCPPClass;    // forward class declaration
#else
typedef struct MyCPPClass MyCPPClass;   // forward struct declaration
#endif

@interface MyOCClass : NSObject
{
@private
    MyCPPClass* cppObject;
} 

// methods and properties

@end

由于您从不取消引用 .mm 文件之外的 cppObject 成员,因此您从不提供结构的完整定义并不重要。

您将 newdelete 分别指向 -init-dealloc 中的指针。您可以在 LLAHProcessorWrapper.mm 中包含完整的 C++ 类声明。

【讨论】:

  • 如果这对任何人都有用:我被#include "MyCPPClass.h" 仍然在LLAHProcessorWrapper.h 中发现了。它应该在LLAHProcessorWrapper.mm 中。
  • 我想我们现在也可以使用类扩展了?也许是更好的方法?
【解决方案2】:

你需要做的就是像你一样创建一个.mm,编译器应该会处理所有事情。

需要注意的是,在 .h 文件中包含任何与 C++ 相关的内容是不安全的,因为它们可以/将由其他仅 Objective-C 的文件导入,然后一切都会崩溃。这里的主要问题是您不能将 C++ 类型直接定义为 Objective-C 包装类的实例变量,除非每个 .m 文件都被重命名为 Objective-C++ .mm 文件。

解决方案是在头文件中将实例变量定义为void*,并通过实现文件中的类型转换来访问它们。最简单的解决方案是使用为您进行类型转换的私有属性访问实例变量。

假设FooFoo.h中定义的C++类的示例代码:

// FooWrapper.h
#import <Foundation/Foundation.h>

@interface FooWrapper : NSObject {
@private
  void* foo;
}
// Actual wrapper API for Foo…
@end


// FooWrapper.mm
#import "FooWrapper.h"
#include <map>
#include "Foo.h"

@interface FooWrapper ()
@property(nonatomic, assign) Foo* foo;
@end

@implementation FooWrapper
-(Foo*)foo {
  return (Foo*)foo;
}
-(void)setFoo:(Foo*)aFoo {
  foo = (void*)aFoo;
}
// Implementation of actual API for Foo…
@end

【讨论】:

    【解决方案3】:

    在您想要引用 LLAHProcessorWrapper 的任何头文件 (.h) 中,使用前向类定义而不是导入,如下所示:

    @class LLAHProcessorWrapper;
    @interface SomeView : UIView {
      LLAHProcessorWrapper *wrapper;
    }
    

    并确保对应的实现文件有#include LLAHProcessorWrapper.h#import LLAHProcessorWrapper.h

    如果LLAHProcessorWrapper.h整个包含树中的任何其他内容具有任何 C++ 语法全部。这样一来,拥有一个 .mm 文件往往意味着代码库的大部分必须将其文件重命名为 .mm

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-06
      • 1970-01-01
      • 1970-01-01
      • 2016-08-13
      相关资源
      最近更新 更多