你应该依赖于它包含的标题的另一个标题吗?

时间:2009-12-23 03:11:36

标签: c++ header

假设所有标题都受到保护,假设您有一个抽象数据类型。

#include "that.h"
#include "there.h"

class Foo {
 protected:
  // Functions that do stuff with varOne and varTwo
 private:
  that varOne; 
  there varTwo;
 ...
};

然后在从foo继承的类中(因此包括foo.h),你还会打扰包括那个吗?通常我所做的是包括类所需的所有内容,无论是否已经从另一个包含它们。这是多余的吗?

6 个答案:

答案 0 :(得分:3)

冗余包含头文件有一个缺点,否则这些头文件将直接包含在内:它会强制编译器重新打开并重新解析它们。例如,在

A.H:

#ifndef __A_H
#define __A_H
// whatever
#endif

b.h:

#ifndef __B_H
#define __B_H
#include "a.h"
// whatever
#endif

c.cpp:

#include "a.h"
#include "b.h"
//whatever

啊必须打开并阅读两次 - 虽然#ifndef会使preproc忽略第二个包含中的内容,但它仍然必须至少加载文件从磁盘读取其字节从#ifndef#endif

这会降低编译速度。它不会打破你的构建或任何东西,它只会是一个非常大的项目的烦恼,编译可能需要很长时间。

如果在标题中使用#pragma once,则有意识的编译器很可能会将文件名缓存在更高级别,并忽略第二次包含a.h。这也可以加快构建速度。

答案 1 :(得分:1)

根据我的经验,最好在Foo.h中转发声明而不是包含它们,因为它们在技术上并不需要,因为它们是通过引用传递的。

在那个cade中,Foo.h看起来像:

class that;
class there;

class Foo
{
    public:

        void func( that &param ) = 0;
        void funcTwo( there &param ) = 0;
        ...
};

答案 2 :(得分:1)

问题是你最终会以这种方式在obj文件中包含额外的东西。标题守卫不会阻止这种情况。你引用的任何东西都必须在你的对象中,所以不要只有很多标题包括其他标题然后包含在其他地方。如果你对标题很草率并且有很多文件,那么你很快会得到一个膨胀的代码大小和慢的编译时间。

答案 3 :(得分:0)

这取决于你。如果很明显超类已经包含它们(即没有查看它的标题)那么省略#include是有意义的。当然,您可以自由添加它们以保证安全。

答案 4 :(得分:0)

这不一定是多余的。您有单独的头文件和源文件这一事实意味着只要源文件提供头文件的定义,您就可以交换src和头文件。

.h文件应该只包含标题中使用的内容。例如,如果标题中没有io声明,则不需要stdio,相反,如果它使用printf,它只应该放在src文件中。

但是可能存在这样的情况:您可以使用的一个标头需要特定的包含,而另一个标头不会(例如,当一个标头比另一个标头更具限制性时),在这种情况下最好复制。 h包括。

由于它是有问题的,它对你生成的最终对象/ exe没有任何影响,并且它不会增加任何值得担心的编译时间,因此最好包含它们以防万一你想要使用不同的某个时候.h文件。

编辑:更具体的例子 inc1.h

#ifndef INC1_H
#define INC1_H
inc1_struct {                                                            
   int x;
};
#endif

inc2.h

#ifndef INC2_H
#define INC2_H
#include "inc1.h"
void inc2_f();
struct inc1_struct *inc2_callinc1();
#endif 

prog.cpp     #include“inc1.h”     #include“inc2.h”
    #包括     #include

void inc2_f() {
   printf("inc2_f\n");
}

struct inc1_struct *inc2_callinc1() {
   return (struct inc1_struct*) malloc(sizeof(struct inc1_struct));
}

int main(int argc, char **argv) {
   struct inc1_struct *s = inc2_callinc1();
   return 0;
}

这会编译,但是假设您不想公开

struct inc1_struct *inc2_callinc1();

in inc2.h

然后你不需要在inc2.h文件中包含inc1.h,但是如果你不想在prog.cpp中删除inc2_callinc1()的定义,那么你需要包含inc1。小时。

答案 5 :(得分:0)

  

然后在继承的类中   会foo(因而包括foo.h),会的   你还打扰包括那个和   此?

通常我会为标题直接使用的任何类型包含标题(带保护)。

但是,我经常删除基类必须包含它们的派生类,因为被覆盖的成员函数原型 - 对于这个是正确的在您的示例中

最终这是你的选择,但你也可以考虑你认为标题有多大可能发生变化 - 因为这是唯一真正重要的时刻。