是否存在两次包含相同标题实际上有用的情况?

时间:2012-12-18 19:37:02

标签: c++ c

为我的h / hpp文件创建标题保护对我来说一直是标准做法,但我想知道,为什么甚至可以两次包含相同的文件?是否存在实际需要不受保护的标题的情况?

6 个答案:

答案 0 :(得分:8)

“参数化”头文件可用于模拟C中的C ++ - ish样式模板。在这种情况下,头文件将取决于许多宏(“模板参数”)。它将根据这些宏的实际“值”生成不同的代码。

因此,此类标头的典型用法看起来是一系列“模板参数”宏定义,后跟#include指令,后跟另一个“模板参数”宏定义序列,后跟相同的{{ 1}},等等。

https://stackoverflow.com/a/7186396/187690

使用此技术时,您将看到没有任何包含警卫的头文件或包含仅包含文件一部分的保护的头文件。

答案 1 :(得分:6)

像Boost.PP这样的东西通过多次包含标题来做很多技巧。它基本上允许原始形式的循环。

此外,X-Macros设计为多次包含。

答案 2 :(得分:6)

在C:

#undef NDEBUG
#include <assert.h>

...code using active asserts...

#define NDEBUG
#include <assert.h>

...code using disabled asserts...

冲洗并重复。 C ++中的模拟使用标题<cassert>代替。

因此,有时候有理由两次包含标题。不经常,但有理由这样做。

答案 3 :(得分:1)

这样的案例很少见,而且当它们确实存在时,重新设计更适合。我能想到的是积累声明的标题:

//functions.h
virtual void foo();
virtual void goo();

//classes.h
class A : public Base
{
    #include "functions.h"
};

class B : public Base
{
    #include "functions.h"
};

如果functions.h包含警卫,这将不起作用,但话又说回来,这是非常尴尬的代码......

答案 4 :(得分:1)

想象一下,你正在为你的微型引擎编写自己的模板数组包装器(元素是指针),其中数组可以是:

  • 动态或静态
  • 索引/订购是否重要
  • 您可以删除数组外部或
  • 内的元素(不只是从数组中删除)

因此,您可以创建一个所有这些处理的类,但它总是会检查我们能做什么或不能做什么。最好是创建单独的类,但是在这里我们有相同的代码,你可以(如果不小心)在其中一个函数中犯错,再添加一个新函数会更慢。

最好是使用“参数化”头文件(如AnT所述)并简单地创建类似

的类
  • Cl_Array_Dy,Cl_Array_DyIn,Cl_Array_DyDel,Cl_Array_DyInDel
  • Cl_Array_St,Cl_Array_StIn,Cl_Array_StDel,Cl_Array_StInDel

代码示例:

// TestDfM.h

#ifndef TEST_DFM_H
#   define TEST_DFM_H

    // first we need to make sure neither of these is defined
#   ifdef Df_ARG1
#       undef Df_ARG1
#   endif
#   ifdef Cl_First
#       undef Cl_First
#   endif
#   ifdef Cl_Second
#       undef Cl_Second
#   endif
#   ifdef Df_FIRST
#       undef Df_FIRST
#   endif
#   ifdef Df_SECOND
#       undef Df_SECOND
#   endif
#   ifdef TEST_DF_H
#       undef TEST_DF_H
#   endif

    // we need this
#   define Df_FIRST 1
#   define Df_SECOND 2

    // first class creation
#   define Df_CLASS Df_FIRST
#   define Df_ARRAY Cl_First
#   include "TestDf.h"

    // cleanup (after 1st)
#   undef Df_CLASS
#   undef Df_ARRAY

    // second class creation
#   define Df_CLASS Df_SECOND
#   define Df_ARRAY Cl_Second
#   define Df_ARG1
#   include "TestDf.h"

    // cleanup (after 2st)
#   undef Df_CLASS
#   undef Df_ARRAY
#   undef Df_ARG1

    // so we theoretically cannot include TestDf.h anymore (anywhere)
#   define TEST_DF_H

#endif // TEST_DFM_H

// TestDf.h

// nothing to do here if the main header for this was not included
// also we should only call this inside the main header
#if defined(TEST_DFM_H) && !defined(TEST_DF_H)
#   include "../Includes.h"

    class Df_ARRAY {
    public:
        int m_shared;

#   ifndef Df_ARG1
        Df_ARRAY(int in_shared=0) { m_shared= in_shared; }
        void f_info() { printf("out: %d\n", m_shared); }
#   else
        int m_x;
        Df_ARRAY(int in_shared=0, int in_x= 7) { m_shared= in_shared; m_x= in_x; }
        void f_info() { printf("out: %d [also has %d]\n", m_shared, m_x); }
#   endif

#   if Df_CLASS == Df_FIRST
        void f_class() { printf("1st\n"); }
#   elif Df_CLASS == Df_SECOND
        void f_class() { printf("2nd\n"); }
#   endif
    };

#endif // TEST_DFM_H

// Main.cpp

#include "Array/TestDfM.h"

int main(int argc, char** argv) {
    Cl_First a(6);
    Cl_Second b(2);
    a.f_class(); // 1st
    b.f_class(); // 2nd
    a.f_info(); // out: 6
    b.f_info(); // out: 2 [also has 7]
    return 0; }

答案 5 :(得分:0)

只要遇到头文件,就会以文本方式包含它们。没有任何真正的理由说明它们不能被包括在一次以上。如果标题仅用于声明而没有定义(并且没有使用默认参数的模板声明),那么多次包含它们甚至没有任何问题。

<cassert>是不止一次包含文件的规范示例:您可以更改NDEBUG的定义,并在一个翻译单元中从assert()宏获取不同的行为。

现在,像include_once这样的东西只包含一个文件,结果证明并不像人们想象的那样微不足道。这是一个不清楚应该包含foo.h的频率的示例:

#include_once "foo.h"
#include_once "./foo.h"
#include_once "bar/foo.h"

假设include_once只包含一次文件,应该多久foo.h包含一次?所有三个文件都可以容易地引用相同的物理文件,但这可能不容易看到,例如,因为一个是到另一个文件的链接。似乎最好将控制权交给程序员如何控制它们最终被使用的频率。