带有条件编译的 c++ 标头包含顺序

Posted

技术标签:

【中文标题】带有条件编译的 c++ 标头包含顺序【英文标题】:c++ header inclusion order with conditional compilation 【发布时间】:2014-07-03 06:54:58 【问题描述】:

假设我有两个文件 A.hpp 和 B.hpp

A.hpp:

#indef DEF_A
#define DEF_A

class A
    /*implementation of class A*/
    /*some part of it needs B*/
    #ifdef DEF_B
        void method(B b)/*do something with B*/
    #endif

#endif

B.hpp:

#indef DEF_B
#define DEF_B

class B
    /*implementation of class B*/
    /*some part of it needs A*/
    #ifdef DEF_A
        void method(A a)/*do something with A*/
    #endif

#endif

我不想在 B.hpp 中包含 A.hpp(反之亦然),因为每次我需要 A.hpp 时,我都需要 B.hpp(反之亦然)。

但是当我在主文件中写:

main.cpp

#include"A.hpp"
#include"B.hpp"

int main()
    A a;
    B b;

A::method(B b) 未知。如果我颠倒包含顺序,我将只有B::method(A a)

当包含两个标头时,有没有办法同时访问这两种方法?

[编辑] 该方法也适用于没有 .cpp 文件的模板类。 [/编辑]

【问题讨论】:

为什么不使用前向声明(并通过 const 引用传递参数)? (并在 A.cppB.cpp 中移动实现) @Jarod42 如果我从不定义转发类会发生什么?和模板类? 你不能使用它的定义。 (例如,您不能使用A a;)。 @Jarod42 好的,看起来不错。我可以写a.some_method()B::method(A const& a)吗? 【参考方案1】:

我会使用前向声明,例如:

A.hpp

#indef DEF_A
#define DEF_A

class B; // Forward declaration of B

class A  // Definition of A
public:
    void method(const B& b);
;
#endif

A.cpp

#include "A.hpp"
#include "B.hpp"

void A::method(const B& b)  /* your implementation */ 

B.hpp

#indef DEF_B
#define DEF_B

class A; // Forward declaration of A

class B  // Definition of B
public:
    void method(const A& a);
;
#endif

B.cpp

#include "B.hpp"
#include "A.hpp"

void B::method(const A& a)  /* your implementation */ 

然后在 ma​​in.cpp 您同时使用 A.hppB.hpp 两者。 但是如果在 C.cpp 中你只使用 A(没有 B)你可以这样做

C.cpp

#include "A.hpp"

void foo()

    A a;
    // B b; // If uncommented, that would fail to compile.

【讨论】:

感谢您的回答,但我看到一些问题/问题... 1) 对于没有 .cpp 文件的模板类,此方法不起作用。 2)我猜如果我在A.cpp和B.cpp中包含两个文件.hpp,我仍然需要提供所有文件来编译代码 1) 对于模板类,您必须包含两个文件。 2) 如果您想在不同项目之间共享文件 A.cpp 而一个项目不使用B,您仍然可以添加一个新定义USE_B 以有条件地包含相关部分(但不要依赖包含守卫DEF_B,这可能会根据包含顺序破坏您的代码。【参考方案2】:

也许你应该试试pimpl-idiom。您可以轻松地在 .cpp 文件中隐藏实现细节,即使它是关于模板类的:

//Important: fwd declaration as Jarod42 already stated!
class B;
class AImpl;

class A

   void aMethod( B* b )
   
      impl->( b );
   
   AImpl* impl; //this will work because compiler need not to know
                //exact object size as we are creating a pointer or
                //reference...type definition in cpp


// same here for B;
//in cpp file of A and B:

class AImpl : public TemplateClass<X>

   void aMethod( B* b )
;

希望对您的问题有所帮助!

【讨论】:

以上是关于带有条件编译的 c++ 标头包含顺序的主要内容,如果未能解决你的问题,请参考以下文章

有条件地包含 C++ 标准库

C++笔试常见问题

C++:当包含从类模板派生的类的标头时,编译器警告 C4505

c++ 编译器如何处理条件中声明的类型?

如何在 Visual Studio 2019 中有条件地编译 c++ 源文件?

编译具有相同标头的 C 和 C++ 文件时未定义的引用