如何处理C ++中的数组(在堆栈上声明)?

时间:2008-09-10 19:27:04

标签: c++ arrays

我有一个类来解析一个矩阵,该矩阵将结果保存在数组成员中:

class Parser
{
  ...
  double matrix_[4][4];
};

这个类的用户需要调用一个API函数(例如,我无法控制的函数,所以我不能只改变它的界面以使事情更容易工作),如下所示:

void api_func(const double matrix[4][4]);

我想让调用者将数组结果传递给函数的唯一方法是将成员公开:

void myfunc()
{
  Parser parser;
  ...
  api_func(parser.matrix_);
}

这是唯一的办法吗?我对这样声明的多维数组的不灵活性感到震惊。我认为matrix_基本上与double**相同,我可以(安全地)在两者之间施放。事实证明,我甚至找不到一种不安全的方式来在事物之间施放。假设我添加了Parser类的访问者:

void* Parser::getMatrix()
{
  return (void*)matrix_;
}

这将编译,但我无法使用它,因为似乎没有办法强制转换回古怪的数组类型:

  // A smorgasbord of syntax errors...
  api_func((double[][])parser.getMatrix());
  api_func((double[4][4])parser.getMatrix());
  api_func((double**)parser.getMatrix()); // cast works but it's to the wrong type

错误是:

  

错误C2440:'type cast':无法从'void *'转换为'const double [4] [4]'

......有一个有趣的附录:

  

虽然存在对引用或指向数组的指针的转换

,但是没有对数组类型的转换

我无法确定如何转换为引用或指向数组的指针,尽管它可能对我没有帮助。

可以肯定的是,在这一点上,这个问题纯粹是学术性的,因为void*演员阵容并不比一个班级成员公开场合更清晰!

5 个答案:

答案 0 :(得分:16)

这是一个很好的,干净的方式:

class Parser
{
public:
   typedef double matrix[4][4];

   // ...

   const matrix& getMatrix() const
   {
      return matrix_;
   }

   // ...

private:
  matrix matrix_;
};

现在您正在使用描述性类型名称而不是数组,但由于它是typedef,编译器仍然允许将其传递给采用基类型的不可更改的API函数。

答案 1 :(得分:6)

试试这个。它在gcc 4.1.3上完全编译:

typedef double FourSquare[4][4];

class Parser
{
  private:
    double matrix_[4][4];

  public:
    Parser()
    {
        for(int i=0; i<4; i++)
          for(int j=0; j<4; j++)
            matrix_[i][j] = i*j;
    }

  public:
    const FourSquare& GetMatrix()
    {
        return matrix_;
    }
};

void api_func( const double matrix[4][4] )
{
}

int main( int argc, char** argv )
{
    Parser parser;
    api_func( parser.GetMatrix() );
    return 0;
}

答案 2 :(得分:4)

我曾经使用这样的联盟来传递矩阵:

union matrix {
    double dflat[16];
    double dmatr[4][4];
};

然后将指针传递给你的setter并将数据复制到你班级的矩阵中。

有一些方法可以处理这种情况(更通用),但根据我的经验,这种解决方案往往是最干净的。

答案 3 :(得分:4)

  

我认为matrix_基本上与双**

相同

在C中有真正的多维数组,而不是指向数组的指针数组,所以double [4] [4]是四个double [4]数组的连续数组,相当于double [16],而不是a(double *)[4]。

  

虽然存在对引用或指向数组的指针的转换,但是没有对数组类型的转换   将值转换为double [4] [4]将尝试在堆栈上构造一个 - 相当于std :: string(parser.getMatrix()) - 除了数组不提供合适的构造函数。你可能不想这样做,即使你可以。

由于类型对步幅进行编码,因此需要完整类型(double [] []不会这样做)。您可以重新解释将void *转换为((d​​ouble [4] [4])*),然后获取引用。但是最简单的方法是输入矩阵并首先返回正确类型的引用:

typedef double matrix_t[4][4];

class Parser
{
    double matrix_[4][4];
public:
    void* get_matrix () { return static_cast<void*>(matrix_); }

    const matrix_t& get_matrix_ref () const { return matrix_; }
};

int main ()
{
    Parser p;

    matrix_t& data1 = *reinterpret_cast<matrix_t*>(p.get_matrix());

    const matrix_t& data2 = p.get_matrix_ref();
}

答案 4 :(得分:2)

要详细说明所选答案,请遵守以下一行

const matrix& getMatrix() const

这很棒,你不必担心指针和投射。您将引用返回到基础矩阵对象。恕我直言参考是C ++的最佳功能之一,我在直接C编码时错过了。

如果您不熟悉C ++中引用和指针之间的区别,read this

无论如何,你必须要知道,如果实际拥有基础矩阵对象的Parser对象超出范围,那么任何试图通过该引用访问矩阵的代码现在将引用一个超出范围的对象,你会崩溃。