4

我在我的一个项目中使用 2D 矩阵。这类似于C++ FAQ Lite中的建议。

巧妙的是,您可以像这样使用它:

int main()
{
  Matrix m(10,10);
  m(5,8) = 106.15;
  std::cout << m(5,8);
  ...
}

现在,我有一个由顶点组成的图,每个顶点都有一个指向 2D 矩阵的公共指针(只是为了示例的简单),如上所示。现在我确实有一个非常难看的语法来访问它。

(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...

由于我对运算符重载缺乏经验,我可能在这里遗漏了一些语法糖。有更好的解决方案吗?

4

9 回答 9

4
  1. 考虑使用引用而不是指针(前提是它不能为空,并且可以在构造函数中初始化)。
  2. 考虑为返回二维矩阵引用的顶点创建一个 getter 或矩阵包装类的实例(前提是它不能为空)。

    sampleVertex.some2DTable()(0,0) = 0;
    sampleVertex.some2DTableWrap(0,0) = 0;
    

但是,对我来说,证明经历所有麻烦似乎不是问题。

于 2009-03-25T14:17:32.823 回答
4

如果您有一个指向 Matrix 的指针,例如作为无法引用的函数参数(例如遗留代码),您仍然可以引用它(伪代码):

struct Matrix {
        void operator () (int u, int v) {
        }
};
int main () {
        Matrix *m;
        Matrix &r = *m;
        r (1,1);
}
于 2009-03-25T14:27:31.240 回答
2

你基本上被限制在(*sampleVertex.some2DTable)(0,0). 当然,如果您不需要重新安装,为什么不将实际值存储在矩阵中呢?

或者,将指针设为私有并创建一个访问器(注意:以下示例假设一个 EntryTypes 矩阵):

Matrix& Vertex::GetTableRef() 
{
    return *some2DTable; 
}
// or
Matrix::EntryType& Vertex::GetTableEntry(int row, int col)
{
    return (*some2DTable)(row,col);
}

// way later...
myVertex.GetTableRef()(0,0) = 0;
// or...
myVertex.GetTableEntry(0,0) = 0;

或者,如果您无法更改 Vertex 类,只需定义一个内联函数来为您执行此操作:

// in some header file
inline Matrix& GetTableRef(Vertex& v)
{
    return *v.some2DTable;
}

// or you could do this
inline Matrix::EntryType& GetTableEntry(Vertex& v, int row, int col)
{
    return (*v.some2DTable)(row, col);
}


// later...
GetTableRef(myVertex)(0, 0) = 0;
// or
GetTableEntry(myVertex, 0, 0) = 0;

最后,不要忘记您不必使用运算符重载。STL 集合实现了一个 at() 成员函数,它被选中,而不是未选中的 operator[]。如果您不介意边界检查的开销,或者您只是想成为非标准的,您可以实现 at() 然后调用myVertex.some2DTable->at(0,0),完全省去一些语法上的麻烦。

于 2009-03-25T14:17:42.387 回答
1

没有 C++ 语法糖可以减轻您所描述的痛苦:

(*sampleVertex.some2DTable)(0,0) = 0; //bad
sampleVertex.some2DTable->operator()(0,0) = 0; //even worse...

在这种情况下,我要么让图形返回引用而不是指针,要么让矩阵定义一个调用 operator() 的函数:

inline matrixType &Matrix::get( int x, int y ){ return operator()(x,y); }

然后,对于顶点示例,语法并不那么难看:

sampleVertex.some2DTable->get(0,0) = 0;
于 2009-03-25T14:32:05.533 回答
1

我会添加一个函数,它会像 rlbond 推荐的那样返回一个 ref。为了快速修复,或者如果您无法控制它的来源,我会这样做:

sampleVertex.some2DTable[0](0,0) = 0; // more readable

这实际上是等价的,因为如果a是指向已定义类的指针,则以下内容成立:

*a == *(a + 0) == a[0]

请参阅关于 comp.lang.c++ 的关于同一个问题的长时间讨论,并给出很好的答案

于 2009-03-25T15:35:02.573 回答
0

这是不更改代码的最佳方法:

//some2DTable is a pointer to a matrix
(*sampleVertex.some2DTable)(0,0)

您也可以改为使 some2DTable 成为对矩阵的引用,而不是指向矩阵的指针。然后你会像在你的第一个代码片段中一样简化语法。

//some2DTable is a reference to a matrix instead of a pointer to a matrix
sampleVertex.some2DTable(0,0)

或者您可以保留 some2DTable 指向引用的指针,并简单地将引用变量存储到它并在代码块的上下文中使用它。

于 2009-03-25T14:11:00.967 回答
0

我不知道这是否值得麻烦,但你可以这样做:

class MatrixAccessor {
private:
  Matrix2D* m_Matrix;
public:
  MatrixAccessor(Matrix2D* matrix) : m_matrix(matrix) { }
  double& operator()(int i, int j) const { return (*m_Matrix)(i,j); }
  Matrix2D* operator->() const { return m_Matrix; }
  void operator=(Matrix2D* matrix) { m_Matrix = matrix; }
};

假设原始operator()返回一个引用(就像在许多矩阵类中一样)。

然后在顶点类中提供 MatrixAccessor:

class Vertex {
  Matrix2D* myMatrix;

public:
  MatrixAccessor matrix;
  Vertex(Matrix2D *theMatrix) : myMatrix(theMatrix), matrix(theMatrix) { }
};

然后你可以写:

Vertex v;
v.matrix(1,0) = 13;
v.matrix->SomeOtherMatrixOperation();

编辑

我添加了const关键字(感谢@phresnel提出了该主题),以便使解决方案在语义上等同于仅提供公共指针的解决方案Matrix2D

该解决方案的一个优点是,可以通过添加两个非const版本的operator()()operator->()(即不能在const顶点上修改矩阵)并将它们分别更改const为返回一个const double&和来将常量转移到矩阵对象const Matrix2D*

当使用指向矩阵对象的公共指针时,这是不可能的。

于 2009-03-25T16:09:24.113 回答
0

我会改变你获取“sampleVertex.some2DTable”的方式,所以它会返回一个引用。

要么自己创建参考:

Matrix& m = *sampleVertex.some2DTable;
m(1,2) = 3;
于 2009-03-25T16:42:08.827 回答
0

您可以通过调用成员函数来实现 Matrix::operator (int,int) 并在处理指针时直接使用该成员函数。

class Matrix
{
public:
  float ElementAt( int i, int j ) const { /*implement me*/ }
  float operator() ( int i, int j ) const { return ElementAt( i, j ); }
  ...
};

void Foo(const Matix* const p)
{
  float value = p->ElementAt( i, j );
  ...
}

void Bar(const Matrix& m)
{
  float value = m(i,j);
}
于 2009-03-26T12:38:59.760 回答