Versuch es einfacher zu machen ...
Das notwendige technische Verständnis für Traits ist nicht zu unterschätzen. Es ist deshalb naheliegend zu überlegen, ob diese für unsere Zwecke immer notwenig sind. Hätten wir nur eine Matrix-Klasse, dann wäre das zumindest im vorigen Beispiel nicht der Fall. Eine einzige Funktion print wäre für Matrizen ausreichend:
template <typename Index, typename T> void print(const GeMatrix<T, Index> &A, const char *name = "") { if (*name) { printf("%s = \n", name); } for (Index i=0; i<A.numRows; ++i) { for (Index j=0; j<A.numCols; ++j) { print_value(A(i,j)); } printf("\n"); } printf("\n"); }
Diese Klasse müsse dann aber die Funktionalität von den vorigen Klassen GeMatrix, GeMatrixView und GeMatrixConstView vereinigen. Wir versuchen dies schrittweise zu erreichen.
Einfache Matrix-Klasse
Wir beginnen mit einer Matrix-Klasse, die im Konstruktor stets Speicher allokiert und im Destruktor stets wieder freigeben soll. Das Konzept von Views wird also noch nicht berücksichtigt. Der Einfachheit halber verzichten wir außerdem auf Template Parameter für den Daten- oder Indextyp. Als Funktionalität wünschen wir:
-
Anlegen einer \(m \times n\) Matrix. Die Speicherverwaltung soll von der Matrix-Klasse übernommen werden.
-
Eine Matrix kann mit der Kopie einer anderen Matrix initialisiert werden.
-
Eine Matrix kann mit dem Zuweisungs-Operator kopiert werden.
-
Der Funktions-Operator kann für den Zugriff auf Elemente verwendet werden.
Aufgaben
-
Verwendet unten stehende Vorlage, um diese Funktionalität zu implementieren.
-
Fügt in alle Konstruktoren, Methoden, Operatoren und dem Destruktor kurze Test-Ausgaben ein, so dass deren Aufruf auch ohne Debugger nachvollziehbar ist.
-
Welche Variante des Funktionsoperator wird in print verwendet?
-
Ändert die Vorlage bzw. eure Implementierung so ab, dass constness berücksichtigt wird.
#include <cassert> #include <cstdio> struct Matrix { Matrix(long numRows, long numCols); Matrix(const Matrix &X); ~Matrix(); void operator=(const Matrix &X); const double & operator()(long i, long j) const; double & operator()(long i, long j); long numRows, numCols; double *data; }; void init(Matrix &A, long offset=1) { for (long i=0; i<A.numRows; ++i) { for (long j=0; j<A.numCols; ++j) { A(i,j) = i+j*A.numRows+offset; } } } void print(Matrix &A, const char *name = 0) { if (name) { printf("%s =\n", name); } for (long i=0; i<A.numRows; ++i) { for (long j=0; j<A.numCols; ++j) { printf(" %5.1lf", A(i,j)); } printf("\n"); } printf("\n"); } int main() { Matrix A(4, 3); Matrix B(4, 3); init(A); init(B, 20); print(A, "A"); print(B, "B"); B = A; print(B, "B"); Matrix C = A; print(C, "C"); }