【问题标题】:Using forward reference使用前向引用
【发布时间】:2012-07-19 00:43:55
【问题描述】:

我有一个圆形标题问题,与这里已经问过的大多数问题不同。我有两个相互依赖的类,但不是成员,所以不要遇到编译器无法计算类大小的问题。所以我可以使用前向声明来打破循环。

但是,我不希望客户端必须包含这两个标头才能使用我的类。标头应该是自包含的,因此用户不需要知道这种依赖关系。有没有办法做到这一点?

编辑:棘手的部分是 A 和 B 必须只定义标题。

在标题 A.hpp 中

#ifndef A_HPP
#define A_HPP

#include "B.hpp"

struct A
{
    B foo() { ... }
};

#endif

在标题 B.hpp 中

#ifndef B_HPP
#define B_HPP

struct A;

struct B
{
    void bar()
    {
        A a = A();
        ...
    }
};

#endif

在 main.cpp 中

#include "B.hpp"
B().bar(); // error: 'a' uses undefined class 'A'

【问题讨论】:

  • 如果A.hpp 包含B.hpp,为什么不在main.cpp 中包含A.hpp 而不是B.hpp
  • A实际上是B的内部实现细节。我真的不希望客户对此有所了解
  • B 是否应该是仅标头实现?不然为什么头文件里有bar的代码?
  • 我想说实际上将课程移至B.hpp,然后如果属于B

标签: c++ header-files


【解决方案1】:

标题 B.hpp

#ifndef B_HPP
#define B_HPP

struct A;

struct B
{
   void bar();
};

#endif

来源 B.cpp

#include "A.hpp"

void B::bar()
{
   A a;
}

编辑。因此,如果您想要仅实现标头,请使用 AndreyT 解决方案。

【讨论】:

  • 这种方法会丢失内联属性。
  • @AndreyT 过早的优化是邪恶的,不是吗?
  • 我应该说我希望 A 和 B 仅作为标题。这是给图书馆的。
  • @ForEveR: inline 很久以前就不再是优化了。优化应该留给编译器。您的责任是确保您不会从编译器中夺走优化机会。这样做比过早优化更邪恶。
  • @AndreyT 但如果实现在 .cpp 文件中,则内联可能不会丢失。这取决于链接器。
【解决方案2】:

如果两个头文件都包含要求其他类型完整的代码,那么在一般情况下,它不可能由独立的头文件实现。

在您的具体示例中(太简单而无法代表),您可以简单地将定义 if B::bar 移动到 A.hpp

inline void B::bar()
{
    A a = A();
    ...
}

当然,在A.hpp 中定义B 的方法看起来并不优雅。

如果B::bar 的“内联性”对您很重要,那么“工业”解决方案将涉及将B::bar 的定义放入额外的头文件B_aux.hpp。当您包含标题时,您应该在包含所有“正常”标题之后包含“辅助”标题,即在main.cpp 中您将拥有

#include "A.hpp"
#include "B.hpp"
#include "C.hpp"
...
#include "B_aux.hpp"
...

但这显然不是一种“自成一体”的方法。

【讨论】:

  • 如果我将代码移动到 A.hpp 并将 A.hpp 包含在几个不同的 .cpp 文件中,这不会导致多定义链接错误吗?
  • 我不在乎内联的(想象的)性能“优势”,所以这不是问题
  • @thehouse:如果将B::bar 放入A.hpp,只要声明为inline,就不会产生多个定义错误。
【解决方案3】:

只需将#include "A.hpp" 添加到B.hpp 的底部。你仍然会有一个循环包含,但现在它不会伤害任何东西。

【讨论】:

  • 我想这有点像在没有实际移动的情况下移动课程:p
  • @MarkRansom 我已经在包含保护的内部和外部尝试过这个,但它没有帮助。同样的错误。
【解决方案4】:

通常循环包含表明这两种类型密切相关,这可能意味着它们是一个组件。如果是这种情况,那么只需将两个标头合并为一个组件的标头,首先是类型声明,最后是成员函数定义,当这两种类型都已完全定义时。

【讨论】:

    猜你喜欢
    • 2010-10-16
    • 2017-01-20
    • 2020-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多