3

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

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

包含一个成功编译的示例 Xcode 项目

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

  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 - 语言 - “编译源为 = 根据文件类型” -这与编译成功的示例项目中的 Build Setting 相同。

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

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

4

2 回答 2

10

不编译头文件。头文件由预处理器使用——任何你有一个#include或一个#import原始文本的地方都被视为你复制并粘贴到原始文本中。

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

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

于 2013-07-31T22:35:19.690 回答
3

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

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

你可以做各种各样的事情。

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

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

于 2013-08-03T20:02:47.060 回答