Question on virtual operator* on C++
I was trying to make virtual operator on C++
class Data
{
virtual Matrix operator* (Matrix &_matrix);
virtual Scalar operator* (Scalar &_scalar);
};
class Matrix : public Data
{
private:
vector<vector<double>> data;
public:
// ...
Matrix operator* (Matrix &_matrix);
};
class Scalar : public Data
{
private:
double data;
public:
// ...
Scalar operator* (Scalar &_scalar);
};
And the problem was, when I created Data* Array like below
Data* arr[10];
arr[0] = new Matrix(3,3);
arr[1] = new Matrix(3,3);
arr[0]->operator*(arr[1]);
I could not do multiplication between these 开发者_运维技巧two matrices, since I cannot pass Data as an argument. But the problem is, I cannot make the function's argument to take Data* type because, it will not be able to access private members of Matrix or Scalar objects.
How to deal with this kind of weird situation?
Class double dispatch problem - See Meyer's (forget which one). You need the operator to be virtual on both the lhs and rhs, so you need two virtual calls:
class Matrix;
class Scalar;
class Data
{
public:
virtual Data* operator* (Data& data) = 0;
virtual Data* operator* (Matrix &matrix) = 0;
virtual Data* operator* (Scalar &scalar) = 0;
};
class Matrix : public Data
{
private:
std::vector<std::vector<double>> data;
// ...
public:
Matrix* operator* (Matrix &_matrix)
{
// implement
}
Matrix* operator* (Scalar& scalar)
{
// implement
}
Data* operator* (Data &data)
{
// Magic here - *this is now Matrix, not Data
return data * (*this);
}
};
class Scalar : public Data
{
private:
double data;
public:
// ...
Data* operator* (Data& data)
{
// Magic here - *this is now Scalar, not Data
return data * (*this);
}
Scalar* operator* (Scalar &scalar)
{
// implement
}
Matrix* operator* (Matrix &matrix)
{
// Note how we need to allow for parameter reveral during the double dispatch
Matrix& lhs = matrix;
Matrix& rhs = *this;
// Compute matrix product lhs * rhs
}
};
I've glossed over the issue of the return type and memory management. As usual with operators, you might be better defining *=
as the primitive. This can then return a reference to *this
. The *
operator can then defined in terms of *=
. Once again, this is in "Effective C++".
The solution to this is called Double Dispatch which is a little strange in C++. The following code shows how this trick works:
#include <iostream>
#include <stdexcept>
#include <vector>
class Matrix;
class Scalar;
class Data {
public:
virtual ~Data() {}
virtual Data const& operator* (Data const& other) const = 0;
virtual Data const& multiplyBy (Data const& other) const {
throw std::runtime_error("bad function call");
}
virtual Data const& multiplyBy (Matrix const& other) const = 0;
virtual Data const& multiplyBy (Scalar const& other) const = 0;
};
class Matrix : public Data {
private:
std::vector< std::vector<double> > data;
public:
virtual Data const& operator* (Data const& other) const {
return other.multiplyBy(*this);
}
virtual Data const& multiplyBy (Matrix const& other) const {
std::cout << "Matrix * Matrix" << std::endl;
return *this;
}
virtual Data const& multiplyBy (Scalar const& other) const {
std::cout << "Matrix * Scalar" << std::endl;
return *this;
}
};
class Scalar : public Data {
private:
double data;
public:
virtual Data const& operator* (Data const& other) const {
return other.multiplyBy(*this);
}
virtual Data const& multiplyBy (Matrix const& other) const {
std::cout << "Scalar * Matrix" << std::endl;
return *this;
}
virtual Data const& multiplyBy (Scalar const& other) const {
std::cout << "Scalar * Scalar" << std::endl;
return *this;
}
};
int
main() {
Matrix m;
Scalar s;
Data* ary[] = { &m, &s };
m * s;
s * m;
*(ary[0]) * *(ary[1]);
*(ary[1]) * *(ary[0]);
return 0;
}
精彩评论