2

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

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

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

另外,我应该在哪里#includeSTL<vector><iostream>

假设 CameraVision.cpp 的客户端也使用<vector><iostream>。客户显然会#include CameraVision.hpp(因为他是 CameraVision 的客户)。如果 CameraVision.cpp 的客户端<iostream>已经被#include'd in ,那么它们是否也应该 #include 、 等CameraVision.hpp?客户怎么会知道这个?

4

3 回答 3

9

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

好处:

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

2) 编译时间。由于编译器必须执行与 1) 中描述的相同类型的查找,头文件中包含的内容越多,编译源代码所需的时间就越长。在极端情况下,编译器必须包含每个翻译单元的所有头文件。虽然生成的编译时间对于一次性编译可能是可以接受的,但这也意味着必须在对标头进行任何更改后重新完成。在紧凑的编辑 - 编译 - 测试 - 编辑循环中,这很快就会增加到不可接受的水平。

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

于 2013-07-09T04:58:31.140 回答
5

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

例如:

富.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);
}
于 2013-07-09T05:02:38.803 回答
4

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

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

这种观点的一个理由不仅是构建/编译,而且是工具。您的开发环境可能会解析头文件以为您提供类型帮助(例如 Intellisense、命令完成等),这可能需要完整的类型信息才能正常工作。

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

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

于 2013-07-09T05:26:45.487 回答