模板中的循环依赖项 Class

Cyclic Dependencies in Template Class

我遇到了模板 classes 的循环依赖问题。我有类似下面的内容,

// A.hxx
template<typename T>
class B;

template<typename T>
class C;

template<typename T>
class A
{
    A(T const& x, T const& y, T const& z)
    {
        data[0] = x;
        data[1] = y;
        data[2] = z;
    }

    A(B<T> const& b) :
     A(b.x(),b.y(),b.z())
    {}

    A(C<T> const& c) :
     A(c.x(),c.y(),c.z())
    {}


    T x() {return data[0];}
    T y() {return data[1];}
    T z() {return data[2];}

    T data[3];
};



// B.hxx
template<typename T>
class A;

template<typename T>
class C;

template<typename T>
class B
{
    B(T const& y, T const& z, T const& x)
    {
        data[0] = y;
        data[1] = z;
        data[2] = x;
    }

    B(A<T> const& a) :
     B(a.y(),a.z(),a.x())
    {}

    B(C<T> const& c) :
     B(c.y(),c.z(),c.x())
    {}

    T x() {return data[2];}
    T y() {return data[0];}
    T z() {return data[1];}

    T data[3];
};



// C.hxx
template<typename T>
class A;

template<typename T>
class B;

template<typename T>
class C
{
    C(T const& z, T const& x, T const& y)
    {
        data[0] = z;
        data[1] = x;
        data[2] = y;
    }

    C(A<T> const& a) :
     C(a.z(),a.x(),a.y())
    {}

    C(B<T> const& b) :
     C(b.z(),b.x(),b.y())
    {}

    T x() {return data[1];}
    T y() {return data[2];}
    T z() {return data[0];}

    T data[3];
};

前向声明不起作用。我曾尝试在声明 class 后打破声明中的定义并包含相关的 hxx 文件,但也没有成功。任何帮助,将不胜感激。谢谢

我想你忘了为 B 和其他 类 提供模板参数。 试试这个:

A(B<T> const& b) :      // B<T> should be better than B
 A(b.x(),b.y(),b.z())
{}

编辑:

这编译得很好:

template <class T>
class A;

template <class T>
class B;


template <class T>
class A
{
    void func(B<T> par) {
        par.func(this);
    }
};

template <class T>
class B
{
    void func(A<T> par) {
        par.func(this);
    }
};

编辑 2:

这也编译:

// A.h
template <class T>
class B;

template <class T>
class A
{
  public:
    void func(B<T>& par) {
        par.func(*this);
    }
};

// B.h
template <class T>
class A;

template <class T>
class B
{
    void func(A<T> par) {
        par.func(*this);
    }
};

// main.cpp
#include "a.h"
#include "b.h"

int main()
{
    A<int> a;
    B<int> b;
    a.func(b);
}

这是第一个想到的解决方案:在同一个头文件中定义所有三个 classes。在 classes 中声明转换构造函数,但暂时不要为它们提供定义。在定义所有 classes 之后(在头文件的底部)提供所有 classes 之外的转换构造函数的内联定义。

稍微好一点,您可以拥有三个单独的头文件,每个头文件一个 class,其中包含另外两个 classes 下方 的头文件] class 的定义但 上面 构造函数的定义。示例 A.h 文件(未经测试):

#ifndef A_H
#define A_H

template<typename T> class B;
template<typename T> class C;

template<typename T>
class A
{
    A(T const& x, T const& y, T const& z) {
        data[0] = x;
        data[1] = y;
        data[2] = z;
    }

    A(B<T> const& b);

    A(C<T> const& c);

    T x() {return data[0];}
    T y() {return data[1];}
    T z() {return data[2];}

    T data[3];
};

#include <B.h>
#include <C.h>

template<typename T>
inline A::A(B<T> const& b) :
    A(b.x(),b.y(),b.z())
{}

template<typename T>
inline A::A(C<T> const& c) :
    A(c.x(),c.y(),c.z())
{}

#endif

重复 classes B 和 C,现在您应该能够包含 A.hB.hC.h 中的任何一个以及所有三个 class 定义将被引入以满足依赖关系。

乍一看,我不认为你可以这样做,除非所有三个模板 class 都在同一个 header 文件中,原因是:

  1. 模板通常必须完整存在于header文件中。

  2. 你不能有循环依赖,有或没有模板。为了解决这个问题,class 只能在其 header 中包含指向从属 class 的指针或引用。然后class'cpp文件可以包含依赖文件的header

您没有提供正确的模板化类型名称。例如这个构造函数:

A(B const& b) :

应该是:

A(B<T> const& b) :

在这种特殊情况下,我会尝试使用接口或超级classes 来消除循环依赖。基础知识:为了消除循环依赖,每个真正的 class 继承自一个仅声明其他 classes 中使用的方法的超 class。它可能实现不依赖于其他 classes 的那些,或者仅仅是一个接口(只有虚拟方法)。唯一的规则是你必须只使用指针或引用其他 classes 的对象来避免切片问题。这里更简单,因为所有 classes 都继承自一个公共的,但在更一般的用例中,每个都可以有自己的 superclass。可能是:

D.hxx

#ifndef _D
#define _D

template<typename T> 
class D {
public:
    virtual T x() const = 0;
    virtual T y() const = 0;
    virtual T z() const = 0;
    virtual ~D() = 0;    // better to add a virtual destructor...
};

#endif

这样,其他文件变成(比如 A.hxx):

#include "d.h"

template<typename T>
class A: public D<T>
{
public:
    A(T const& x, T const& y, T const& z)
    {
        data[0] = x;
        data[1] = y;
        data[2] = z;
    }

    A(class D<T> const& d): A(d.x(), d.y(), d.z()) {} // for C++11 and above...

    T x() const { return data[0]; }
    T y() const { return data[1]; }
    T z() const { return data[2]; }

private:
    T data[3];
};

它在这里工作,因为你只使用来自其他 classes 的对象的引用,所以你只需要声明。但我不知道它是否适用于您的实际用例。

无论如何,如前所述,这里只使用普通的 superclass 因为它很简单,但是您可以使用一个接口或 superclass per class