C++中的基本类设计,处理相互依赖的类

Basic class design in C++, dealing with co-dependent classes

本文关键字:处理 依赖 C++      更新时间:2023-10-16

我有两个类,一个是3D向量类(Vector3),它的成员是3个浮点数组(float[3]),另一个是3乘3矩阵类,它将其中3个向量存储在另一个数组中(Vector3[3])。我的向量类要求矩阵类绕轴旋转,而我的矩阵类要求所有东西都有向量。我使用前向声明和指针来处理它,比如这个问题:在C++中处理共依赖类的最佳方法是什么?,但必须有更好的方法来设计这个,以完全避免这种情况。目前,我在矩阵头文件上声明了一个指向Vector3的指针,然后在实现文件中用new初始化它,但这感觉很笨拙。关于如何解决这个问题,有什么建议吗?编辑:我使用矢量类来表示一个三维点,我打算绕任意轴旋转。

我希望它工作的代码:

    //Vector3.h
    #include "Matrix3.h"
    class Matrix3;
    class Vector3 {
      float xyz[3];
    };
    //Vector3.cpp
    Vector3 Vector3::rotatePoint(Vector3 o, Vector3 a,  float theta) {
Vector3 point = (*this);
Vector3 x = Vector3(1,0,0);
Vector3 y = Vector3(0,1,0);
Vector3 z = Vector3(0,0,1);
// Create new coordinate system
Vector3 new_coord[4];
new_coord[0] = o;
new_coord[1] = a.normalize();
unsigned closer_to;
if (a*x < a*y) {
    new_coord[2] = (a % x).normalize();
    closer_to = 0; // x
}
else {
    new_coord[2] = (a % y).normalize();
    closer_to = 1; // y
}
new_coord[3] = (a % new_coord[2]).normalize();
// Transform point to new coord system
Matrix3 trans_matrix = Matrix3(new_coord[0], new_coord[1], new_coord[2]);
point = trans_matrix*(point - o);
// Rotate about a by theta degrees
Matrix3 r_m(closer_to, theta);
point = r_m*point;
//Transform back to original coord system
point = (trans_matrix.inverse()*point) + o;
return point;
}        
    //Matrix3.h
    #include "Vector3.h"
    class Vector3;
    class Matrix3 {
       Vector3 rows[3];
    }

我用来让它工作的代码:

    //Vector3.h
    class Matrix3;
    class Vector3 {
      float xyz[3];
    };
    //Matrix3.h
    #include "Vector3.h"
    class Vector3;
    class Matrix3 {
       Vector3 *rows;
    }
    //Matrix3.cpp
    Matrix3::Matrix3() {
        rows = new V3[3];
    }

我接受了@n.m.和@Chris Dodd的建议,刚刚从我的Vector头中删除了Matrix3 include,并将其添加到我的Vectorimplementation文件中,如下所示:

    //Vector3.h
    class Vector3 {
        float xyz[3];
    }
    //Vector.cpp
    #include "Vector3.h"
    #include "Matrix3.h"
    //Matrix3.h
    #include "Vector3.h"
    class Vector3;
    class Matrix3 {   
        Vector3 rows[3];
    }
    //Matrix3.cpp
    #include "Matrix3.h"

由于您处理的是向量和矩阵,您可以定义一个带有维度模板(可能还有元素类型)的矩阵类——然后向量类(取决于向量的类型)将是一个维度为1的矩阵。如果你这样做,你最终只得到一个类、一组代码和完成你想要的一切所需的所有功能。您可以避免任何类间依赖关系,因为您只有一个类!

类本身看起来像这样:

template<unsigned m, unsigned n, typename T = float>
class matrix {
    T e[m * n];
public:
   T* operator [](unsigned i) { return e + i; }
   T * const operator [](unsigned i) const { return e + i; }
   /* repeat for -, *, / -- same pattern */
   matrix<m,n>& operator += (matrix<m,n> const& a) {
        for (unsigned i = 0; i < m * n; ++i) e[i] += a.e[i];
        return *this;
   }
};

然后,您应该定义任何不在类外使用等大小矩阵的函数(这就是我们使用[]运算符的原因)。注意,*和/运算符作用于所有元素,不计算通常的矩阵矩阵乘法或矩阵矩阵除法。相反,您将需要一个反转函数和一个乘法函数。

template<unsigned m, unsigned n, unsigned k>
matrix<m,k> const multiply(matrix<m,n> const& a, matrix<n,k> const& b);
template<unsigned m>
matrix<m,m> const invert(matrix<m,m> const&);
template<unsigned m, unsigned n>
matrix<n,m> const transpose(matrix<m,n> const&);

请注意,如果你有一种反转通用非平方矩阵的方法,我不知道其中的任何一个,那么上面的模板只适用于平方矩阵。填写我留给您的函数的代码作为练习。

要得到一个3向量和一个3x3矩阵,你可以这样定义它们:

typedef matrix<3,1,float> vector3f;
typedef matrix<3,3,float> matrix3x3f;

记住要添加比较运算符以及任何其他需要的运算符。

如果你愿意,你也可以添加矩阵标量和标量矩阵运算符和函数(比如说,为矩阵中的所有元素添加标量)。

如果您想更好地控制[]运算符中的元素,可以使用向量作为基类,然后将矩阵定义为向量的向量。这会给你带来同样的优势,但可能更容易适应你的心态(很多人认为向量和矩阵是不同的类型)。