查看您的源代码后,这是我所看到的!在您的私人成员课程中,您的行和列大小不应该是 int 类型,它们应该是 unsigned int。它们应该是 unsigned int 的原因是因为没有 unsigned int 的 int 默认是有符号值,这意味着它可以有负数。对于没有意义的矩阵中的行数和列数。对于 unsigned int 值,它的范围为 unsigned int 的 [0, max_value]。另一件需要注意的事情是,如果有人在行或列大小或两者中输入 0 怎么办?那么你仍然没有一个有效的矩阵。这里需要做一点逻辑;如果有人输入 0,那么您必须决定默认行为应该是什么。是否要使用默认值 10? 1x1 的值也没有意义!现在你可以有 1x4 或 4x1,那么这些将不完全是一个矩阵,但它们将是按顺序主要是行或列的向量。老实说,您在基本构造函数中没有任何参数的默认矩阵大小应该是 2x2。如果用户为任一参数指定 1,则另一个参数应大于 1。这里也不需要 2 个构造函数,这是重复代码,只需 1 个构造函数即可完成。也不需要调用你的析构函数,当这个类对象超出范围时会自动调用它。
对于矩阵,您认为元素应该是公开的以便于访问吗?
现在,您的(元素)数组是私有的,这意味着没有外部类可以访问它们,现在如果这是您想要的行为,那么您将需要函数来访问它们并在值需要更改时设置它们。
根据您的类实现,我在这里向您展示了我上面提到的更改。
#include <vector>
#include <array>
class Matrix {
private:
const unsigned int DEFAULT_SIZE;
unsigned int size_row, size_column;
double* elements;
public:
explicit Matrix( unsigned int row = 0; unsigned int column = 0 );
~Matrix();
// Copy Constructor
Matrix( const Matrix& c );
// Operator = Needed
Matrix& operator=( const Matrix& c );
}; // Matrix
Matrix::Matrix( unsigned int row, unsigned int column ) : DEFAULT_SIZE(2) {
// Check if both are 0 Or both are 1 - use default sizes
if ( (row == 0 && column == 0) ||
(row == 1 && column == 1) ) {
row = DEFAULT_SIZE;
column = DEFAULT_SIZE;
}
// Check [Row,Column] For [0,1] && [1,0]
if ( row == 0 && column == 1 ) {
row = 1;
column = DEFAULT_SIZE;
} else if ( row == 1 && column == 0 ) {
row = DEFAULT_SIZE;
column = 1;
}
size_row = row;
size_column = column;
element = new double[size_row * size_column];
} // Matrix
Matrix::~Matrix() {
delete [] elements
} // ~Matrix
Matrix::Matrix( const Matrix& c ) : DEFAULT(2) {
this->size_row = c.size_row;
this->size_column = c.size_column;
this->element = c.element;
} // Matrix(copy)
Matrix& Matrix::operator=( const Matrix& c ) {
// Assignment Can Only Happen If Both Matrices Are Of The Same Dimensions:
// You can not set a 4x3 = 6x9 for this does not make sense
if ( (this->size_row == c.size_row) &&
(this->size_column == c.size_column) ) {
this->element = c.element;
return *this;
} // operator=
至于您的 main 函数中的代码,我看到一些需要修复的错误。前两行:
Matrix A;
delete A;
您正在声明矩阵 A;然后在下一行你在 A 上调用 delete。
这是您的第一个错误:A 是 Matrix 的一个实例。这是一个本地堆栈变量,属于 main 函数的范围。无需为此调用删除!当您的 Matrix (A) 实例超出范围时,会在幕后为您隐式调用 Matrix::~Matrix(),无需调用它。
接下来的两行代码:
Matrix* B = new Matrix[5];
delete [] B;
这两个是正确的,这里没有问题。您的实例 B 是指向类型对象 Matrix 的指针,因为这里使用了 new ,所以它是在堆上创建的,并且因为您有 [5] B 不仅是指向此类型的指针,而且是指向第一个地址的堆上的指针你动态分配的数组。然后你用 B 上的 [] 运算符调用 delete,这是正确的。
接下来的两行代码:
Matrix C(15,15);
delete C;
您正在使用定义的构造函数的堆栈上声明一个名为 C 的 Matrix 对象的实例。再次在这里的第二行,不需要在 C 上调用 delete。
至于你的最后两行代码,这并不像你想要的那样简单,但也不是那么简单。为了让您创建默认大小为 15x15 的矩阵的动态数组,需要做更多的工作。为了正确执行此操作,您可以从类实现中看到我添加了一个复制构造函数和一个重载的 = 运算符。实现这一目标的三个步骤。
// First Step - Create A Single Stack Instance With Size [15,15]
Matrix D = Matrix( 15, 15 ); // This Will Be Used Later To Populate Your Array
// Second Step - Create An Array of 5 Matrices On The Heap
Matrix* E = new Matrix[5]; // Right Now All Five Are Using Default Size 2x2.
// Step Three Now We Update Them Using Our operator=()
for ( unsigned int i = 0; i < 5; i++ ) {
E[i] = D;
}
// Then Delete the Array
delete [] E; // Only Need To Delete E
但是这将不起作用:由于我们的 operator=() 是如何定义的!那么我们如何实现这一目标呢?有两种方法,两种方法都有效。所以你可以删除 Matrix E、for 循环和 delete [] E 行。留下矩阵 D,因为这是需要的!
第一个更简单:如果您注意到我在本例中包含了 STL 中的向量和数组,我将使用向量类,因为它是最常用的。
// We already have: Matrix D = Matrix( 15, 15 );
// You Want an Array of 5
std::vector<Matrix> vMatrices; // This will create a vector of stack Matrices but at first it will be "EMPTY"
for ( unsigned int i = 0; i < 5; i++ ) {
vMatrices.push_back( D );
}
// Now You Have A vector of 5 Matrices.
// If You Want Vector of Pointers
std::vector<Matrix*> vpMatrices;
for ( unsigned int i = 0; i < 5; i++ ) {
vpMatrices.push_back( &D );
}
// To clean up your vectors you can simply do
vMatrices.clear();
vpMatrices.clear();
// The Other Way Would Be To Use std::array but it is less commonly used.
// If You know you will only ever need a set amount this works good
std::array<Matrix, 5> aMatrices;
for ( unsigned int i = 0; i < 5; i++ ) {
aMatrices.at(i) = D;
}
// For Holding Pointers
std::array<Matrix*, 5> apMatrices;
for ( unsigned int i = 0; i < 5; i++ ) {
apMatrices.at(i) = &D;
}
// To Clean Up std::array To Be Honest Not really sure for I do not use them
// But using it here just as an illustration that there are plenty of predefined containers
// to use to hold multiple elements of the same data type.
作为关于您的课程的最后一点,您正在创建矩阵的大小并根据大小定义元素数组,但是由于所有内容都是私有的,您无法填充或访问它。保持私有意味着您必须实现函数来执行此操作并考虑矩阵的性质,以便它们“存储”数据或“函数调用”或作为计算和运算的数学对象。您不希望附加功能的开销会影响性能。将行和列的大小保持私有并没有错,因为一旦定义了它们,就无需在类之外访问它们。但是代表 MxN 矩阵的一维数组应该是公开定义的。你也应该定义 operator[] 。
如果您想了解基本数学库如何实现矩阵,请查看 GLM 的数学库,该库是为与 OpenGL 着色器语言 GLSL 一起使用而编写的。
该库是仅标题库。无需链接或包含 *.dll 或 *.libs。您需要做的就是将其存储到计算机上的文件夹中,并将系统设置为具有指向其主文件夹的环境变量。然后在您的 IDE 中,如果您使用的是 VS,那么您在项目属性的附加包含部分中所要做的就是使用定义的环境变量。这是为了使用它!但是要查看其内容,您可以将其下载到任何文件夹并打开任何 *.h 文件。然后你可以看到他们是如何实现 Matrix 类的!您会注意到它们是模板类型,并且它们具有预定义的矩阵类型,例如 mat2x2、mat2x3、mat2x4、mat3x2、mat3x3、mat3x4、mat4x2、mat4x3 和 mat4x4。这与编写专注于 2D 和 3D 图形的程序和着色器的性质有关,因此所需的最小值是 2x2,而真正需要的最大的是 4x4。它们还定义了不同大小的向量类,并且您的矩阵可以由不同大小的向量构造。但这应该作为指导。这是他们的链接
GLM