Как я иду о перегрузке операторов C++ для обеспечения объединения в цепочку?

Я, как столько программистов передо мной, рву волосы, пишущий right-of-passage-matrix-class-in-C ++. Я никогда не делал очень серьезной перегрузки оператора, и это вызывает проблемы. По существу, путем продвижения через

Это - то, что я называю для порождения проблем.

    cMatrix Kev = CT::cMatrix::GetUnitMatrix(4, true);
    Kev *= 4.0f;
    cMatrix Baz = Kev;
    Kev = Kev+Baz;  //HERE!

То, что, кажется, происходит согласно отладчику, - то, что Kev и Baz добавляются, но затем значение потеряно и когда дело доходит до переприсвоения Kev, память является просто своими изворотливыми значениями по умолчанию. Как я перегружаю свои операторы для обеспечения этого оператора? Мой (разделенный вниз) код ниже.

//header
class cMatrix
{
private:
    float* _internal;
    UInt32 _r;
    UInt32 _c;
    bool _zeroindexed;

    //fast, assumes zero index, no safety checks
    float cMatrix::_getelement(UInt32 r, UInt32 c)
    {
        return _internal[(r*this->_c)+c];
    }

    void cMatrix::_setelement(UInt32 r, UInt32 c, float Value)
    {
        _internal[(r*this->_c)+c] = Value;
    }

public:
    cMatrix(UInt32 r, UInt32 c, bool IsZeroIndexed);
    cMatrix( cMatrix& m);
    ~cMatrix(void);

    //operators
    cMatrix& operator + (cMatrix m);
    cMatrix& operator += (cMatrix m);
    cMatrix& operator = (const cMatrix &m);
};

//stripped source file
cMatrix::cMatrix(cMatrix& m)
{
    _r = m._r;
    _c = m._c;
    _zeroindexed = m._zeroindexed;
    _internal = new float[_r*_c];

    UInt32 size = GetElementCount();

    for (UInt32 i = 0; i < size; i++)
    {
        _internal[i] = m._internal[i];
    }
}

cMatrix::~cMatrix(void)
{
    delete[] _internal;
}
cMatrix& cMatrix::operator+(cMatrix m) 
{
    return cMatrix(*this) += m;
}

cMatrix& cMatrix::operator*(float f) 
{
    return cMatrix(*this) *= f;
}

cMatrix& cMatrix::operator*=(float f) 
{
    UInt32 size = GetElementCount();

    for (UInt32 i = 0; i < size; i++)
    {
        _internal[i] *= f;
    }

    return *this;
}

cMatrix& cMatrix::operator+=(cMatrix m) 
{
    if (_c != m._c || _r != m._r)
    {
        throw new cCTException("Cannot add two matrix classes of different sizes.");
    }
    if (!(_zeroindexed && m._zeroindexed))
    {
        throw new cCTException("Zero-Indexed mismatch.");
    }

    for (UInt32 row = 0; row < _r; row++)
    {
        for (UInt32 column = 0; column < _c; column++)
        {
            float Current = _getelement(row, column) + m._getelement(row, column);
            _setelement(row, column, Current);
        }
    }

    return *this;
}

cMatrix& cMatrix::operator=(const cMatrix &m) 
{
    if (this != &m) 
    {
        _r = m._r;
        _c = m._c;
        _zeroindexed = m._zeroindexed;

        delete[] _internal;

        _internal = new float[_r*_c];

        UInt32 size = GetElementCount();

        for (UInt32 i = 0; i < size; i++)
        {
            _internal[i] = m._internal[i];
        }
    }
    return *this;
  }
5
задан User2400 23 April 2010 в 11:03
поделиться

2 ответа

Ваши операторы + и * должны возвращаться по значению, а не по ссылке. Вы возвращаете временную переменную по ссылке. Кроме того, ваши аргументы передаются по значению, когда это должна быть ссылка на константу:

cMatrix cMatrix::operator+(cMatrix const& m) 
{
    cMatrix matrix(*this);
    matrix += m;
    return matrix;
}

cMatrix cMatrix::operator*(float f) 
{
    cMatrix matrix(*this);
    matrix *= m;
    return matrix;
}

Вам следует взглянуть на Boost.Operators . Это позволит вам реализовать только оператор * = и оператор + = и автоматически обеспечить правильные реализации для оператора + и оператора * .

PS: Если вы реализуете свой матричный класс только для обучения, не стесняйтесь взглянуть на другие реализации, такие как Библиотека шаблонов матриц .

PPS: Если вы не хотите использовать ускорение или просто хотите понять передовой опыт, взгляните на Boost.Operator и сделайте то, что они делают.

10
ответ дан 18 December 2019 в 09:05
поделиться

IMO каноническая форма сложения перегрузки такова:

class X {
public:
  X& operator+=(const X& rhs) { /*add rhs to *this*/ }
};

inline X operator+(X lhs, const X& rhs) {lhs+=rhs; return lhs;}

То же самое касается - , * , / , где применимо.

Обратите внимание, что + возвращает копию, а не ссылку. Это важно, потому что A + B создает новое значение, поэтому оно не может вернуть ссылку на существующее.
Кроме того, это бесплатная функция. IMO лучше всего реализовать те из двоичных операторов, которые могут быть реализованы либо как член, либо как свободная функция как свободные функции, если они обрабатывают свои операнды симметрично (как + ), и как функции-члены, если они обрабатывают свои операнды асимметрично (как + = , что изменяет его левый аргумент. Если вы реализуете operator + как член, вам придется сделать функцию const ] ( оператор X + (const X & rhs) const ), чтобы его можно было вызывать для константных элементов слева.

8
ответ дан 18 December 2019 в 09:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: