包含在头文件的末尾,是否安全/良好做法
include at the end of a header file, is it safe/good practise?
我一直在尝试编写自己的状态机,其中每个状态都是从状态基类派生的单独类。
无论我在哪里包含我的state_t类文件(#include"state_t.h"),我都希望包含所有派生的状态类标头,这样我就不必在每次需要使用状态机或创建新状态时单独包含它们。
由于"state_t"直到 state_t.h 末尾才定义,因此我只能在文件 state_t.h 的末尾包含我的状态文件。我以前从未编写过这样做的代码,这似乎有点奇怪!我可以添加一个顶级的"statemachine.h",将所有文件收集在一起,但这似乎是一种浪费。
我的问题是:这样做是否正确/安全/可以? 有什么缺点/问题吗?
注意:目前我的代码都是测试代码,它是用Qt编写的,但它应该是一个直接的C ++问题。
这是我的基类 (state_t.h) - 请注意最后的 #include:
#ifndef STATE_T_H
#define STATE_T_H
#include <QByteArray>
#include <QDebug>
class state_t
{
public:
state_t(QByteArray stateName);
virtual ~state_t();
virtual state_t * processState(int input) = 0;
QByteArray getState();
QByteArray name;
};
#include "teststate1.h"
#include "teststate2.h"
#endif // STATE_T_H
下面是一个状态派生类(teststate1.h):
#ifndef TESTSTATE1_H
#define TESTSTATE1_H
#include "state_t.h"
class testState1 : public state_t
{
public:
testState1();
state_t *processState(int input);
};
#endif // TESTSTATE1_H
这是我的主要.cpp:
#include <QCoreApplication>
#include <QDebug>
#include "state_t.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
state_t *myState = new testState1();
myState = myState->processState(1);
myState = myState->processState(2);
myState = myState->processState(3);
myState = myState->processState(1);
return a.exec();
}
注意:代码都运行良好,这实际上是一个"正确性"的问题。
给定您的特定示例:
这是一个坏主意。您在错误的方向上引入了基类型和派生类型之间的非常紧密的耦合。基类应该不知道其派生类型。这是使它成为一个有效的基类的原因之一。在当前的方案中,每次编写派生类型时,都必须触摸基的标头,从而强制编译时依赖于基的所有客户端代码。除此之外,您还有一个循环包含依赖项。
一般来说:
在非病理性病例中,这取决于情况。关于头文件,有人可能会争辩说,最好知道文件需要哪些头文件,在这种情况下,将它们放在顶部是有意义的。但是,如果包含被认为是只会分散注意力的实现细节,则可以将它们放在底部。根据我的经验,这特别适用于模板代码的实现,以及匿名命名空间中帮助程序类和内联函数的实现。
就个人而言,我宁愿将所有包含的内容放在顶部。 您可以在其他标头中使用前向声明来解决定义顺序问题。
但这只是一种风格——"正确性"明智,没有理由你不能这样做。 您可以有效地在任何地方包含任何您喜欢的内容,只是以后可能会引起混淆!
据我说,这只是一个约定,因为每个人都这样做,如果标准开发人员需要添加一些,他不会查看文件的末尾,这将是一团糟,一些包含在顶部,一些在底部。
我更喜欢将我的包含放在顶部,否则可能会有点混乱。我对你的建议是不要在 test_t.h 中包含 teststate1.h 和 teststate2.h,而是创建 state_all.h
#include "state_t.h"
#include "teststate1.h"
#include "teststate2.h"
并在您需要的地方包括 state_all.h 而不是 state_t.h
- 通过网络、跨平台传递std::变体是否安全
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 跨 DLL 边界访问虚拟方法是否安全/可能?
- 静态 constexpr 类成员变量对多线程读取是否安全?
- 在函数结束后使用指向变量的指针是否安全?
- 逐字节删除 void* 是否安全?
- 在 RAII 构造中修改 RVO 值是否安全?
- 线程调用的函数对对象删除是否安全?
- 将对象的字节复制到数组并再次复制回来是否安全
- std::memmove在同一对象之间是否始终安全
- 使用枚举为数组编制索引是否安全?
- 返回从字符串文本创建的静态string_view是否安全?
- 在cstlib中将#include_next替换为#include是否安全
- 由并发无序映射查找线程调用的函数是否安全?
- 使用 c++ 原子时编写"y=++x"是否安全?
- 从另一个线程发出信号是否安全?
- 从其存储的回调中删除 std::函数是否安全
- 使用 std::vector::swap 方法在C++中交换两个不同的向量是否安全?
- 当我在C++中调用 struce 的只读静态成员时,线程是否安全
- 同时调用 ASIO 对象的 API 是否安全?