【问题标题】:Headers needing each other相互需要的标头
【发布时间】:2012-05-10 19:40:06
【问题描述】:

此问题已关闭,因为它被认为与以下内容重复:

  1. C++ cyclical header dependency
  2. cyclic dependency between header files
  3. C++ error: 'Line2' has not been declared

但是另一个问题与我的不同:他们提出了不同的情况,而答案不适用于我的问题。他们的回答建议将该函数放入.cpp 文件中,并在声明它之前定义类。我不能把函数放在.cpp,因为我的类是一个模板,我已经定义了这个类,但是没有用。


我有两个头文件a.hb.h。其中定义了两个模板类AB

A 的函数需要与B 的对象一起使用,反之亦然。由于它们是模板类,我不能把函数放在.cpp文件中,它必须留在头文件中,而且因为包含的顺序,我很头疼。

什么是解决这个问题的好方法?

目前我移动函数定义并找到一种方法以正确顺序包含标题,但这总是变得更加复杂。此外,我不喜欢函数定义远离类声明(例如在其他文件中)。


示例代码:

啊.h

#ifndef A_H
#define A_H

#include <iostream>
#include "b.h"
template< typename T > class B;

template< typename T >
class A {
public:
    B<void> *b;
    void f();
    void g();
};
template< typename T > void A<T>::f() {
    std::cout << "A::f" << std::endl;
    b->f();
}
template< typename T > void A<T>::g() {
    std::cout << "A::g" << std::endl;
}

#endif

b.h

#ifndef B_H
#define B_H

#include <iostream>
#include "a.h"
template< typename T > class A;

template< typename T >
class B {
public:
    A<void> *a;
    void f();
    void g();
};
template< typename T > void B<T>::f( ) {
    std::cout << "B::f" << std::endl;
}
template< typename T > void B<T>::g( ) {
    std::cout << "B::g" << std::endl;
    a->g();
}

#endif

ma​​in.cpp

#include "a.h"
#include "b.h"
int main( ) {
    A<void> a;
    B<void> b;
    a.b = &b;
    b.a = &a;

    a.f();
    b.g();

    return 0;
}

这不起作用,因为a.h 包含b.hb.h 则不能包含a.h,因此B::g 是错误的。

对于这个示例代码,我可以将B::g 移动到main.cppa.h 的末尾,但是对于更复杂的程序,这并不容易。

【问题讨论】:

标签: c++ class header include dependencies


【解决方案1】:

实际上,您的代码在我的 Visual C++ 上按原样编译。原因是编译器在实际调用它之前不会查看函数的“内部”,即在您的情况下直到 main.cpp

坦率地说,我不确定标准是否能保证这一点。如果不是,您可以随时将标题拆分为“独立”和“依赖”部分,如下所示:

a_forward.h

#ifndef A_FORWARD_H
#define A_FORWARD_H

template< typename T > class B;

template< typename T >
class A {
public:
    B<T> *b;
    void f();
    void g();
};

#endif

啊.h

#ifndef A_H
#define A_H

#include <iostream>
#include "a_forward.h"
#include "b_forward.h"

template< typename T > void A<T>::f() {
    std::cout << "A::f" << std::endl;
    b->f();
}

template< typename T > void A<T>::g() {
    std::cout << "A::g" << std::endl;
}

#endif

b_forward.h

#ifndef B_FORWARD_H
#define B_FORWARD_H

template< typename T > class A;

template< typename T >
class B {
public:
    A<T> *a;
    void f();
    void g();
};

#endif

b.h

#ifndef B_H
#define B_H

#include <iostream>
#include "a_forward.h"
#include "b_forward.h"

template< typename T > void B<T>::f( ) {
    std::cout << "B::f" << std::endl;
}

template< typename T > void B<T>::g( ) {
    std::cout << "B::g" << std::endl;
    a->g();
}

#endif

ma​​in.cpp

---||---

【讨论】:

  • “坦率地说,我不确定标准是否能保证这一点。”我确定。 不是。事实上恰恰相反:两阶段查找至少需要对第一遍进行一些检查。现在,它无法在第一次通过时实例化模板,因此它可能会在符合标准的编译器上进行编译。但是你不能依赖编译器来忽略模板预实例化。
猜你喜欢
  • 1970-01-01
  • 2010-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-04
  • 1970-01-01
  • 2015-06-16
相关资源
最近更新 更多