【问题标题】:C++ Including header file multiple timesC++多次包含头文件
【发布时间】:2018-03-08 22:04:39
【问题描述】:

我只是想知道根据下面的示例在哪里需要/正确地包含特定的头文件。假设我有一个异常类的定义:

//exc.hpp
#ifndef EXC_H
#define EXC_H
class MyException : public exception {

};
#endif /* EXC_H */

然后我有另一个类定义抛出这样的异常:

//a.cpp
void SomeClass::someMethod(void) {
  throw MyException(...);
}

并有另一个文件处理该异常,例如:

//main.cpp
#include "a.hpp"

int main() {
   ...
   catch(MyException & e) { ... }
}

所以我的问题是,我应该将#include "exc.hpp" 放在哪里?只发给a.hpp,还是发给a.hppmain.cpp

当涉及到makefile... 应该如何在此类文件中指定目标?

【问题讨论】:

  • 您的“exc.hpp”不完整,因为没有看到用作基类的exception 的定义。因此,包含该标头仅在先前定义 exception 的编译单元中有效。

标签: c++ makefile include


【解决方案1】:

throws 或 catches 该类型异常的每个翻译单元都需要能够看到其定义。

简单地说,这意味着每个包含与该异常相关的throwcatch.cpp 文件都必须包含您的.hpp 文件。

那是even if you only catch by reference 并且从不检查异常对象,这在 C++ 的其他领域(前向声明会这样做)不是这种情况。

Makefile 不相关。

【讨论】:

    【解决方案2】:

    具有实现的文件 (a.cpp) 和使用类 (main.cpp) 的所有文件都应具有 #include

    没有包含的a.cpp 根本不能编译。

    【讨论】:

      【解决方案3】:

      您需要在 main.cpp 和 a.cpp 中都包含 .hpp 文件。 #ifndef 序列的目的是防止意外的多重包含(通过间接#includes)。在 MS 编译器中还有一个 #pragma once 指令可以做同样的事情。

      编译器根据 .cpp 文件中的 #include 确定要读取的 .h/.hpp 文件;不涉及make文件。

      【讨论】:

        【解决方案4】:

        请记住,编译器会独立处理每个源文件,并且在处理完成后不会记住源文件中的任何内容。即使您在单个编译器命令行上列出了多个源文件。

        您有一个定义类型的头文件。自然,您必须在需要定义该类型的每个源文件中 #include 头文件。 (编译器不会记得在处理较早的源文件时看到过这些类型。)

        #include 其他头文件中的头文件可能很诱人,这样您就不必在 .c 或 .cpp 文件中使用#include 这么多东西,但是 这应该在一定程度上避免可能。它会产生所谓的“头文件耦合”,并且会产生难以在以后在其他项目中重用的代码。

        在我上面所说的内容中还隐藏了一个要点:“您需要在哪里定义该类型”。 C 和 C++ 中有两个非常具体的概念与变量相关:

        1. 声明——当你让编译器知道一个类型存在时,并且
        2. 定义——告诉编译器类型的细节。

        您需要在需要定义的任何地方#include 标题。即,当您打算实例化该类型的对象时,在另一个结构或类中定义该类型的成员,或调用其方法之一(假设 C++)。相反,如果您只想存储对该类型对象的引用而不创建或使用它们,则声明就足够了,您只需前向声明该类即可。即,

        class MyException;
        
        void setFileNotFoundExceptionObject(const MyException *exc) { ... }
        

        许多 API 是专门围绕仅使用指针或对象引用而设计的,因此 API 标头只需要类型的前向声明,而不需要完整的定义(这样可以隐藏对象的内部成员,以防止开发人员滥用它们.)

        【讨论】:

        • 我还不清楚...我有多个类头定义,但有时我需要将它们包含在彼此中。所以我最终得到了一些 *.hpp 文件,其中包括另一个 *.hpp 文件(例如 B 类返回 A 类对象的指针)。在这种情况下,当我不使用警卫时,我确实会收到重新定义错误。我做错了吗?
        • 你似乎没有做错什么。 每个 标头都使用警卫。您有时需要在标题中包含标题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-23
        • 1970-01-01
        • 1970-01-01
        • 2010-11-25
        相关资源
        最近更新 更多