C++ C++;矩阵类层次结构
矩阵软件库是否应该有一个根类(例如,C++ C++;矩阵类层次结构,c++,oop,C++,Oop,矩阵软件库是否应该有一个根类(例如,MatrixBase),从中派生出更专业(或更受约束)的矩阵类(例如,SparseMatrix,uppertriangaluarmatrix等)?如果是,派生类是否应该公开/保护性/私有地派生?如果不是,它们是否应该由封装公共功能的实现类组成,并且在其他方面不相关?还有别的吗 我和一位软件开发人员同事(我不是自己)讨论过这个问题,他提到从一个更一般的类派生出一个更受限的类是一个常见的编程设计错误(例如,他举了一个例子,说明从一个类似于矩阵设计问题的椭圆类派生出
MatrixBase
),从中派生出更专业(或更受约束)的矩阵类(例如,SparseMatrix
,uppertriangaluarmatrix
等)?如果是,派生类是否应该公开/保护性/私有地派生?如果不是,它们是否应该由封装公共功能的实现类组成,并且在其他方面不相关?还有别的吗
我和一位软件开发人员同事(我不是自己)讨论过这个问题,他提到从一个更一般的类派生出一个更受限的类是一个常见的编程设计错误(例如,他举了一个例子,说明从一个类似于矩阵设计问题的椭圆
类派生出一个圆
类并不是一个好主意),即使SparseMatrix
确实是一个MatrixBase
。对于基本操作,基类和派生类提供的接口应该相同;对于专用操作,派生类将具有额外的功能,对于任意MatrixBase
对象可能无法实现。例如,我们可以计算cholesky分解仅适用于正定定义矩阵
类对象;但是,对于基类和派生类,标量乘法的工作方式应相同。此外,即使基础数据存储实现不同,运算符()(int,int)
也应按预期适用于任何类型的矩阵类
我已经开始研究一些开源的矩阵库,看起来这是一个混合的包(或者可能我正在研究一个混合的包)。我计划帮助重构一个数学库,这一直是争论的焦点,我希望能有一些意见(除非这个问题真的有一个客观正确的答案)关于什么样的设计理念是最好的,以及任何合理的方法的优缺点是什么。拥有一个矩阵基类的可能性是否有用,该基类具有允许您构建特定矩阵的方法?例如(一个非常简单的例子):
这在OpenSceneGraph框架中使用,对于我们的目的来说效果很好。但是,构建方法只是简单的旋转或反转等。但是我觉得它可以避免派生许多矩阵子类的问题。椭圆的圆子类(或矩形的正方形子类)的问题当您可以修改每个椭圆界面的一个标注,使圆不再是圆(且正方形不再是正方形)时发生
如果你只允许不可修改的矩阵,那么你是安全的,你可以用自然的方式构造你的类型层次结构。呵呵。起初我读到你的朋友说一个圆应该是一个椭圆,并写了一篇长篇的长篇大论,解释为什么他们都是椭圆 你应该听听你的朋友的话,除了我希望他们不是说SparseMatrix“is-a”MatrixBase。这个词在现实世界和建模世界中的意思不同。在建模世界中,“is-a”的意思是遵循Liskov替换原则(查一查!)。或者,这意味着SparseMatrix必须遵循MatrixBase的约定,成员函数不得要求任何额外的先决条件,并且必须满足不少于后决条件 我不知道这到底是如何应用于矩阵问题的,但如果你仔细研究我在上一段中使用的术语(LSP和合同设计),那么你应该能够很好地了解问题的答案
在您的案例中,一种可能适用的方法是在您的层次结构中采用各种通用性,并使其成为抽象接口。然后在正确响应这些接口的类中从这些接口继承。这将允许您编写允许通用的函数,但在变量过多的情况下仍然保持分离这是一个很好的问题,但是我还不确定你想用什么标准来评估这个问题
值得一提的是,我目前使用最多的一个矩阵库确实有一个通用的
Base
对象,使用了奇怪的重复出现的remplate模式做同样的事情。如果有足够多的通用方法和成员来保证一个基类,那么就应该有一个和继承。我不会将基类用作所有矩阵的通用类型,而是用作通用方法和成员的容器(使构造函数受到保护)
与Java不同,并不是每个类或结构都需要基类。请记住,简单性;复杂性使项目变得更长,更难管理,更难纠正。像这样基于继承的设计需要注意的主要问题是切片 假设MatrixBase定义了一个非虚拟赋值运算符。它复制了所有矩阵子类共有的所有数据成员。您的SparseMatrix类定义了其他数据成员。现在我们编写这个时会发生什么
SparseMatrix sm(...);
MatrixBase& bm = sm;
bm = some_dense_matrix;
这段代码没有什么意义(试图通过基类中定义的运算符直接将DenseMatrix分配给SparseMatrix)并且容易出现各种恶劣的切片行为,但这是此类代码的一个易受攻击的方面,如果您提供可通过MatrixBase*/MatrixBase访问的赋值运算符,则这种情况很有可能发生。即使我们有:
SparseMatrix sm(...);
MatrixBase& bm = sm;
bm = some_other_sparase_matrix;
…由于赋值运算符是非虚拟的,我们仍然存在切片问题。如果没有公共基类的继承,我们可以提供赋值运算符来有意义地将密集矩阵复制到稀疏矩阵,但尝试通过公共基类来实现这一点容易出现各种问题
阿西格
SparseMatrix sm(...);
MatrixBase& bm = sm;
bm = some_other_sparase_matrix;