C++矩阵类架构设计:继承还是模板特化?
最优设计方案:CRTP+模板特化组合
这个方案完美解决你的痛点:既复用通用矩阵的所有方法,又能给特定维度矩阵添加专属功能,还不用做返回值强制转换。
1. 先写CRTP基类封装通用逻辑
把所有通用方法(比如转置、元素访问、通用矩阵运算)放在一个CRTP基类里,核心是让基类知道最终的派生类类型,这样通用方法可以直接返回派生类对象:
template <typename Derived, typename T, std::size_t M, std::size_t N> class MatrixBase { protected: std::array<std::array<T, N>, M> m_data; // 内部存储放在基类,所有子类共享 public: // 转置方法:直接返回Derived类型(也就是特化类/通用类本身) auto transpose() const { Derived result; for (std::size_t i = 0; i < M; ++i) { for (std::size_t j = 0; j < N; ++j) { result.m_data[j][i] = m_data[i][j]; } } return result; } // 元素访问通用方法 T& operator()(std::size_t row, std::size_t col) { return m_data[row][col]; } const T& operator()(std::size_t row, std::size_t col) const { return m_data[row][col]; } // 其他通用方法:比如矩阵加法、标量乘法等都可以放这里 };
2. 通用矩阵类直接继承基类
通用的Matrix<T,M,N>不需要写任何额外代码,直接继承基类,派生类就是自身:
template <typename T, std::size_t M, std::size_t N> class Matrix : public MatrixBase<Matrix<T, M, N>, T, M, N> { public: // 继承基类的构造函数(如果需要自定义构造,再加) using MatrixBase<Matrix<T, M, N>, T, M, N>::MatrixBase; };
3. 特定维度的特化类(以2x2为例)
特化类同样继承CRTP基类,这样自动获得所有通用方法,同时可以添加专属方法,甚至重写通用方法做维度优化:
template <typename T> class Matrix<T, 2, 2> : public MatrixBase<Matrix<T, 2, 2>, T, 2, 2> { public: using MatrixBase<Matrix<T, 2, 2>, T, 2, 2>::MatrixBase; // 2x2矩阵专属方法:绕原点旋转theta弧度 void rotate(T theta) { const T cos_theta = std::cos(theta); const T sin_theta = std::sin(theta); // 缓存当前元素避免覆盖 T a = (*this)(0,0), b = (*this)(0,1); T c = (*this)(1,0), d = (*this)(1,1); (*this)(0,0) = a * cos_theta - b * sin_theta; (*this)(0,1) = a * sin_theta + b * cos_theta; (*this)(1,0) = c * cos_theta - d * sin_theta; (*this)(1,1) = c * sin_theta + d * cos_theta; } // 可选:重写转置方法,针对2x2做优化(比通用循环更高效) auto transpose() const { Matrix<T,2,2> result; result(0,0) = (*this)(0,0); result(0,1) = (*this)(1,0); result(1,0) = (*this)(0,1); result(1,1) = (*this)(1,1); return result; } };
4. 使用效果
调用通用方法时,返回值直接是特化类类型,完全不用强制转换:
#include <array> #include <cmath> int main() { Matrix<double, 2, 2> mat; mat(0,0) = 1; mat(0,1) = 2; mat(1,0) = 3; mat(1,1) = 4; // transpose返回的就是Matrix<double,2,2>,直接赋值 auto transposed = mat.transpose(); // 调用专属的rotate方法 mat.rotate(M_PI / 2); return 0; }
方案优势
- 零代码重复:通用逻辑只写一次在基类,所有矩阵类共享。
- 无强制转换:CRTP让基类方法直接返回最终类型,符合使用直觉。
- 扩展性强:特化类可以自由添加专属方法,也能重写通用方法做维度特定优化。
- 类型统一:
Matrix<T,2,2>就是你要的特化类,不需要额外定义Matrix2x2(如果需要别名,加一行template <typename T> using Matrix2x2 = Matrix<T,2,2>即可)。
替代方案:模板别名+非成员扩展函数
如果不想用CRTP,也可以用模板别名简化特化类的写法,把专属方法写成非成员函数:
// 通用矩阵类,包含所有通用方法 template <typename T, std::size_t M, std::size_t N> class Matrix { private: std::array<std::array<T, N>, M> m_data; public: Matrix<T, N, M> transpose() const { Matrix<T, N, M> result; // 通用实现 return result; } // 元素访问方法... }; // 模板别名,简化2x2矩阵写法 template <typename T> using Matrix2x2 = Matrix<T, 2, 2>; // 专属旋转方法作为非成员函数(需要友元才能访问私有成员) template <typename T> void rotate(Matrix2x2<T>& mat, T theta) { // 实现旋转逻辑 }
但这个方案的缺点是专属方法是全局函数,封装性不如成员方法,而且访问私有成员需要加友元声明,不如CRTP方案简洁直观。
内容的提问来源于stack exchange,提问作者Julienchz
相关产品推荐
相关产品推荐

