Question

J'ai une classe pour analyser une matrice qui maintient le résultat dans un tableau de membre:

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

L'utilisateur de cette classe a besoin d'appeler une fonction de l'API (comme dans une fonction je n'ai aucun contrôle dessus, donc je ne peux pas juste changer son interface pour rendre les choses plus facilement un emploi) qui ressemble à ceci:

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

Le seul moyen que j'ai trouvé pour l'appelant pour passer le tableau de résultat de la fonction est d'en faire un membre du public:

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

Est-ce la seule façon de faire les choses?Je suis étonné par la façon rigide les tableaux multidimensionnels déclaré comme ce sont.J'ai pensé matrix_ serait essentiellement le même que pour un double** et je pourrais (en toute sécurité) entre les deux.Il s'avère que je ne peux même pas trouver un dangereux façon de jeter entre les choses.Dis-je ajouter un accesseur pour la Parser classe:

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

Cela permettra de compiler, mais je ne peux pas l'utiliser, parce qu'il ne semble pas être un moyen de jeter en arrière pour le weirdo type de tableau:

  // 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

L'erreur est:

error C2440:"type " cast":impossible de convertir de 'void *' to 'const double [4][4]'

...avec une intrigante addendum:

Il n'y a pas que les conversions de types de tableau, bien qu'il existe des conversions des références ou des pointeurs de tableaux

Je ne peux pas déterminer la manière de voter, à une référence ou un pointeur de tableau, bien qu'il ne sera probablement pas m'aider ici.

Pour être sûr, à ce stade, la question est purement théorique, comme le void* les castes sont à peine plus propre que un seul membre de la classe à gauche publique!

Était-ce utile?

La solution

Voici une façon agréable et propre:

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

   // ...

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

   // ...

private:
  matrix matrix_;
};

Maintenant que vous travaillez avec un descriptif type nom plutôt qu'un tableau, mais comme c'est une typedef le compilateur auront toujours la possibilité de passer à l'immuable la fonction de l'API qui prend le type de base.

Autres conseils

Essayez ceci.Il compile correctement sur 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;
}

J'ai utilisé une union de ce genre pour passer autour de matrices dans le passé:

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

Puis de passer un pointeur à votre setter et copier les données dans la matrice de votre classe.

Il existe des moyens de la manipulation de ce autrement (qui sont plus génériques), mais cette solution tend à être le plus propre à la fin, dans mon expérience.

J'ai pensé matrix_ serait essentiellement le même que d'un lit double**

En C il y a des multi-dimensions des tableaux, pas des tableaux de pointeurs de tableaux, donc un double[4][4] est une ligne de tableau à quatre double[4] tableaux, équivalent à un double[16], pas un (double*)[4].

Il n'y a pas que les conversions de types de tableau, bien qu'il existe des conversions des références ou des pointeurs de tableaux La conversion d'une valeur à une double[4][4] serait une tentative pour construire un sur la pile - équivalent à std::string(analyseur.getMatrix()) - sauf que le tableau ne fournit pas un constructeur approprié.Vous n'avez probablement pas envie de le faire, même si vous le pouviez.

Depuis le type de code la foulée, vous avez besoin d'un type complet (double[][] ne pas le faire).Vous pouvez réinterpréter cast le void* à ((double[4][4])*), et puis prendre la référence.Mais il est plus facile de typedef la matrice et de renvoyer une référence du type correct en premier lieu:

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

Pour des précisions sur la réponse choisie, d'observer cette ligne

const matrix& getMatrix() const

C'est super, vous n'avez pas à vous soucier de pointeurs et de la coulée.Vous êtes de retour d'une référence de la matrice sous-jacente de l'objet.À mon humble avis, les références sont l'une des meilleures fonctionnalités de C++, ce qui me manque lorsque le codage en droit C.

Si vous ne connaissez pas la différence entre les références et les pointeurs en C++, lire ce

En tout cas, vous ne devez être conscient que si l' Parser l'objet qui est le propriétaire de la matrice sous-jacente de l'objet est hors de portée, tout code qui tente d'accéder à la matrice par l'intermédiaire de cette référence sera désormais la référence à un hors-de-portée de l'objet, et vous serez d'accident.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top