代码之家  ›  专栏  ›  技术社区  ›  Nazgob

2d matrix and overloading operator()/丑陋语法

  •  4
  • Nazgob  · 技术社区  · 16 年前

    我正在我的一个项目中使用二维矩阵。有点像是建议在 C++ FAQ Lite .

    最有趣的是你可以这样使用它:

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

    现在,我有一个由顶点组成的图,每个顶点都有一个公共的(只是为了简单起见)指向上面所述的二维矩阵的指针。现在我有了一个非常难看的语法来访问它。

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

    可能是因为我对运算符重载缺乏经验,所以这里缺少了一些句法方面的内容。有更好的解决方案吗?

    9 回复  |  直到 16 年前
        1
  •  4
  •   Alex B    16 年前
    1. 考虑使用引用而不是指针(前提是它不能为空,并且可以在构造函数中初始化)。
    2. 考虑为返回对二维矩阵引用的顶点生成getter或矩阵包装类的实例(前提是不能为空)。

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

    然而,对我来说,这似乎是一个没有问题的理由去经历所有的麻烦。

        2
  •  4
  •   Sebastian Mach    16 年前

    如果你有一个指向矩阵的指针,例如作为一个你不能引用的函数参数(传统代码,例如),你仍然可以引用它(伪代码):

    struct Matrix {
            void operator () (int u, int v) {
            }
    };
    int main () {
            Matrix *m;
            Matrix &r = *m;
            r (1,1);
    }
    
        3
  •  2
  •   rlbond    16 年前

    你基本上只限于 (*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;
    

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

    // 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()成员函数,该函数被选中,而不是未选中的运算符[]。如果您不介意边界检查的开销,或者您只是想成为非标准的,那么可以实现at(),然后调用 myVertex.some2DTable->at(0,0) 省去了一点句法上的麻烦。

        4
  •  1
  •   Paul    16 年前

    没有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;
    
        5
  •  1
  •   Johannes Schaub - litb    16 年前

    我将添加一个函数,它返回一个像rlbond建议的引用。为了快速解决问题,或者如果您无法控制其来源,我将使用以下方法:

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

    这实际上是等价的,因为下面的假设 a 是指向已定义类的指针:

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

    this 关于comp.lang.c++关于同一个问题的长时间讨论,有很好的答案。

        6
  •  0
  •   Brian R. Bondy    16 年前

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

    //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保留一个指向引用的指针,并简单地存储一个引用变量,然后在代码块的上下文中使用它。

        7
  •  0
  •   Jimmy J    16 年前

    我将更改获取“samplevertex.some2dtable”的方式,以便它返回引用。

    或者自己创建引用:

    Matrix& m = *sampleVertex.some2DTable;
    m(1,2) = 3;
    
        8
  •  0
  •   MartinStettner    16 年前

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

    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 关键词(感谢 @菲利内尔 为了使解决方案在语义上等同于只呈现公共的解决方案 Matrix2D 指针。

    这个解的一个优点是,通过添加两个非- 康斯特 版本的 operator()() operator->() (即矩阵不能在 康斯特 以及更改 康斯特 返回一个 const double& const Matrix2D* 分别。

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

        9
  •  0
  •   SmoCoder    16 年前

    可以通过调用成员函数来实现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);
    }