由于 Xcode 不尊重文件类型导致的 Objective-C++ 编译错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17982091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 03:38:38  来源:igfitidea点击:

Objective-C++ compilation errors due to Xcode not respecting file type

xcodeobjective-c++

提问by sja26

I'm following a tutorial in a book (iPhone 3D Programming), which uses:

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

  • Objective-C header and source files (file extensions .h, .m - respectively),
  • Objective-C++ header and source files (file extensions .h, .mm - respectively)
  • C++ header and source files (file extensions .hpp, .mpp - respectively)
  • Objective-C 头文件和源文件(文件扩展名分别为 .h、.m),
  • Objective-C++ 头文件和源文件(文件扩展名为 .h、.mm - 分别)
  • C++ 头文件和源文件(文件扩展名分别为 .hpp、.mpp)

A sample Xcode projectis included which compiles successfully.

一个示例Xcode项目被列入其中编译成功。

Before I found the sample project, I had manually typed out the code from the book but I was getting the following compilation errors for the files detailed below:

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

  1. Unknown type name 'virtual'
  2. Expected member name or ';' after declaration specifiers
  1. 未知类型名称“虚拟”
  2. 预期的成员名称或“;” 声明说明符后

IRenderingEngine.hpp (Xcode File Inspector - File Type = "Default - C++ Header")

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. Must use 'struct' tag to refer to type 'IRenderingEngine'
  1. 必须使用“struct”标签来引用类型“IRenderingEngine”

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

GLView.h(Xcode 文件检查器 - 文件类型 =“默认 - C 标题”)

#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

The file types for all the other files also defaulted to their expected file types in the Xcode File Inspector and as such should have worked correctly with the Build Setting - Apple LLVM compiler 4.2 - Language - "Compile Sources As = According to File Type" - which is identical to the Build Setting in the sample project that compiles successfully.

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

For some odd reason changing the Build Setting to "Compile Sources As = Objective-C++" in my manually created project removed the compilation errors and the application ran as expected.

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

Can anyone offer a reason as to why this setting is not consistent between seemingly identical (source-code-wise) projects?

任何人都可以解释为什么这个设置在看似相同(源代码方面)的项目之间不一致?

回答by Tommy

Header files are not compiled. Header files are used by the preprocessor — anywhere you have a #includeor a #importthe actual text of the original is treated as though you'd copied and pasted it into the original.

不编译头文件。头文件使用的预处理器-任何地方,你有一个#include或一个#import好像你复制原来的实际文本进行处理,并将其粘贴到原来的。

Hence it doesn't matter if your file is called .hpp, .h or anything else. If a .m file imports a .h file that includes a .hpp file then the .hpp code will be compiled as part of the .m file, i.e. as Objective-C.

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

I am therefore going to guess that you've got GLView.m. If that's going to import a .hpp file, whether directly or indirectly, it needs to be compiled as Objective-C++. One way to do it is to rename it .mm, the other is to tell the project not to try to guess language types by file extension.

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

回答by newacct

Tommy and HotLicks gave you the right answer to your immediate problem -- you need to make sure that all source files that include GLView.hare Objective-C files, by naming them .mm.

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

However, I want to add another side to this. Blindly making all files Objective-C++ is a bad solution. It should lead you to ask yourself: why do all these files need to be Objective-C++, if they are not using C++ features? The answer is that they import GLView.h, and the GLViewclass contains an instance variable whose type is a pointer to a struct that contains C++ features. Why do these other files care about that? They shouldn't.

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

There are various things you can do about it.

你可以做很多事情。

  • IRenderingEnginecan be forward-declared in GLView.h. It is unnecessary to import IRenderingEngine.hpp, since the header doesn't care about the internal structure of IRenderingEngine; it only needs to know that it's some type in order to have a pointer to it. A forward declaration suffices for this. (However it would be necessary to write struct IRenderingEngine* m_renderingEngine;to be compatible with C.)

  • Furthermore, the instance variables for the GLViewclass do not need to be declared in the header in the first place. Instance variables can instead be declared in the implementation (.m) file either in the "class extension" (i.e. @interface GLView () { ... }), or, in newer versions of Xcode, directly in the class implementation (@implementation GLView { ... })

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

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