2016-05-13 9 views
2

Ich versuche, eine Reihe von Klassen zu implementieren, die eine (gemeinsame) Schnittstelle zu dreieckigen oder symmetrischen Matrizen bieten, aber ich möchte das Kopieren von Speicher vermeiden Platz-Operationen).Verschiedene Schnittstellen für eine einzelne "Daten tragende" Klasse

Die Art, wie ich dies in C++ dachte, ist die Implementierung einer Klasse oder Struktur, die einfach ein Vektor ist, der die Matrixdaten enthält (da ich nur an Dreiecksmatrizen interessiert bin, muss ich nur die Hälfte der Matrix ca .). Nennen wir diese "Daten tragende" Klasse SquareTriangularMatrix. Nun könnten die Daten innerhalb dieser Matrix unterschiedlich zugegriffen werden, abhängig davon, ob die Daten als oberes Dreieck, unteres Dreieck oder sogar als symmetrisch behandelt werden sollen.

Ich glaube nicht, dass Polymorphismus in meinem Fall angewandt werden kann, weil ich will, dass das gleiche Objekt von SquareTriangularMatrix verschiedene Schnittstellen hat je nach Kontext. Einige Male SquareTriangularMatrix könnte als eine untere Dreiecksmatrix behandelt werden, aber einige andere können sein transpose: eine obere Dreiecksmatrix, und so weiter.

Gibt es ein Entwurfsmuster, das dieses Problem anspricht? Jeder Hinweis oder Richtlinie in diesem Zusammenhang wäre sehr willkommen.

Vielen Dank

+0

Nur ein paar Gedanken: Ich würde für die Zusammensetzung über Vererbung gehen. Wenn die verschiedenen Matrixtypen tatsächlich unterschiedliche Schnittstellen haben sollen, könnte das Aufrufen einer Basisklassenschnittstelle verwirrender als hilfreich sein. Auf der anderen Seite möchten Sie möglicherweise den gleichen Algorithmus mit verschiedenen Arten von Matrizen verwenden, was einfacher wäre, wenn sie dieselbe Schnittstelle teilen. – user463035818

+0

Das klingt nach einem [Fliegengewicht] (https://sourcemaking.com/design_patterns/flyweight) für mich. – jaco0646

Antwort

0

Sie können Adapterklassen für Ihre Storage-Klasse erstellen, wie folgt aus:

struct SquareTriangularMatrix { 
    // constructor, maybe operator[], etc 
    int* values; 
    int nrows; 
    int ncolumns; 
}; 

struct UpperTriangleMatrix { 
    UpperTriangleMatrix (SquareTriangularMatrix& data): data(data) {} 
    int at (unsigned row, unsigned column) const { 
     if (row > column) return 0; 
     return data.values [row * data.ncolumns + column]; 
    } 
private: 
    SquareTriangularMatrix& data; 
}; 

Dann Sie diese Klasse UpperTriangleMatrix im SquareTriangularMatrix verschachtelt machen können und eine Funktion wie SquareTriangularMatrix::as_upper() hinzufügen, die zurückkehren dieser Adapter mit dieser Matrix konstruiert.

Ein anderer Weg Sie gehen können, ist eine Funktion as im SquareTriangularMatrix zu erstellen, die später eigenen Adapter hinzufügen können, um, wie folgen aus:

struct SquareTriangularMatrix { 
    //... 
    template <class T> T 
    as() { return T(*this); } 
}; 

//usage: 
SquareTriangularMatrix m; 
auto upper = m.as <UpperTriangleMatrix>(); 

Mit diesem Ansatz können Sie Ihre Matrix jederzeit umwandeln können Jeder Adapter, den Sie wünschen, erfüllt die as Vorlage (die ziemlich einfach und breit ist) und erweitert die Liste der Adapter in jeder Datei lokal.

Sie können auch die Art und Weise STL folgen erlaubt Zeit zu konvertieren (std::duration_cast):

template <typename T> T& matrix_cast (SquareTriangularMatrix& m) { return T(m); } 

SquareTriangularMatrix m; 
auto upper = matrix_cast <UpperTriangleMatrix>(m); 

Es ist einfach auf die gleiche Weise wie die Funktion as<> aus dem vorherigen Beispiel funktioniert, es ist nur eine Frage des Geschmacks.

Verwandte Themen