0

I wrote an IntegerMatrix class to add my own methods to work with matrices. Now I've written a function like this:

IntegerMatrix** IntegerMatrix::multiplyMatrix(IntegerMatrix** table2)

(It's a double pointer because I'm holding a huge array of pointers to 4x4 2D arrays.) so I simply could do this:

matrix1.multplyMatrix(matrix2)

One little problem is the * isn't defined for my own class. So I thought to overload this operator that I could do something like this:

sum += this->table[i][k] * table2[k][j];

But how can I get the right i and k in the overloaded operator, which is defined like this:

IntegerMatrix IntegerMatrix::operator*(const IntegerMatrix & k);

The only problem I can't figure out right now is how to get the right values ?

EDIT:

I've rewrote this and now I have:

IntegerMatrix IntegerMatrix::operator*(const IntegerMatrix & table2)
{
    int i, j, k;
    int sum;
    IntegerMatrix * result = new IntegerMatrix(SIZE);

    for (i = 0; i < SIZE; i++) {
        for (j = 0; j < SIZE; j++) {
            sum = 0;
            for (k = 0; k < SIZE; k++) {
                sum += this->table[i][k] * table2[k][j];
            }
            result[i][j] = sum;
        }
    }
    return *result;

}

That gives me just an error on the [] :

Binary '[' : 'IntegerMatrix' does not define this operator or a conversiont o a type acceptable to the predefined operator.
Mooing Duck
  • 56,371
  • 16
  • 89
  • 146
user1007522
  • 7,040
  • 14
  • 62
  • 107
  • 2
    Why does your multiply function take a double pointer instead of a reference? What errors did you get when you tried that `operator*` that you suggested? Why should the matrix multiplication know about `i` and `k`? I don't understand this question at all. – Mooing Duck Oct 08 '12 at 19:24
  • Are you sure you are supposed to use dynamic memory for 2 Dimensional arrays for multiplication and other operations? – Recker Oct 08 '12 at 19:25
  • People who downvote without explaining why are silly. – Wug Oct 08 '12 at 19:27
  • `sum += this->table[i][k] * table2[k][j];` seems to be multiplying two integers, and is completely unrelated to matrix multiplication. @Wug: maybe they did comment. – Mooing Duck Oct 08 '12 at 19:31
  • I didn't say comment, I said explain. I didn't see anything that said "-1 because X". Deliberately teaching people helps them learn, but not, doesn't. The question itself is reasonably well formed, and is a practical, answerable question about a specific algorithm. (style notwithstanding.) If you see something that alarms you in someone's style, it helps more if you show them what good style looks like, instead of just implying they're wrong. – Wug Oct 08 '12 at 19:39
  • See edit above. It's a double pointer because I'm holding a huge array of pointers to 4x4 2D arrays. I'm trying to compress an image. So that's way i have a *** pointer to ** pointer 4x4 integer arrays. – user1007522 Oct 08 '12 at 19:44

3 Answers3

1

I don't understand your question, but here's a brief demo of how matrix multiplication normall works:

class IntegerMatrix {
    int table[3][3];

public:
      IntegerMatrix& operator*=(const IntegerMatrix& rhs) {
           //multiply table by rhs.table, store in data.
           return *this;
      }
};
IntegerMatrix operator*(IntegerMatrix lhs, const IntegerMatrix& rhs)
{return lhs*=rhs;} //lhs is a copy, so we can alter and return it

FOR YOUR EDIT

You have the code

IntegerMatrix * result = new IntegerMatrix(SIZE); //pointer to an IntegerMatrix
...
result[i][j] = sum; //assign sum to the jth index of matrix # i

when in actuality, I presume you wanted

result->table[i][j] = sum; //sum to the ixj index of the result matrix.

Also, your function is leaky, because you have a new, but no delete. This is easy to fix in your case, since you don't need the new. (Are you from a Java or C# background?)

