C++ 试图理解C+中矩阵乘法的存取算子+;
我试图理解矩阵乘法的存取运算符C++ 试图理解C+中矩阵乘法的存取算子+;,c++,C++,我试图理解矩阵乘法的存取运算符 模板 类Matrix44 { 公众: Matrix44(){} //接下来的两行对我来说完全混淆了 常量T*运算符[](uint8_T i)常量{return m[i];} T*运算符[](uint8_T i){返回m[i];} //用单位矩阵的系数初始化矩阵的系数 T m[4][4]={{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1};//你为什么能这样做m[4][4] }; 类型定义矩阵X44矩阵X44F; 因此,我的理解是
模板
类Matrix44
{
公众:
Matrix44(){}
//接下来的两行对我来说完全混淆了
常量T*运算符[](uint8_T i)常量{return m[i];}
T*运算符[](uint8_T i){返回m[i];}
//用单位矩阵的系数初始化矩阵的系数
T m[4][4]={{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1};//你为什么能这样做m[4][4]
};
类型定义矩阵X44矩阵X44F;
因此,我的理解是,他们定义了自己的访问操作符,用于访问矩阵索引:
Matrx44f材料;
mat[0][3]=1.f;
但这与他们的定义有什么关系呢
。。。
常量T*运算符[](uint8_T i)常量{return m[i];}
T*运算符[](uint8_T i){返回m[i];}
非常感谢您帮助C++ NoOb
,因为有不少人已经指出它是一个相当强的>差的矩阵实现< /强>:它让我们假设内部实现,并有一些缺陷。但如果我说我在研究代码中还没有见过这样的实现,那我就撒谎了除了抨击实现,我想简单地指出它是如何工作的,尽管它显示了C++的一些特殊性。 概述
// Class for a generic data type T (e.g. T = float)
template<typename T>
class Matrix44 {
public:
// Constructor
Matrix44() {
return;
}
// Access operator for constant objects
const T* operator [] (uint8_t i) const {
return m[i];
}
// Access operator for non-constant objects
T* operator [] (uint8_t i) {
return m[i];
}
// Declaration of a stack-allocated array as class member
T m[4][4]
// Initialisation of this class member
= {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
};
// Alias Matrix44f for a matrix of floats (T = float)
typedef Matrix44<float> Matrix44f;
当
将是a的声明,可使用
int m[2][3] = {{1,2},{3,4},{5,6}};
(类似于用an初始化向量向量的方式),然后可以用类似的语法m[i][j]
访问其元素(也类似于向量向量std::vector
,注意:没有越界检查!)
如您所见,您的类仅是泛型类型T
的此类堆栈分配二维数组的包装器
T m[4][4];
所谓的模板类
。将类实例化为Matrix44
将使其成为T=float
的矩阵,而对于矩阵Matrix44
而言,基础数据类型将是int
。使用底部的typedef matrix4 matrix4f
创建此数据类型的新别名。因此可以声明一个变量Matrix44f mat
Stack allocated(堆栈分配)意味着它的大小与堆分配的数组相比非常有限,而堆分配的数组对于4x4
数组不是非常禁止(但为什么不将此实现至少扩展到NxN
?)。此外,它的编写方式甚至没有正确的构造函数(Matrix44(){}
),而是默认使用标识矩阵初始化
{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}
(为什么会有人这么做?)
操作员[]
C++提供了重载运算符的可能性。因此,我们可以定义(重载)基本操作,如加法运算符+
、乘法运算符*
、比较等。同样,我们也可以重载[]
(但仅使用一个参数,因此像特征值这样的数字库选择重载()
运算符),()
和,
。但是没有什么过载!为了允许类外使用类似于堆栈分配数组的[]
访问矩阵,选择编写运算符[]
返回指向底层二维数组第二维第一个元素的指针,该元素位于第一维m[i][0]
的相应索引i
:返回m[i]
相当于返回&m[i][0]
。然后可以应用指针的操作符[]
p[j]
,它相当于*(p+j)
(有关更多详细信息,请参阅)通过j项移动此指针,以访问元素m[i][j]
。(这类似于使用向量向量而不是堆栈分配的数组,从操作符[]
返回std::vector&
,然后使用向量的[]
操作符访问精确的元素。)
成员函数可以声明为常量(请参见参数列表后的const
),这意味着也可以为常量对象调用它们,而如果未声明为常量,则只能为非常量对象调用它们。对于常量对象,调用常量版本,而对于非常量对象,调用非常量实现()。为了允许分配非恒定版本
T* operator [] (uint8_t i) {
return m[i];
}
返回一个非常量指针T*
,当常量实现返回一个指向常量变量const T*
的指针时,可以修改该指针
const T* operator [] (uint8_t i) const {
return m[i];
}
这就是为什么有两个这样的实现。对于常量对象,将调用不允许赋值的后一个对象(但您可以使用m[1][2]
读取元素1,2
),而对于非常量对象,将调用允许赋值的第一个对象(例如m[1][2]=1
将元素1,2
设置为1
).正如许多人已经指出的那样,它是一个非常差的矩阵实现:让我们对内部实现进行假设,并且有相当多的缺陷。但如果我说我在研究代码中还没有见过这样的实现,那我就撒谎了除了抨击实现,我想简单地指出它是如何工作的,尽管它显示了C++的一些特殊性。
概述
// Class for a generic data type T (e.g. T = float)
template<typename T>
class Matrix44 {
public:
// Constructor
Matrix44() {
return;
}
// Access operator for constant objects
const T* operator [] (uint8_t i) const {
return m[i];
}
// Access operator for non-constant objects
T* operator [] (uint8_t i) {
return m[i];
}
// Declaration of a stack-allocated array as class member
T m[4][4]
// Initialisation of this class member
= {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
};
// Alias Matrix44f for a matrix of floats (T = float)
typedef Matrix44<float> Matrix44f;
当
将是a的声明,可使用
int m[2][3] = {{1,2},{3,4},{5,6}};
(类似于使用an初始化向量向量的方式),然后可以使用类似的语法m[i]访问其元素
using reference = T(&)[4]; // reference to a 4-element subarray
reference const operator[](int i) const { return m[i]; }
reference operator[](int i) { return m[i]; }
template<class T> using Matrix44 = std::array<std::array<T, 4>, 4>;
template<typename T>
class Matrix44
{
public:
Matrix44() {}
// The next two lines are totally confusing for me
decltype(auto) operator [] (uint8_t i) const { return m[i]; }
decltype(auto) operator [] (uint8_t i) { return m[i]; }
// initialize the coefficients of the matrix with the coefficients of the identity matrix
std::array<std::array<T, 4>, 4> m = {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}};
};
typedef Matrix44<float> Matrix44f;