首页 文章

解决模板类之间的循环依赖关系

提问于
浏览
19

我有两个类, Foo<T>Bar<T> ,派生自 Base . 每个都覆盖一个方法 virtual Base* convert(ID) const ,其中 ID 是一个唯一标识 FooBar (假装它是 enum )的特定实例的类型的实例 . 问题是 Foo::convert() 需要能够返回 Bar 实例,同样 Bar::convert() 需要能够实例化 Foo . 由于它们都是模板,因此导致 Foo.hBar.h 之间存在循环依赖关系 . 我该如何解决这个问题?

Edit: 前向声明不起作用,因为每个方法的实现需要另一个类的构造函数:

Foo.h

#include <Base.h>

template<class T> class Bar;

template<class T>
class Foo : public Base { ... };

template<class T>
Base* Foo<T>::convert(ID id) const {

    if (id == BAR_INT)
        return new Bar<int>(value); // Error.

    ...

}

Bar.h

#include <Base.h>

template<class T> class Foo;

template<class T>
class Bar : public Base { ... };

template<class T>
Base* Bar<T>::convert(ID id) const {

    if (id == FOO_FLOAT)
        return new Foo<float>(value); // Error.

    ...

}

该错误自然是“无效使用不完整类型” .

4 回答

  • 10

    您需要做的是从实现中分离类声明 . 所以像

    template <class T> class Foo : public Base
    {
        public:
        Base* convert(ID) const;
    }
    
    template <class T> class Bar : public Base
    {
        public:
        Base* convert(ID) const;
    }
    
    template <class T> Base* Foo<T>::convert(ID) const {return new Bar<T>;}
    template <class T> Base* Bar<T>::convert(ID) const {return new Foo<T>;}
    

    这样,在定义函数时,您就拥有了完整的类定义 .

  • 20

    您应该在任一标头中使用模板类前向声明

    template <class T>
    class X;
    

    是完美的模板类前向声明 .

  • 12

    (更新)您应该能够处理与非模板类相同的操作 . 像这样写你的Bar.h. (同样对于Foo.h)

    #if !defined(BAR_H_INCLUDED)
    #define BAR_H_INCLUDED
    
    template <class T>
    class Foo;
    
    template <class T>
    class Bar
    {
        /// Declarations, no implementations.
    }    
    
    #include "Foo.h"
    
    template <class T>
    Base* Bar<T>::Convert() {  /* implementation here... */ }
    #endif
    
  • 8

    James Curran的回答是天赐之物 . 一般来说,James的想法是限制所需头文件的包含,直到需要来自包含头文件的成员('声明)为止 . 举个例子:

    t1.hh

    #ifndef S_SIGNATURE
    #define S_SIGNATURE
    
    struct G; // forward declaration
    
    template<typename T>
    struct S {
      void s_method(G &);
    };
    
    #include "t2.hh" // now we only need G's member declarations
    
    template<typename T>
    void S<T>::s_method(G&g) { g.g_method(*this); }
    
    #endif
    

    t2.hh

    #ifndef G_SIGNATURE
    #define G_SIGNATURE
    
    template<typename T>
    struct S; // forward declaration
    
    struct G {
      template<typename T>
      void g_method(S<T>&);
    };
    
    #include "t1.hh" // now we only need S' member declarations
    
    template<typename T>
    void G::g_method(S<T>& s) { s.s_method(*this); }
    
    #endif
    

    t.cc

    #include "t1.hh"
    #include "t2.hh"
    
    S<int> s;
    G g;
    
    int main(int argc,char**argv) {
      g.g_method(s); // instantiation of G::g_method<int>(S<int>&)
    }
    

相关问题