-
more matrix problems
same template class as in the other thread, but i'll post the current prototypes first for orientation:
Code:
template<typename T, int n> // n is the Matrix height/width
class Matrix
{
private:
T** content; // 2-dimensional array of T objects
public:
// default constructor should use default T object if there is one
Matrix();
// creates uniform Matrix (all values = t)
Matrix(const T& t);
// construct a Matrix from an array
Matrix(const T arr[][n]);
// copy constructor
Matrix(const Matrix& m);
// destructor
~Matrix();
// assignment
Matrix<T, n>& operator=(const Matrix<T, n>& m);
// 'at' function (indexing)
T at(const int i, const int j);
// basic matrix operations
// addition
Matrix<T, n> operator+(const Matrix<T, n>& m) const;
// scalar multiplication
friend Matrix<T, n> operator*(T t, const Matrix<T, n>& m);
//Matrix<T, n> scalar_mult(const T& t) const;
// other methods
void show();
};
The 'at' function is my current problem. I'd obviously like to have a prototype of the form
T& at(const int i, const int j);
but I can't get it to work that way. Here's the definition:
Code:
template<typename T, int n>
T Matrix<T, n>::at(const int i, const int j)
{
if (1 <= i && i <= n && 1 <= j && j <= n)
return content[i - 1][j - 1];
else
{
std::cout << "Invalid index!\n";
return NULL;
}
}
Aside from whether or not the else part will even work, this stops working as soon as I change the return type to T& and then in the if part use return &content[i - 1][j - 1]; (I thought it was kind of nice to convert to standard matrix notation.
How do I get a reference here so that I can not only show what the value is but also use this function to assign values inside my matrix?
-
Well if you're returning a reference, you can't return NULL.
My guess is you throw an exception instead.
Perhaps follow what std::vector.at() does when it has a problem.
-
fair enough, so something like this?
Code:
// 'at' function: indexing using normal MATRIX notation (starting at row/col 1 not 0)
template<typename T, int n>
T Matrix<T, n>::at(const int i, const int j) throw(std::out_of_range)
{
if (i < 1 || n < i || j < 1 || n < j)
throw std::out_of_range("Matrix index out of range");
else
return content[i - 1][j - 1];
}
That still leaves the problem of returning a reference so that we can not only look at the value but also assign it-- and this doesn't work:
Code:
template<typename T, int n>
T& Matrix<T, n>::at(const int i, const int j) throw(std::out_of_range)
{
if (i < 1 || n < i || j < 1 || n < j)
throw std::out_of_range("Matrix index out of range");
else
return &content[i - 1][j - 1];
}
-
You do not need to change anything other than the return type when changing to return a reference. What you did is to change the return type to a reference type, but then you changed the return statement to return the address. Therefore, there is a type mismatch.
-
I'd want to see how you'll perform matrix multiplication with this class....
-
I prepare using 1D arrays for multiplication. They are, at my opinion, simpler.
-
I was thinking multiplication would be hard, too, but that turned out to work easily.
Code:
template<typename T, int n>
Matrix<T, n> Matrix<T, n>::operator*(const Matrix<T, n>& m) const
{
T arr[n][n];
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
arr[i][j] = 0; // initialize before doing multiplication
for (int k = 0; k < n; ++k)
{
arr[i][j] += content[i][k] * m.content[k][j];
}
}
}
return Matrix<T, n>(arr);
}
Where i'm bogging down is with the recursive def of determinants (which also suffers from a clunky version of scalar multiplication). More on those later.
Weird that I could get matrix multiplication to work with no problem but that scalar multiplication is looking very ugly.
Also need to try laser's suggestion on at and see what happens (if i'm understanding it right).
-
right on again, laser. it at least compiled when i just changed the return types in prototype and definition to T&. Now i'll have to make sure it also allows me to make assignments.
-
assigment worked, too! tx!!
now just scalar multiplication and determinants (which i knew would be hard as i'm a recursion novice) left to go.
-
here's the current "at", just to close that one out for now:
Code:
template<typename T, int n>
T& Matrix<T, n>::at(const int i, const int j) throw(std::out_of_range)
{
if (i < 1 || n < i || j < 1 || n < j)
throw std::out_of_range("Matrix index out of range");
return content[i - 1][j - 1];
}
-
Well, even if your class is correct, it's useless! Only 3x3 and 4x4 matrices are useful, for me, as i'm building a 3D maths library