在我的数学库中我用C ++创建,我有一个Quaternion类和一个Vector3类。它们的布局如下:
Vector3.hpp:
#pragma once
template<typename T>
struct Vector3
{
//...
};
template<typename T>
Vector3<T> operator+(Vector3<T> lhs, Vector3<T> rhs);
#include "Vector3.inl"
Vector3.inl
template<typename T>
Vector3<T> operator+(Vector3<T> lhs, Vector3<T> rhs)
{
return Vector3<T>(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z);
}
//...
Quaternion
类的布局相同。
目前我使用Quaternion
类的Vector3
类用于函数参数,因此它#include
是Vector3.hpp
标题。但现在我需要使用Quaternion
类中的Vector3
类来实现某些功能。
由于这仅在函数的实现中需要,我通常只将#include
放在源文件中,但由于我使用内联文件,并且它们包含在头文件中,这样做只会导致一堆编译器错误,因为它们相互依赖。
当我只能使用标题/内联文件时,如何解决这种循环依赖?
答案 0 :(得分:0)
处理循环依赖的最佳方法是首先避免它!花一些时间重新考虑设计,改变功能,拆分类等是明智的。
让我们假设没有循环依赖的情况如下:
template <typename T>
struct Vector{
...
};
template<typename T>
struct VectorUser{
Vector<T> v;
...
};
如果可以通过前向声明解决循环依赖问题,例如:
template <typename T>
struct Vector{
void printout(const VectorUser<T> &user);
...
};
VectorUser
的前向声明与Vector<T>::printout()
声明后VectorUser
的声明,即 VectorUser.inl (毕竟,没有人可以使用Vector)无论如何不包括 VectorUser.h )会产生所需的结果:
//Vector.h:
template <typename T>
struct VectorUser;
template <typename T>
struct Vector{
void printout(VectorUser<T> &user);
...
};
//VectorUser.h:
template<typename T>
struct VectorUser{...}
};
template<typename T>
void Vector<T>::printout(VectorUser<T> &user){
user.printout();
}
但如果前瞻声明还不够呢?例如:
template <typename T>
struct Vector{
VectorUser<T> user;
...
};
好吧,即使没有模板也不会让它编译。我在代码中经常看到至少两个选项:
使Vector<T>::user
成为指针/引用,因此前向声明就足够了。
将Vector<T>
拆分为两个类:VectorUser
中使用的一个基类和另一个基类,所有功能都取决于VectorUser
。
我会提倡第二种解决方案,但它可能并不总是可行的。