假设我有一个包含 3 个项目X
、Y
和的解决方案E
。
E
将生成一个可执行文件,并将生成X
静态Y
库,例如Y
包含.X
E
Y
现在,我的问题是:为什么我必须包含 in 的头文件的X
目录E
?
假设我有一个包含 3 个项目X
、Y
和的解决方案E
。
E
将生成一个可执行文件,并将生成X
静态Y
库,例如Y
包含.X
E
Y
现在,我的问题是:为什么我必须包含 in 的头文件的X
目录E
?
原因如下:
Y
需要一个参数(或返回一个值),该参数是在X
.E
。X
则绝对需要E
.如果你构造 Y 使得它对 X 的依赖被完全封装,你可以避免这种情况。根据 X 和 Y 的具体情况,这可能会也可能不会。但是如果 Y 呈现给 E 的接口不需要包含 X 的任何细节,那么 E 项目甚至不需要间接包含来自 X 的标头。在精简情况下,只有 Y 的实现文件(.c 或 .cpp 文件)将包含来自 X 的标头。在 Y 标头中对 X 中的类型使用前向声明可以帮助实现 X 在 Y 中的这种封装。
这是一个很好的目标,但它可能并不总是可能的,即使有可能,它也可能比你(或你的管理层)想要付出的努力更多。
有时可以为 C++ 重构头文件以使用前向声明来避免您描述的情况。这是一个示例:C++ 头文件依赖技巧。
一个简单的案例:
class X {
//...
};
// #include <X.h> -- remove this
class X; // add forward declaration
class Y {
X *m_px; // must be a pointer, not a value,
// otherwise the size of X would need to be known
//...
};
#include <X.h> // need to add it here
//...
简短的回答: “为什么我必须在 E 中包含 X 的头文件的目录?”......你不应该。Y 的客户不必知道 Y 依赖于 X。
长答案:只有当 Y 的接口(签名)使用 X 的标头中声明的东西时,您才需要在 E 中包含 X 的标头。但是如果 Y 的标头是“正确构造的”,那么它们将包括Y 标头本身中的 X 标头,您不必在 E 中显式包含 X 标头(包括 Y 标头将自动包含 X 标头)。
通过“正确构造”,我的意思是如果 Y1.h 中的签名依赖于(比如)X3.h 和 X7.h,那么 Y1.h 应该包括这些文件(直接或间接)。这样,Y1.h 的任何客户端都不必知道它的依赖项是什么,因此必须单独包含这些依赖项。作为一个简单的测试,包含以下行的 .cpp 应该可以毫无问题地编译:
#include "Y1.h"
一个好的做法是在 Y1.cpp 中包含任何其他文件之前 #include "Y1.h"。如果 Y1.h 缺少依赖项,编译器会通知您。