C++多次包含头文件

C++ Including header file multiple times

本文关键字:文件 包含头 C++      更新时间:2023-10-16

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

//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...在此类文件中应如何指定目标?

throwcatch该类型的例外的每个翻译单元都需要能够看到其定义。

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

即使您只通过引用捕获并且从不检查异常对象,这在C++的其他领域(前向声明就可以)并非如此。

生成文件是不相关的。

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

没有包含的a.cpp不得编译。

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

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

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

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

在其他标头中#include标头可能很诱人,这样您就不必在 .c 或 .cpp 文件中#include太多内容,但应尽可能避免这种情况。 它产生所谓的"标头耦合",并且它使代码以后很难在其他项目中重用。

在我上面所说的中还有一个很好的观点:"你需要定义该类型的地方"。 在 C 和 C++ 中有两个非常具体的概念与变量相关:

  1. 声明 -- 当您让编译器知道存在某个类型时,以及
  2. 定义 -- 告诉编译器类型的详细信息。

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

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

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