Вопрос по виртуальному оператору * на C ++ - PullRequest
2 голосов
/ 20 сентября 2011

Я пытался сделать виртуальный оператор на 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);
};

И проблема была, когда я создал Data * Array, как показано ниже

Data* arr[10];
arr[0] = new Matrix(3,3);
arr[1] = new Matrix(3,3);

arr[0]->operator*(arr[1]);

Я не мог сделать умножение между этими двумя матрицами, так как я не могу передать Data в качестве аргумента. Но проблема в том, что я не могу сделать аргумент функции для получения типа Data *, потому что он не сможет получить доступ к закрытым членам объектов Matrix или Scalar.

Как справиться с такой странной ситуацией?

Ответы [ 2 ]

6 голосов
/ 20 сентября 2011

Класс двойной проблемы отправки - См. Мейер (забудьте, какой). Вам нужно, чтобы оператор был виртуальным как для lhs, так и для rhs, поэтому вам нужно два виртуальных вызова:

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
    }

};

Я замял вопрос о типе возвращаемого значения и управлении памятью. Как обычно с операторами, вы могли бы лучше определить *= как примитив. Это может затем вернуть ссылку на *this. Оператор * может быть определен в терминах *=. Еще раз, это в "Эффективном C ++".

4 голосов
/ 20 сентября 2011

Решение этой проблемы называется Double Dispatch , что немного странно в C ++.Следующий код показывает, как работает этот трюк:

#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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...