Frage

Ich habe eine Klasse zum Parsen einer Matrix, die das Ergebnis in einem Array-Mitglied speichert:

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

Der Benutzer dieser Klasse muss eine API-Funktion aufrufen (z. B. eine Funktion, über die ich keine Kontrolle habe, sodass ich nicht einfach ihre Schnittstelle ändern kann, damit die Dinge einfacher funktionieren), die wie folgt aussieht:

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

Die einzige Möglichkeit, die ich für den Aufrufer gefunden habe, um das Array-Ergebnis an die Funktion zu übergeben, besteht darin, das Mitglied öffentlich zu machen:

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

Ist das der einzige Weg, Dinge zu tun?Ich bin erstaunt darüber, wie unflexibel mehrdimensionale Arrays sind, die auf diese Weise deklariert werden.ich dachte matrix_ wäre im Wesentlichen dasselbe wie a double** und ich konnte (sicher) zwischen den beiden werfen.Wie sich herausstellt, kann ich nicht einmal eine finden unsicher Weg, zwischen den Dingen zu werfen.Angenommen, ich füge einen Accessor hinzu Parser Klasse:

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

Dies wird kompiliert, aber ich kann es nicht verwenden, da es anscheinend keine Möglichkeit gibt, auf den Array-Typ „Weirdo“ zurückzugreifen:

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

Der Fehler ist:

Fehler C2440:'type cast':Konvertierung von „void *“ in „const double [4][4]“ nicht möglich.

...mit einem interessanten Nachtrag:

Es gibt keine Konvertierungen in Array-Typen, wohl aber Konvertierungen in Referenzen oder Zeiger auf Arrays

Ich kann auch nicht bestimmen, wie ich in eine Referenz oder einen Zeiger auf ein Array umwandeln soll, auch wenn mir das hier wahrscheinlich nicht helfen wird.

Allerdings ist die Angelegenheit an dieser Stelle rein akademischer Natur, da die void* Abgüsse sind kaum sauberer als ein einzelnes Klassenmitglied, das öffentlich hinterlassen wird!

War es hilfreich?

Lösung

Hier ist eine schöne, saubere Art und Weise:

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

   // ...

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

   // ...

private:
  matrix matrix_;
};

Jetzt arbeiten Sie mit einem beschreibenden Typnamen eher als ein Array, aber da es ein typedef der Compiler noch wird es auf die unveränderliche API-Funktion ermöglichen die Weitergabe, die den Basistyp nimmt.

Andere Tipps

Versuchen Sie dies. Es kompiliert sauber auf 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;
}

ich eine Vereinigung wie diese verwendet habe Matrizen in der Vergangenheit passiert um:

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

Dann einen Zeiger übergeben, um Ihre Setter und die Daten in die Matrix in der Klasse kopiert werden.

Es gibt Wege im Umgang mit dieser sonst (die allgemeinere sind), aber diese Lösung neigt die sauberste am Ende zu sein, in meiner Erfahrung.

  

Ich dachte matrix_ im Wesentlichen die gleiche wie eine Doppel **

sein würde,

C gibt es wahre Mehrdimensionale Arrays, nicht Arrays von Zeigern auf Arrays, so dass ein Doppel [4] [4] ist eine zusammenhängende Anordnung von vier Doppel [4] Arrays äquivalent zu einem double [16], nicht a (double *) [4].

  

Es gibt keine Conversions Array-Typen, obwohl es Conversions Verweise oder Zeiger auf Arrays   Gießen einen Wert zu einem Doppel [4] [4] versuchen würde, ein auf dem Stapel zu konstruieren - das entspricht std :: string (parser.getMatrix ()) - mit Ausnahme, dass das Array keine geeignete Konstruktor nicht liefert. Sie did't wahrscheinlich das tun wollen, selbst wenn man könnte.

Da der Typ die Schritt kodiert, benötigen Sie einen vollständigen Typ (double [] [] wird nicht). Sie können die void * zu ((double [4] [4]) *) neu interpretieren gegossen und dann die Referenz nehmen. Aber es ist am einfachsten, die Matrix typedef und eine Referenz des richtigen Typs in erster Linie zurück:

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

Um auf die gewählte Antwort zu erarbeiten, beachten Sie diese Zeile

const matrix& getMatrix() const

Das ist großartig, Sie müssen nicht über Zeiger und Gießen kümmern. Sie Rückkehr eine Hinweis auf die zugrunde liegende Matrix-Objekt. IMHO Referenzen sind eine der besten Eigenschaften von C ++, die ich vermissen, wenn in geraden C-Codierung.

Wenn Sie nicht vertraut mit dem Unterschied zwischen Referenzen und Zeigern in C ++ sind, lesen this

Auf jeden Fall müssen Sie sich bewusst sein, dass, wenn das Objekt, das Parser besitzt tatsächlich die Aufgabe zugrunde, Matrix den Gültigkeitsbereich verlässt, die jeder Code versucht, die Matrix über diese Referenz für den Zugriff wird nun eine out-of- werden Referenzierung Bereichsobjekt, und Sie werden zum Absturz bringen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top