我的头文件看起来像:
// A.hpp --- A's interface
#ifndef MY_H
#define MY_H
#include<string>
#include<vector>
class A {
public:
A(const std::string& name);
std::vector<double> foo() const;
private:
std::string m_name;
};
#endif
我的实现文件如下所示:
// A.cpp --- A's interface implementation
#include<A.hpp>
#include<implementation_detail.hpp>
A::A(const std::string& name)
: m_name(name) { }
std::vector<double> A::foo() const {
std::vector<double> r;
r.push_back(1);
return r;
}
我的立场是,我不#include
string
或vector
实现文件中,因为它们已经在接口中声明,并且在实现文件中#include
它们充其量是多余的,在更糟糕的情况下是有害的**。
当然,A
的实现将#include
界面上看不到的所有实现细节。
的问题:我说得对吗?这种做法会对我的代码产生负面影响吗?
** 这是牵强附会的,但是包含的数量(以及使用的包含保护)可以影响非常大的项目的编译速度;这篇文章很有趣。
这是风格和个人喜好的问题。
对于头文件,我个人的偏好是使头文件独立存在,但只是勉强。通过"独立",我的意思是我应该能够在某个随机源文件中#include
该标头,并且该源文件仍将编译。
#include "some_random_header_file.h"
int main () {}
以上应始终编译。通过"勉强",我的意思是标头应该没有无端的#include
指令。如果某些#include
不提供直接在头文件中使用的功能,则我不会在头文件中#include
该其他头文件。
对于源文件,我个人的偏好是#include
提供源文件中使用的功能的每个标头。如果源文件调用的代码std::string::append
,则该源文件具有更好的#include <string>
- 即使其他标头已经包含它。
你是对的。cpp 文件是编译单元。这就是使用标头的地方。这些标头包含的所有内容也有效地存在于 cpp 文件中。
值得注意的是:
- 不要在标题的 cpp 文件中包含您需要的内容。 在
- 标头中的类型中明确。 即将
std::string
用作类型不using std::string
甚至更糟using namespace std;
在标题中。 - 可以在 cpp 文件中方便地使用
using
语句。
您不希望向包括标题在内的人员引入不必要的类型。
这是风格问题,而不是正确性。
但是,只包含绝对需要的东西被认为是一种很好的风格。因此,如果您的接口需要这些标头,那么您的.h
必须包含它们。
同时,使每个标头自给自足被认为是一种很好的样式 - 也就是说,为了使用其设施,包含它而不包含任何其他内容就足够了。
因此,鉴于这两点,您在标头中包含这些#include
指令是正确的。
如果您真的关心#include
性能,这里有一些选择:
- 前瞻声明
- 痘痘成语
- 预编译标头