模板类

时间:2015-11-19 15:56:03

标签: c++ circular-dependency

我遇到了与模板类的循环依赖关系的问题。我有类似以下的内容,

// 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];
};

前瞻性声明不起作用。我已经尝试从声明中删除定义并在声明类后包含相关的hxx文件,但也没有运气。任何帮助,将不胜感激。感谢

5 个答案:

答案 0 :(得分:3)

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

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];
};

它适用于此,因为您只使用其他类中对象的引用,因此您只需要声明。但我不知道它是否适用于您的真实用例。

无论如何已经说过,常见的超类只在这里使用,因为它很简单,但你可以为每个类使用一个接口或超类

答案 1 :(得分:2)

我认为您忘记向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);
    }
};

EDIT2:

这也编译:

// 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);
}

答案 2 :(得分:2)

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

稍微好一点,您可以有三个单独的头文件,每个类一个,其中包含其他两个类的标题下面类的定义,但上面构造函数的定义。示例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

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

答案 3 :(得分:0)

第一眼看,我不认为你可以这样做,除非所有三个模板类都在同一个头文件中,原因如下:

  1. 模板通常必须存在于头文件中。

  2. 您不能使用或不使用模板进行循环依赖。为了解决这个问题,一个类只能在其标题中包含指向或依赖类的引用。然后类'cpp文件可以包含依赖文件的头。

答案 4 :(得分:0)

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

A(B const& b) :

应该是:

A(B<T> const& b) :