2012-05-01 45 views
0

,因为它被认为是一个重复的这个问题被关闭:头需要相互

  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文件中,它必须保留在标题中,并且由于包含的顺序,我很头痛。

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

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


示例代码:

A.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 

的main.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是错误的。

对于此示例代码,我可以在main.cppa.h的末尾移动B::g,但使用更复杂的程序时,这并不容易。

+0

http://stackoverflow.com/questions/5239943/c-cyclical-header-dependency http://stackoverflow.com/questions/2089056/cyclic-dependency-between-header-files http://stackoverflow.com/questions/5058363/c-error-line2-has-not-been-declared/5058627#5058627 < - Dupes –

+0

告诉我们一些**最小**代码,不幸的是没有解决这个问题的捷径。 –

+0

@BillyONeal:不,我的情况是不同的,因为我的类是模板:我不能把该函数的声明放在源文件中,并且声明该类('A类;')不能解决我的问题。 –

回答

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 

#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 

BH

#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 

的main.cpp

---||--- 
+0

“坦率地说,我不确定这是否由标准保证。”我确定。 **不是**。事实上,情况恰恰相反:两阶段查找需要在第一阶段至少进行一些检查。现在,它不能在第一遍实例化模板,所以它有可能会在一致的编译器上编译。但是你不能依赖编译器来查看忽略模板预实例。 –