我应该把C ++ #include包含在哪里?在标题或实现中?

时间:2013-07-09 04:53:38

标签: c++ include

假设我在CameraVision.cpp文件中有一个名为CameraVision的类。

此类的构造函数接受IplImage*的向量(IplImage是一个表示OpenCV中图像的C结构)。我需要在CameraVision.hpp或CameraVision.cpp中#include opencv.h。

哪个更好,为什么? (#在CameraVision.hpp或CameraVision.cpp中包含这些?)

此外,我应该在哪里#include STL <vector><iostream>等?

假设CameraVision.cpp的客户端也使用<vector><iostream>。客户端显然会#include CameraVision.hpp(因为他是CameraVision的客户)。 CameraVision.cpp的客户端是否也应该#include,<iostream>等,如果#include已经CameraVision.hpp了?客户如何知道这一点?

3 个答案:

答案 0 :(得分:8)

此处的规则是:限制范围。如果你只能在实现文件中使用include(例如通过使用前向声明,包括<iosfwd>等),那么就这样做。在公共接口中,即客户端将使用的标头包含您使用的库,请考虑使用PIMPL模式隐藏任何实现细节。

好处:

1)代码的清晰度。基本上,当某人正在查看头文件时,他正在寻找关于你的课程内容的一些想法。包含的每个标头都会在标题中添加“范围”:要考虑的其他标头,更多标识符,更多结构。在非常糟糕的代码中,每个标题包含更多标题,如果不了解整个库,就无法真正理解一个类。尝试将这种依赖性保持在最低限度使得更容易理解隔离的类的接口。 (“不要打扰IplImage实际 ,内部或它能做什么 - 此时我们只需要指向它的指针”。

2)编译时间。由于编译器必须执行与1)中所述相同类型的查找,因此头文件中包含的内容越多,编译源的时间就越长。在极端情况下,编译器必须为每个翻译单元包含所有头文件。虽然结果编译时间对于一次性编译可能是可接受的,但这也意味着必须在任何更改为标头后重新完成编译。在严格的编辑 - 编译 - 测试 - 编辑周期中,这可能会很快加起来达到不可接受的水平。

编辑:不完全是主题,但在我们处理时,请不要在头文件中使用using,因为它与限制范围相反...

答案 1 :(得分:3)

为了避免额外的包含,您应该在所有情况下在实现(.cpp)文件中使用#include,除非您导入的名称,在模块导出的原型或声明中使用的情况除外。

例如:

foo.h中:

#ifndef _FOOBAR_H_
#define _FOOBAR_H_

#include <vector>

void foo();
std::vector<int> bar();

#endif // _FOOBAR_H_

Foo.cpp中:

#include "foo.h"
#include <iostream>

void foo() {
    std::cout << "Foo";
}

std::vector<int> bar() {
    int b[3] = {1, 2, 3};
    return std::vector<int>(b, b+3);
}

答案 2 :(得分:3)

如果仅在实现文件中使用/引用类型,而不是在头文件中,则应仅在实现文件中#include,坚持范围有限的原则。

但是,如果您的头文件引用了某个类型,那么您的头文件应该#include该类型的头文件。原因是您的头文件应该能够被完全理解并且具有#included时所需的一切。

这种观点的一个理由不仅仅是建筑/编制,还包括工具。您的开发环境可能会解析头文件以向您提供类型帮助(例如,智能感知,命令完成等等),这可能需要完整的类型信息才能正常工作。

另一个理由是,如果您的头文件被另一方使用,该方有足够的有关您的类型的信息来使用您的代码。而且他们不应该有#include几个文件来编译一种类型。

您不应该在另一个类型的头文件中#include类型的头文件,只是为了避免在实现文件中有#include个文件。相反,应该制作第三个头文件以聚合这些类型。