Как мне перегрузить операторы C ++ для создания цепочки? - PullRequest
5 голосов
/ 23 апреля 2010

Я, как и многие программисты до меня, вырываю голову, пишу "матрица права на прохождение" в 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;
  }

Ответы [ 2 ]

10 голосов
/ 23 апреля 2010

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

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 .Это позволит вам реализовать только operator*= и operator+= и автоматически предоставить правильные реализации для operator+ и operator*.

PS: Если вы реализуете свой матричный класс только дляНе стесняйтесь взглянуть на другие реализации, такие как Matrix Template Library .

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

8 голосов
/ 23 апреля 2010

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 operator+(const X& rhs) const), чтобы ее можно было вызывать для константных элементов налевая сторона.

...