Странное поведение оператора присваивания / умножения в C ++ - PullRequest
2 голосов
/ 16 декабря 2011

Может кто-нибудь объяснить, пожалуйста, что не так с моими операторами:

Matrix3D Matrix3D::operator*(Matrix3D& m) {
    Matrix3D ret;
    for(int i=0;i<4;i++) {
        for(int j=0;j<4;j++) {
            ret._data[i][j]=0.0;
            for(int k=0;k<4;k++) {
                ret._data[i][j] += (this->_data[i][k]*m._data[k][j]);
            }
        }
    }
    return ret;
}

Matrix3D& Matrix3D::operator=(Matrix3D& m) {
    if(this==&m) {
        return *this;
    }
    for(int i=0;i<4;i++) {
        for(int j=0;j<4;j++) {
            this->_data[i][j] = m._data[i][j];
        }
    }
    return *this;
}

Matrix3D Matrix3D::Rotation(double ax, double ay, double az) {
    Matrix3D rotX;
    Matrix3D rotY;
    Matrix3D rotZ;
    rotX(
        1,          0,          0,          0,
        0,          cos(ax),    -sin(ax),   0,
        0,          sin(ax),    cos(ax),    0,
        0,          0,          0,          1
    );
    rotY(
        cos(ay),    0,          sin(ay),    0,
        0,          1,          0,          0,
        -sin(ay),   0,          cos(ay),    0,
        0,          0,          0,          1
    );
    rotZ(
        cos(az),    -sin(az),   0,          0,
        sin(az),    cos(az),    0,          0,
        0,          0,          1,          0,
        0,          0,          0,          1
    );

    // Matrix3D ret;
    // ret = rotX*rotY*rotZ;
    // This doesn't work
    // C:\(...)\Matrix3D.cpp|100|error: no match for 'operator=' in 'ret = Matrix3D::operator*(Matrix3D&)(((Matrix3D&)(& rotZ)))'|

    // however this does work

    Matrix3D ret = rotX*rotY*rotZ;
    return ret;
}

как указано в коде выше, что-то вроде

    Matrix3D ret;
    ret = rotX*rotY*rotZ;

приведет к

    C:\(...)\Matrix3D.cpp|100|error: no match for 'operator=' in 'ret = Matrix3D::operator*(Matrix3D&)(((Matrix3D&)(& rotZ)))'|

ошибка компиляции, пока что-то типа

    Matrix3D ret = rotX*rotY*rotZ;

скомпилируется без каких-либо предупреждений или ошибок (не знаю, правильны ли матрицы, еще не проверял ...).

Ответы [ 4 ]

8 голосов
/ 16 декабря 2011

На самом деле оба оператора объявлены неправильно.Они должны иметь ссылку const, чтобы позволить принимать значения.

Matrix3D Matrix3D::operator*(const Matrix3D& m) const
//                           ^^^^^              ^^^^^
//                                              this too, since you're not
//                                              changing the LHS during '*'.

Matrix3D& Matrix3D::operator=(const Matrix3D& m)
//                            ^^^^^

Вы увидите, что * не работает с rotX*(rotY*rotZ).

Причина, по которой компиляция Matrix3D ret = rotX*rotY*rotZ; заключается в том, что operator= вообще не вызывается.Он просто вызывает конструктор копирования Matrix3D для результата умножения.И умножение работает, потому что rotX * rotY * rotZ переписывается в

rotX.operator*(rotY).operator*(rotZ)

, а rotY и rotZ оба являются lvalues, поэтому они могут быть связаны с Matrix3D&.

5 голосов
/ 16 декабря 2011

Правильные декларации как operator*, так и operator=:

Matrix3D  Matrix3D::operator* (Matrix3D const& m) const;
Matrix3D& Matrix3D::operator= (Matrix3D const& m);

Материал для чтения:


Ваш operator= принимает Matrix3D&, хотя rotX*rotY*rotX приведет к r-значению , и поэтому вы не можете связать ссылку на него.

Для работы operator= следует принять Matrix3D const&, который может быть связан как с значениями , так и значениями .

Даже если он выглядит так, как Obj a = b использует Obj::operator=, это не так, он будет использовать то, что обычно называется copy-constructor . Подробнее об этом здесь .

4 голосов
/ 16 декабря 2011

Измените сигнатуру оператора присваивания, чтобы она была константно-правильной:

Matrix3D& Matrix3D::operator=(Matrix3D const & m)
//                                     ^^^^^

В вашем примере кода оператор присваивания хочет привязаться к временному, а временные привязки не могут привязаться к непостоянным ссылкам.Напротив, конструктор копирования, который вызывается вторым фрагментом кода, принимает константную ссылку, поэтому ошибки нет.

1 голос
/ 16 декабря 2011
Matrix3D& Matrix3D::operator=(Matrix3D& m)

Вы запрашиваете, чтобы параметр правой стороны был l-значением.Это должна быть существующая переменная, не может быть временным значением.Попробуйте вместо этого использовать const Matrix3D& m.

Matrix3D ret = rotX*rotY*rotZ; работает, поскольку он вообще не использует operator=, а использует конструктор по умолчанию Matrix3D::Matrix3D(const Matrix3D&).

...