【问题标题】:Objective-C++ compilation errors due to Xcode not respecting file type由于 Xcode 不尊重文件类型导致的 Objective-C++ 编译错误
【发布时间】:2013-08-01 16:04:32
【问题描述】:

我正在学习一本书 (iPhone 3D Programming) 中的教程,该教程使用:

  • Objective-C 头文件和源文件(文件扩展名分别为 .h、.m),
  • Objective-C++ 头文件和源文件(文件扩展名分别为 .h、.mm)
  • C++ 头文件和源文件(文件扩展名分别为 .hpp、.mpp)

包含一个sample Xcode project,编译成功。

在找到示例项目之前,我已经手动输入了书中的代码,但是对于下面详述的文件,我收到了以下编译错误:

  1. 未知类型名称“虚拟”
  2. 预期的成员名称或“;”在声明说明符之后

IRenderingEngine.hpp(Xcode 文件检查器 - 文件类型 = “默认 - C++ 标头”)

...
struct IRenderingEngine {
    virtual void Initialize(int width, int height) = 0; //2 errors as marked above
    virtual void Render() const = 0; //2 errors as marked above
    virtual void UpdateAnimation(float timeStep) = 0; //2 errors as marked above
    virtual void OnRotate(DeviceOrientation newOrientation) = 0; //2 errors as marked above
    virtual ~IRenderingEngine() {} //2 errors as marked above
};
...
  1. 必须使用“struct”标签来引用类型“IRenderingEngine”

GLView.h (Xcode File Inspector - File Type = "Default - C Header")

#import "IRenderingEngine.hpp"
#import <QuartzCore/QuartzCore.h>

@interface GLView : UIView {
@private
    EAGLContext* m_context;
    IRenderingEngine* m_renderingEngine; //1 error marked above
    float m_timestamp;
}

- (void) drawView:(CADisplayLink*)displayLink;
- (void) didRotate:(NSNotification*)notification;

@end

所有其他文件的文件类型也默认为其在 Xcode 文件检查器中的预期文件类型,因此应该可以与构建设置正常工作 - Apple LLVM 编译器 4.2 - 语言 - “编译源为 = 根据文件Type" - 与编译成功的示例项目中的 Build Setting 相同。

由于某些奇怪的原因,在我手动创建的项目中将 Build Setting 更改为“Compile Sources As = Objective-C++”消除了编译错误,并且应用程序按预期运行。

谁能解释为什么这个设置在看似相同(源代码方面)的项目之间不一致?

【问题讨论】:

  • 将包含第一个 sn-p 的文件的文件类型从 .m 更改为 .mm。重要的是 .m/.mm 的文件类型。
  • @HotLicks 第一个代码 sn-p 确实是 C++,如文件名 IRenderingEngine.hpp 所示
  • 包含文件的名称可以是 IRenderingEngine.i'mC++,它不会有任何区别。重要的是编译文件的类型。
  • Right and Xcode's File Inspector 显示 File Type = "Default - C++ Header" 所以我想这是编译器用来确定如何处理它的,但由于某种原因我不得不强行告诉它通过更改构建设置“Compile Sources As = Objective-C++”将所有文件视为 Objective-C++ 以使项目编译。
  • 不,头文件类型与它无关。除非它是可编译类型(.c、.m、.cpp、.mm),否则它基本上会被忽略。它是包含决定如何处理代码的头文件的可编译文件。

标签: xcode objective-c++


【解决方案1】:

Tommy 和 HotLicks 为您的当前问题提供了正确答案 - 您需要确保所有包含 GLView.h 的源文件都是 Objective-C 文件,将它们命名为 .mm

但是,我想为此添加另一面。盲目地制作所有文件 Objective-C++ 是一个糟糕的解决方案。它应该引导你问自己:为什么所有这些文件都需要是 Objective-C++,如果它们不使用 C++ 特性?答案是它们导入了GLView.h,而GLView 类包含一个实例变量,其类型是指向包含C++ 特性的结构的指针。为什么这些其他文件关心这个?他们不应该。

你可以做很多事情。

  • IRenderingEngine 可以在 GLView.h 中前向声明。不需要导入IRenderingEngine.hpp,因为头部不关心IRenderingEngine的内部结构;它只需要知道它是某种类型即可获得指向它的指针。一个前向声明就足够了。 (但是,必须编写 struct IRenderingEngine* m_renderingEngine; 才能与 C 兼容。)

  • 此外,GLView 类的实例变量首先不需要在头文件中声明。实例变量可以改为在“类扩展”(即@interface GLView () { ... })的实现(.m)文件中声明,或者在较新版本的 Xcode 中,直接在类实现中声明(@implementation GLView { ... }

【讨论】:

    【解决方案2】:

    头文件未编译。头文件由预处理器使用——只要有#include#import,原始文本的实际文本就会被视为您已将其复制并粘贴到原始文本中。

    因此,您的文件是否称为 .hpp、.h 或其他任何名称都没有关系。如果 .m 文件导入包含 .hpp 文件的 .h 文件,则 .hpp 代码将被编译为 .m 文件的一部分,即作为 Objective-C。

    因此,我猜你有GLView.m。如果要导入 .hpp 文件,无论是直接还是间接,都需要将其编译为 Objective-C++。一种方法是将其重命名为 .mm,另一种方法是告诉项目不要尝试通过文件扩展名猜测语言类型。

    【讨论】:

    • 我按照你的逻辑,意识到这两个项目之间存在差异,示例项目中的 main.m 文件没有导入或包含任何内容,但我手动创建的项目导入了 AppDelegate.h - 所以我将 main.m 重命名为 main.mm 并且无需更改构建设置即可编译。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多