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

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:'类型转换':无法从“void *”转换为“const double [4][4]”

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

尽管存在对数组的引用或指针的转换,但没有对数组类型的转换

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

可以肯定的是,目前这个问题纯粹是学术性的,因为 void* 演员阵容并不比公开的单个班级成员干净!

有帮助吗?

解决方案

这是一个很好、干净的方法:

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

   // ...

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

   // ...

private:
  matrix matrix_;
};

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

其他提示

尝试这个。它在 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;
}

我过去曾使用这样的联合来传递矩阵:

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

然后将指针传递给您的设置器并将数据复制到您的类中的矩阵中。

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

我认为matrix_本质上与double**相同

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

没有转换到数组类型,尽管参考文献或指针的转换为double [4] [4]将尝试在堆栈上构造一个数组 - 等效于STD :: string(Parser.getMatrix)( )) - 除了阵列不提供合适的构造函数。即使你可以,你可能也不想这样做。

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

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();
}

要详细说明所选答案,请观察这一行

const matrix& getMatrix() const

这太棒了,您不必担心指针和转换。您正在返回一个 参考 到底层矩阵对象。恕我直言,引用是 C++ 的最佳功能之一,在直接使用 C 进行编码时我很怀念这一点。

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

无论如何,您必须意识到,如果 Parser 实际拥有底层矩阵对象的对象超出了范围,任何尝试通过该引用访问矩阵的代码现在都将引用超出范围的对象,并且您将崩溃。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top