C ++多次包含头文件

时间:2018-03-08 22:04:40

标签: c++ makefile include

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

//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时......如何在这样的文件中指定目标?

4 个答案:

答案 0 :(得分:0)

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

没有include的

a.cpp根本不能编译。

答案 1 :(得分:0)

Every translation unit that throws or catches exceptions of that type will need to be able to see its definition.

Loosely speaking, that means every .cpp file containing a throw or catch relating to that exception must include your .hpp file.

That's even if you only catch by reference and never inspect the exception object, which is not the case in other areas of C++ (where a forward declaration will do).

Makefiles are unrelated.

答案 2 :(得分:0)

You need to include the .hpp file in both main.cpp and a.cpp. The purpose of the #ifndef sequence is to prevent accidental multiple inclusion (through indirect #includes). There is also a #pragma once directive in MS compilers that does the same thing.

The compiler figures out what .h/.hpp files to read based on the #includes in the .cpp files; the make file is not involved.

答案 3 :(得分:0)

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

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

其他标题中的#include标题可能很诱人,只是因为你不必在.c或.cpp文件中#include这么多东西,但是这个应该尽可能避免。它产生了所谓的"标题耦合",它使代码很难在以后的其他项目中重复使用。

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

  1. 声明 - 当您使编译器意识到存在类型时,
  2. 定义 - 您告诉编译器类型的详细信息。
  3. 您需要#include标题所在的任何位置。即,当您打算实例化该类型的对象时,在另一个结构或类中定义该类型的成员,或者调用其中一个方法(假设使用C ++)。相反,如果您只想存储对该类型对象的引用而不创建或使用它们,则声明就足够了,您只需向前声明该类即可。即,

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

    许多API是专门设计的,只使用指针或对象的引用,这样API头只需要对类型的前向删除,而不是完整的定义(这会保持对象的内部成员隐藏,以防止开发人员滥用它们。)