include语句应该驻留在哪里? 作为C++的返回新手,我尝试对包含方法进行排序。
我遵循一套特定的指导原则,我在下面的示例中详细介绍了这些指导原则。到目前为止,这对我来说是可行的(整个项目一直在编译:),但我担心将来可能会遇到问题,因此我的问题是-这是一种正确的方法吗?有更好的吗?解释它的基本逻辑是什么? 考虑以下示例: 父亲.hinclude语句应该驻留在哪里? 作为C++的返回新手,我尝试对包含方法进行排序。,c++,include,methodology,C++,Include,Methodology,我遵循一套特定的指导原则,我在下面的示例中详细介绍了这些指导原则。到目前为止,这对我来说是可行的(整个项目一直在编译:),但我担心将来可能会遇到问题,因此我的问题是-这是一种正确的方法吗?有更好的吗?解释它的基本逻辑是什么? 考虑以下示例: 父亲.h #pragma once class Father { // Some implementation }; #pragma once #include "Father.h" #include "StructC.h" class Class
#pragma once
class Father
{
// Some implementation
};
#pragma once
#include "Father.h"
#include "StructC.h"
class ClassB;
class ClassA : public Father
{
StructC struct_c_obj;
ClassB class_b_obj;
// Some implementation
};
struct StructC {
// Some implementation
};
ClassA.h
#pragma once
class Father
{
// Some implementation
};
#pragma once
#include "Father.h"
#include "StructC.h"
class ClassB;
class ClassA : public Father
{
StructC struct_c_obj;
ClassB class_b_obj;
// Some implementation
};
struct StructC {
// Some implementation
};
ClassA.cpp
#include "Father.h"
#include "ClassB.h"
#include "StructC.h"
// Some implementation
ClassB.h和ClassB.cpp没有包含的类 StructC.h
#pragma once
class Father
{
// Some implementation
};
#pragma once
#include "Father.h"
#include "StructC.h"
class ClassB;
class ClassA : public Father
{
StructC struct_c_obj;
ClassB class_b_obj;
// Some implementation
};
struct StructC {
// Some implementation
};
我遵循这些准则:
- 所有*.h均以
声明开头#pragma once
- 如果ClassA继承自类父,则必须将其同时包含在*.h和*.cpp文件中
- 如果ClassA使用ClassB(并且在类的作用域中声明了一个ClassB变量),那么它有一个
ClassB代码>在ClassA.h中的减容,以及在ClassA.cpp中包含“ClassB.h”
- 如果ClassA使用StructC(并且在类的作用域中声明了一个StructC变量),那么它必须将它同时包含在ClassA.h和ClassA.cpp中
- 如果ClassA只在ClassA.cpp文件中使用ClassD或StructE,那么它应该只在那里包含它们
- 正如一些人在下面所写的,我在示例中有一个错误-只有当ClassA有一个指向ClassB的指针或引用,而不是当它有一个简单的ClassB数据成员时,才可以在ClassA中使用ClassB的前向声明
#pragma once
是非标准的(但得到广泛支持),因此您可能/可能不想使用\ifdef
防护
至于是否需要#包含任何特定的头,这取决于。如果代码只需要一个转发声明,那么通过转发声明类型来避免导入
除了模板之外,我认为在头文件中放置长函数定义可能不太合适
话虽如此,我认为ClassA.h
实际上应该包括ClassB.h
,因为ClassA.h
的任何用户(可能使用ClassA
)都必须拥有ClassB.h
。好吧,如果它正在做类似于分配的事情。以下是我个人遵循的准则:
- 尽可能选择转发声明而不是包含。在您的情况下,
ClassA
包含一个ClassB
,因此需要一个#include“ClassB.h”
。如果ClassB
类型仅通过指针或引用出现在文件中,则向前引用就足够了
- 使头文件“自给自足”:编译永远不应该依赖于包含的顺序,包含文件应该包含/转发需要解析的所有内容
- 为确保遵守上述准则,请始终在
ClassA.cpp
中首先包含ClassA.h
,并对以下包含项使用任意顺序(我使用字母排序)
关于其他方面:
#pragma
为非标准,首选
- 请记住,永远不要转发声明标准类型:如果头文件中出现
std::string
,则必须#包含
- 如果您最终得到的头文件包含一百万个其他文件,那么您可能需要查看以减少依赖关系(本文还包含一些关于头文件的其他指南)
我通常一次都不使用pragma
,因为pragma不是标准的。您可能必须将代码移植到未定义的其他编译器,并且必须使用#ifndef#定义成语
这是因为我直接使用#ifndef#定义
第二件事:在头文件中使用多个包含不是一个好主意:我总是尽量减少它们。如果你有太多的文件,每次你对其中一个文件做一点修改,你就必须重新编译每个依赖的.cpp文件
如果是这样的话,我采用piml习惯用法,你可以找到描述(见C++示例)。无论如何,如果项目的规模没有那么大,我认为您的方法是正确的。
当ClassA有这种类型的数据成员时,不要使用ClassB的前向声明。
当它有指向ClassB的指针时,可以使用它,如:
#pragma once
#include "Father.h"
#include "StructC.h"
class ClassB;
class ClassA : public Father
{
StructC struct_c_obj;
ClassB *class_b_obj;
// Some implementation
};
关于你的回答,我有两个问题:1)为什么我们更喜欢远期申报?2) 我试图理解为什么不使用#pragma,为什么它不在标准中很重要?1)因为它减少了耦合(直接或间接包含头的任何文件在头更改时都必须重新编译)2)因为您可能希望有朝一日将代码移植到另一个编译器+1。这是一个很好的答案。我要补充的是,包含的顺序是:ClassA.h
首先,然后是任何ClassB.h
或您自己的其他类,然后是Boost头或其他库头,最后是标准库头(string
,vector
,等等)。遵循这个顺序有助于确保您自己的标题是自给自足的。您几乎不应该在头文件中包含完整的类定义。仅将转发声明头包含在