IntegerMatrix result(SIZE);
...
        result[i][j] = sum;
...
return result;

Unrelated to all of the above, you might actually want to provide a [] operator for your Integer Matrix.

class row {
    int* data;
    int size;
public:
    row(int* d, int s) :data(d), size(s) {}
    int& operator[](int offset) {
        assert(offset<size);
        return data[offset];
    }
};

row operator[](int column) {
    assert(column<SIZE); 
    return row(table[column], SIZE);
}

And this would allow you to write:

IntegerMatrix result;
result[i][j] = sum;
Community
  • 1
  • 1
Mooing Duck
  • 56,371
  • 16
  • 89
  • 146
1

You may be carrying over some artifacts, in sort of a Cargo-Cult programming sense. :-/

For instance: I'm guessing that the double indirections (**) on your prototype for multiplyMatrix are there because you saw multidimensional arrays of integers around somewhere...stuff like:

void printMatrix(int ** myMatrix, int rows, int columns);

The double-indirection is just a pointer-to-a-pointer. It's a way of achieving the specific implementation point of passing low-level C-style 2D arrays as parameters. But it's not something you have to tack on any time you're working with an abstract class that happens to represent a Matrix. So once you've encapsulated the matrix size and data itself inside the IntegerMatrix class, you don't want something like this:

void printMatrix(IntegerMatrix ** myMatrix);

More likely you'd want to pass in a simple reference to the class which is encapsulating the data, like this:

void printMatrix(IntegerMatrix const & myMatrix);

You should actually return a new matrix from your multiplication function, at least if you're using it to implement an operator overload...because semantically it does not make sense for people to write things like a * b; and have that modify a. (It can, but you shouldn't.) So you are left with either the choice of returning a matrix value instance:

IntegerMatrix IntegerMatrix::multiplyMatrix(IntegerMatrix const & rhs);

...or returning a pointer to a new object:

IntegerMatrix * IntegerMatrix::multiplyMatrix(IntegerMatrix const & rhs);

Returning by pointer has historically been chosen by many libraries because returning by value from a local variable in the function would involve making a copy at the time of return. Returning a pointer is fast (it "copies" only one 32-bit/64-bit number) while copying an instance of an object and large blocks of data inside it is slow. So a lot of libraries would just use Matrix pointers everywhere...with the problem that it becomes hard to know whose responsibility it is to ultimately delete the object. Smart pointers are one way of ensuring this:

unique_ptr<IntegerMatrix> IntegerMatrix::multiplyMatrix(IntegerMatrix const & rhs);

But C++11 has some sneaky ability to be just as fast without the mess. If you return something by value from a function and the compiler is sure that value isn't going to be used again (since it's going out of scope), then it can be "moved" about as fast as a pointer could. This requires that you support move construction by RValue reference, and there's all kinds of trickiness in that.

There's really a lot of nuance. If you're doing this as an educational exercise, I'd suggest taking it slowly and going through a tutorial that walks you through every step instead of jumping straight into the fire. And if you're using low-level C arrays and dynamic allocations inside your matrix, change them to a std::vector of std::vector.

Community
  • 1
  • 1
1

For one IntegerMatrix object you're using this->table[i][k] to refer to the array where you're holding the matrix data, while for the table2 object reference and the result pointer, you're using table2[k][j] and result[i][j].

I think that what you want to do is something like:

IntegerMatrix IntegerMatrix::operator*(const IntegerMatrix & table2)
{
    int i, j, k;
    int sum;
    IntegerMatrix * result = new IntegerMatrix(SIZE);

    for (i = 0; i < SIZE; i++) {
        for (j = 0; j < SIZE; j++) {
            sum = 0;
            for (k = 0; k < SIZE; k++) {
                sum += this->table[i][k] * table2.table[k][j];
            }
            result->table[i][j] = sum;
        }
    }
    return *result;
}
Giovany
  • 21
  • 1