operator overloading with abstract base class
I've been pondering this design pattern for a few days & getting nowhere. Please have a look at this "skeleton" code which comes from Linxutopia - Thinking in C++ - 15: Polymorphism & Virtual Functions - Operator overloading:
It doesn't show the actual arithmetic implementation but gives the outline of the class hierarchy.
Code:
//: C15:OperatorPolymorphism.cpp
// Polymorphism with overloaded operators
#include <iostream>
using namespace std;
class Matrix;
class Scalar;
class Vector;
class Math {
public:
virtual Math& operator*(Math& rv) = 0;
virtual Math& multiply(Matrix*) = 0;
virtual Math& multiply(Scalar*) = 0;
virtual Math& multiply(Vector*) = 0;
virtual ~Math() {}
};
class Matrix : public Math {
public:
Math& operator*(Math& rv) {
return rv.multiply(this); // 2nd dispatch
}
Math& multiply(Matrix*) {
cout << "Matrix * Matrix" << endl;
return *this;
}
Math& multiply(Scalar*) {
cout << "Scalar * Matrix" << endl;
return *this;
}
Math& multiply(Vector*) {
cout << "Vector * Matrix" << endl;
return *this;
}
};
class Scalar : public Math {
public:
Math& operator*(Math& rv) {
return rv.multiply(this); // 2nd dispatch
}
Math& multiply(Matrix*) {
cout << "Matrix * Scalar" << endl;
return *this;
}
Math& multiply(Scalar*) {
cout << "Scalar * Scalar" << endl;
return *this;
}
Math& multiply(Vector*) {
cout << "Vector * Scalar" << endl;
return *this;
}
};
class Vector : public Math {
public:
Math& operator*(Math& rv) {
return rv.multiply(this); // 2nd dispatch
}
Math& multiply(Matrix*) {
cout << "Matrix * Vector" << endl;
return *this;
}
Math& multiply(Scalar*) {
cout << "Scalar * Vector" << endl;
return *this;
}
Math& multiply(Vector*) {
cout << "Vector * Vector" << endl;
return *this;
}
};
int main() {
Matrix m; Vector v; Scalar s;
Math* math[] = { &m, &v, &s };
for(int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++) {
Math& m1 = *math[i];
Math& m2 = *math[j];
m1 * m2;
}
} ///:~
I understand the need for the multiple dispatching and how it works. What bothers me is the return value of the * operator. When main calls it, as in it will call m1's * operator, giving it m2 as the rhs argument. That * function in turn calls m2's multiply function, giving it m1 as the rhs argument. The multiply function modifies the value of m2's data member(s) and returns a reference to m2 to the * function, which then returns that reference to main. So the result of the * operation is to modify one of the operands.
Similarly, it seems that using this pattern to implement an assignment operator would modify the rvalue of the assignment.
This does not seem right to me. A + operator shouldn't modify one of the operands, and an = operator shouldn't modify the rvalue. On the other hand, I don't see any way to get around this. Is this just an inappropriate application for polymorphism, or am I missing something?