模板中的循环依赖项 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.h
、B.h
和 C.h
中的任何一个以及所有三个 class 定义将被引入以满足依赖关系。
乍一看,我不认为你可以这样做,除非所有三个模板 class 都在同一个 header 文件中,原因是:
模板通常必须完整存在于header文件中。
你不能有循环依赖,有或没有模板。为了解决这个问题,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
我遇到了模板 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.h
、B.h
和 C.h
中的任何一个以及所有三个 class 定义将被引入以满足依赖关系。
乍一看,我不认为你可以这样做,除非所有三个模板 class 都在同一个 header 文件中,原因是:
模板通常必须完整存在于header文件中。
你不能有循环依赖,有或没有模板。为了解决这个问题,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