Domanda

Ho una classe per analizzare una matrice che tiene il risultato in un array membro:

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

L'utente di questa classe deve chiamare una funzione API (come in, una funzione che non ho alcun controllo su, quindi non posso cambiare la sua interfaccia per rendere le cose più facili) che assomiglia a questo:

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

L'unico modo che ho di venire con il chiamante passa la matrice risultato per la funzione è fare in modo che il membro del pubblico:

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

È questo l'unico modo per fare le cose?Io sono sbalordito da quanto inflessibile array multidimensionali dichiarato come questo sono.Ho pensato matrix_ sarebbe essenzialmente lo stesso come un double** e ho potuto cast (in modo sicuro) tra i due.Come si scopre, non riesco nemmeno a trovare un pericoloso modo di gettare tra le cose.Posso dire di aggiungere una funzione di accesso per il Parser classe:

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

Questo compilerà, ma non posso usarlo, perché non sembra essere un modo per gettare indietro la tipa del tipo di matrice:

  // 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'errore è:

l'errore c2440 errore:'cast del tipo' :impossibile convertire da 'void *' a 'const double [4][4]'

...con un intrigante addendum:

Non ci sono conversioni di tipi di matrice, anche se ci sono conversioni di riferimenti o puntatori ad array

Io non riesco a determinare come il cast di riferimento o puntatore alla matrice, anche se probabilmente non aiuterà con me qui.

Per essere sicuri, a questo punto la questione è puramente accademico, come il void* i calchi sono quasi più pulito di un singolo membro di una classe, di sinistra pubblico!

È stato utile?

Soluzione

Ecco un modo bello, pulito:

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

   // ...

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

   // ...

private:
  matrix matrix_;
};

Ora si sta lavorando con una di tipo descrittivo nome piuttosto che un array, ma poiché si tratta di un typedef il compilatore ancora consentire il passaggio al immutabile API funzione che prende il tipo di base.

Altri suggerimenti

Prova in questo modo.Compila correttamente su 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;
}

Ho usato una unione come questo per passare in giro matrici in passato:

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

Poi passare un puntatore al tuo setter e copiare i dati nella matrice in classe.

Ci sono modi per gestire questo altrimenti (più generico), ma questa soluzione tende ad essere il più pulito alla fine, nella mia esperienza.

Ho pensato matrix_ sarebbe essenzialmente la stessa come un doppio**

In C non ci sono vere array multi-dimensionali, non un array di puntatori ad array, quindi, un doppio[4][4] è una matrice contigua di quattro doppi[4] array, equivalente al doppio[16], non un (double*)[4].

Non ci sono conversioni di tipi di matrice, anche se ci sono conversioni di riferimenti o puntatori ad array Il cast di un valore di un doppio[4][4] tentativo di costruzione di una pila - equivalente di std::string(parser.getMatrix ()) a parte che l'array non fornisce un adeguato costruttore.Probabilmente non voglio farlo, anche se è impossibile.

Dal momento che il tipo di codifica per la falcata, avete bisogno di un tipo completo (double[][] non fare).È possibile reinterpretare il cast di the void* a ((double[4][4])*), e poi prendere il riferimento.Ma è più facile typedef la matrice e restituisce un riferimento del tipo corretto, in primo luogo:

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

Per elaborare la risposta selezionata, osservare questa linea

const matrix& getMatrix() const

Questo è grande, non è necessario preoccuparsi di puntatori e casting.Sei la restituzione di un riferimento la matrice sottostante oggetto.IMHO i riferimenti sono una delle migliori caratteristiche del C++, che mi manca quando si codifica in rettilineo C.

Se non hai familiarità con la differenza tra riferimenti e puntatori in C++, leggere questo

In ogni caso, è necessario essere consapevoli del fatto che se il Parser oggetto che effettivamente possiede la matrice sottostante oggetto ambito, qualsiasi codice che tenta di accedere alla matrice per il tramite di tale riferimento sarà ora il riferimento a un out-of-scope oggetto, e sarete in crash.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top